SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

よろずプログラマーのためのPython導入ガイド

Java meets Python - 第4回 配列と別れる50の方法(2) オセロゲーム

よろずプログラマーのためのPython導入ガイド (6)


春うらら:コードを巡る旅の縁(よすが)に

 同じ景色を眺めても、思い入れがあるのとないのとでは、その感動も違ってきます。そこで、漠然とコードを眺めるのではなく、構造化ブログラミング(SP)とオブジェクト指向プログラミング(OOP)との違いを示しながら、その相互理解を深めます。

最初に石を配置するのは

 ゲームを始める前に、ルール(要求仕様)に従って石を配置します。

class OthelloPanel(GameBoardPanel):
    def locateStone(self):
        points = [(x, y)
            for y in range(-1, self.dim+1)
            for x in range(-1, self.dim+1)]
        for x, y in points:
            self.items.append(NullStone(x, y, None))
        self.place(Stone(3, 3, self.white))
        self.place(Stone(3, 4, self.black))
        self.place(Stone(4, 3, self.black))
        self.place(Stone(4, 4, self.white))
    def place(self, stone):
        null = self.detect(stone.x, stone.y)
        self.items.remove(null)
        self.items.append(stone)

 メソッドlocateStoneは、ゲームを開始するときに必要な石を配置します。盤面の中央には、白黒2つずつの石Stoneを配置します。他の場所には、何も存在しないことを表す、見えない石NullStoneを配置します。これで準備が整います。

 メソッドplaceは、引数に指定した石stoneを盤面に配置します。見えない石NullStoneを削除して、そこに新たな石stoneを追加します。

そこに石があるなら

class OthelloPanel(GameBoardPanel):
    def detectStone(self, e):
        return self.detect(
            self.dim*e.x/self.width,
            self.dim*e.y/self.height)

 メソッドdetectStoneは、盤面をクリックしたときに発生するイベントeをもとに、その位置にある石を検出detectします。このとき、ウィンドウの大きさが変化しても、それに応じて柔軟に対処できます。

そこが領地になるのは

 反転できる石は、自分と同じ色で挟まれた石だけです。伝統的な手法では、これを配列の値に対する操作として実現します。そのとき、主役を演じるのは配列で、値は脇役にすぎません。OOPでは、これをオブジェクト間のメッセージ送受信としてモデル化します。そこでは、石(オブジェクト)が主役を演じます。

class OthelloPanel(GameBoardPanel):
    def reverseStones(self, stone, x, y):
        stones = [stone]
        for i in range(1, self.dim):
            e = self.detect(stone.x+x*i, stone.y+y*i)
            if e.state == None:
                stones = []; break
            if e.state == self.mode:
                break
            if e.state == (not self.mode):
                stones.append(e)
        if not stones: return
        for e in stones:
            e.state = self.mode
        self.reversed = True
        print stones

 メソッドreverseStonesは、指定した石stoneのオフセット位置x/yと同じ方向にある石を裏返えします。局所変数stonesが、裏返したい石を管理します。最初に、指定した石stoneを、裏返す対象として追加しておきます。

 2つのオブジェクトが「石を裏返しませんか」というメッセージ(目的 what)をやり取りする様子を、メソッド(手段 how)として実現することを目指します。つまり、OthelloPanelインスタンス(盤面)からStone(石)への「石を裏返したい」という意思の伝達と考えます。

事例:単一方向に単数の石

>>> ((2,3),None)
[((3,3),white)]

 座標(2,3)には石がないNoneので、そこに黒(自分の石)を置けます。すると、座標(3,3)にある白 whiteが黒(自分の領地)になります。

 挟むべき位置に石が存在しないe.state==Noneなら、stonesが管理するすべての石を破棄します。ここでは、右上に石が存在しない(Noneが存在する)ので、反転できる石(白の領地)は存在しません。

 対象となる石が同じ色e.state==self.modeなら、処理を中断します。ここでは、右下に黒(同じ色)が存在するので、反転できる石(白の領地)は存在しません。

 対象となる石が違う色e.state==(not self.mode)なら、stonesに追加します。ここでは、右に白(違う色)が存在するので、反転できる石(白の領地)が存在します。そこで、stonesに石eを追加すると共に、((3,3),white)を出力します。

《読者への課題》正しいバグの飼い方
 条件式をe.state==(not self.mode)からe.state<>self.modeに変更すると、どのようなバグ(問題)が生じるか考察してください。

事例:複数方向に複数の石

>>> ((2,5),None)
[((2,4),white)]
[((3,4),white)]

 座標(2,5)には石がないNoneので、そこに黒(自分の石)を置けます。すると、座標(2,4)および(3,4)にある白 whiteが黒(自分の領地)になります。

 対象となる石が違う色 e.state==(not self.mode)なら、stonesに追加します。ここでは、上/右上に白(違う色)が存在するので、反転できる石(白の領地)が存在します。そこで、stonesに石eを追加すると共に、((2,4),white)および((3,4),white)を出力します。

事例:単一方向に複数の石

>>> ((1,4),None)
[((2,4),black), ((3,4),black)]

 座標(1,4)には石がないNoneので、そこに白(自分の石)を置けます。すると、座標(2,4)および(3,4)にある黒 blackが白(自分の領地)になります。

 対象となる石が違う色 e.state==(not self.mode)なら、stonesに追加します。ここでは、右に黒(違う色)が存在するので、反転できる石(黒の領地)が存在します。そこで、stonesに石eを追加すると共に、((2,4),black)および((3,4),black)を出力します。さらにその先を見ると、対象となる石が同じ色e.state==self.modeなら、処理を中断します。ここでは、その先に白(同じ色)が存在するので、そこで処理を中断します。

《読者への課題》要求仕様の変更
 既にお気付きのように、このオセロゲームは未完成です。例えば、何処にも石を置けないときに、パスできるようにはなっていません。また、一度置いた石を元へ戻せません。これらが可能になるように、コードを変更してください。

次のページ
絶景かな?

この記事は参考になりましたか?

よろずプログラマーのためのPython導入ガイド連載記事一覧

もっと読む

この記事の著者

小泉ひよ子とタマゴ倶楽部(コイズミヒヨコトタマゴクラブ)

http://tamago-club.cocolog-nifty.com/「楽しくなければ仕事じゃない」が私たちのモットー。99%の苦悩の連続も、1%の成功に報われます。だからこそ、この仕事が楽しくて仕方がないのです。楽をするための努力なら惜しみません。何もせず楽をしているのと、努力をしたから楽ができるのと...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

伊藤うさぎ(イトウ ウサギ)

ペンネームの「由来は」と言うと。苗字の方は、セミナー研修で同じチームになった、3人の合体ユニット名 [I:石塚, T:田川, O:尾沢] から来ています。名前の方は、同じ干支(卯:1987 年生)に因んだものです。既に2人は卒業して、残る1人がその名跡を継承しています。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1802 2008/03/25 12:48

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー