以前、オセロをつくりました。

C#でオセロを作ってみる

C#でオセロをつくる コンピューターの次の一手

このときは対戦相手であるコンピュータは着手可能な手を適当に選んでいただけなので、お話にならないくらいに弱いです。これに改良を加えます(もっともワンパターンな行動しかできないコンピュータを叩くのがゲームの面白いところなのかもしれませんが・・・)。

前回同様にピクチャーボックスを8行8列に敷き詰めて盤面をつくります。ただ前回はStoneというPictureBoxを継承したクラスを石がある位置の管理にも使っていましたが、石の描画と石の位置の管理は別のクラスにします。コンピュータに次の一手を考えさせるときに、石の描画と石の位置の管理が同じクラスではちょっと困ったことがおきるからです。

石の描画は前回同様にPictureBoxを継承したクラスを使います。ただしクラスの名前をCellに変えます。Cellクラスがどのようなものかを示します。

StoneColorプロパティでProperties.Resources.black;とかProperties.Resources.white;とありますが、以下のようなリソースをつくって追加しておきます。

こちらは石の位置と色を管理するクラスです。

あと石の色をあらわす列挙型を示します。黒か白か石は置かれていないかのどれかです。

ではフォーム部分をみていきましょう。

コンストラクタ内で自作メソッド CreateCells()でセルを作成します。CreateCells()とGameStart()メソッドはこのあと示します。

CreateCells()メソッドを示します。フォームの座標(30, 30)を起点に8×8のピクチャーボックスをセットします。フォーム上にセットしたピクチャーボックスはフィールド変数 Cells に格納して必要なときにアクセスできるようにします。同様にピクチャーボックスの位置もフィールド変数 StonePositions に格納します。

ゲームが開始したら4つの石を中央に配置します。配置したらCellのプロパティとStonePositionのプロパティを変更します。そのためにSetCellColorメソッドを作成しました。

プレイヤーが黒なら先手、白なら後手です。後手の場合は最初の一手をコンピュータに考えさせます。

自分の手番のときにマスをクリックしたら着手できます。ただし石を置くことで相手の石をひっくり返せる場所でなければなりません。

CreateCells()メソッドを実行したときにCellオブジェクトにはイベントハンドラが追加されているのでOnCellClickメソッドが呼び出されます。自分の手番か確認し、着手可能な場所か調べて問題がなければ着手が成立します。その後、コンピュータの手番となります。

また本当に着手可能な場所かどうかは自作メソッド GetRevarseStones(StonePositions, posX, posY, YourColor)で調べます。これはひっくり返される石に対応するStonePositionオブジェクトのリストを返します。リストが空でなければ着手可能な場所と判断できます。

ひっくり返される石に対応するStonePositionオブジェクトのリストを返すGetRevarseStonesメソッドを示します。

一度に調べるのは大変なので、上方向にひっくり返せる石があるか?下方向は?と全部で8方向について調べています。

着手しようとしている場所の上方向にひっくり返せる石があるか調べる処理を示します。その場所のひとつ上を調べて盤の端であれば対象の石は存在しないことになります。ひとつ上にある石が相手の石の場合は、さらにその上を調べます。

これを繰り返しひとつ以上相手の石が続いて、そのあと自分の石があればその間にある石は挟まれていることになります。それ以外の場合は挟めていないと判断します。

他の7方向も同様に調べます。やっていることはほとんど同じなので一気に示します。

次にコンピュータの手番の処理を考えたいのですが、そのまえにそもそも手自体が存在するのかを調べるメソッドを作成しておきます。

取得したいのは、石が置かれていない場所で相手の石を挟むことができる場所です。第一引数は盤面の全部のマスです。これを総当りで調べています。そして結果をStonePositionのリストで返します。

ではコンピュータの手番の処理を考えます。

まず1秒間の間をおきます。これは特に意味があるわけではなく、自分が着手したあと一瞬でまた手番が回ってくるのは違和感があるので間をおくだけです。

プレイヤーの石を挟むことができる場所を探すのですが、複数見つかったら適当に選ぶのではなくちょっと考えさせます。

まず角を安易に取らせてはいけません。見つけ出した候補手のなかから次にプレイヤーに角を取られる手はいったん候補から外します。そのうえで候補手が複数みつかったらプレイヤーの次の手が一番少なくなるものを選びます。

もし候補がない場合は角を取られるような場所でも仕方がないので適当に選びます。また着手可能な場所がひとつも存在しないのであれば、その場合はパスをします。

コンピュータの着手後、プレイヤーに手番が回ってくるのですが、この場合、プレイヤーはパスをするしかない場合も考えられます。そのときはひきつづきコンピュータの手番となります。もしコンピュータもパスするしかない場合はすべてのマス目が埋まっていなくても試合終了となります。

すべてのマス目が埋まってしまった場合、双方がパスをするしかない場合は試合終了です。お互いの石を数えてどちらが勝ったのかを判定します。