前回、C#でオセロを作ってみるの続きです。今回はコンピューターに次の一手を選ばせて対戦できるようにします。
追記:コンピュータのアルゴリズムを改良して作り直しました。こちらのページがおすすめです。
以下は古いコンテンツです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public partial class Form1 : Form { async private void Box_PictureBoxExClick(int x, int y) { // 自分の手番か確認する if(!isYour) return; // 着手可能な場所か調べる List<Stone> stones = GetRevarseStones(x, y, StoneColor.Black); if(stones.Count != 0) { StonePosition[x, y].StoneColor = StoneColor.Black; stones.Select(xx => xx.StoneColor = StoneColor.Black).ToList(); isYour = false; toolStripStatusLabel1.Text = "コンピュータが考えています"; await Task.Delay(1000); EnemyThink(); } else toolStripStatusLabel1.Text = "ここには打てません"; } } |
await Task.Delay(1000);をいれているのは着手が完了するとすぐにコンピュータが処理をするため、すぐに自分の手番になってしまうからです。ちょっと落ち着かないので、着手して1秒間待ってからコンピュータに次の手を考えさせます。
EnemyThinkメソッドはコンピュータに次の一手を決めさせるためのメソッドです。石が置かれていない場所で、黒を挟むことができる場所を探させます。見つかったら乱数で適当に決めさせています。そして石を置かせて石をひっくり返させています。
もし次にどこへ打っても石をひっくり返せない場合はパスをすることになります。その場合、ステータスバーにパスをしたこと、手番はプレーヤー側にあることがわかるように表示させます。
それからプレーヤー側に次の手があるかどうかもプログラムで調べさせています。そして双方がパスをした場合はゲームセットの処理をおこなうことになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
public partial class Form1 : Form { void EnemyThink() { bool isComPassed = false; bool isYouPassed = false; while(true) { // Cast メソッドで 1次元に var stones = StonePosition.Cast<Stone>(); // 石が置かれていない場所で挟むことができる場所を探す。 stones = stones.Where(xx => xx.StoneColor == StoneColor.None && GetRevarseStones(xx.Colum, xx.Row, StoneColor.White).Any()); var hands = stones.ToList(); int count = hands.Count(); if(count > 0) { // 石をおける場所が見つかったらそのなかから適当に次の手を選ぶ Stone stone = hands[random.Next() % count]; // 石を置いてひっくり返す StonePosition[stone.Colum, stone.Row].StoneColor = StoneColor.White; List<Stone> stones1 = GetRevarseStones(stone.Colum, stone.Row, StoneColor.White); stones1.Select(xx => xx.StoneColor = StoneColor.White).ToList(); } else { if(isYouPassed) { // 双方に「手」が存在しない場合はゲームセットとする OnGameset(); return; } // 石をおける場所が見つからない場合はパス isComPassed = true; } // プレイヤーの手番だが、「手」は存在するのか? stones = StonePosition.Cast<Stone>(); stones = stones.Where(xx => xx.StoneColor == StoneColor.None && GetRevarseStones(xx.Colum, xx.Row, StoneColor.Black).Any()); hands = stones.ToList(); count = hands.Count(); // 「手」が存在するならプレーヤーの手番とする if(count > 0) { isYour = true; if(isComPassed) toolStripStatusLabel1.Text = "コンピュータはパスしました。あなたの手番です。"; else toolStripStatusLabel1.Text = "あなたの手番です。"; return; } else { // 「手」が存在しない場合はもう一度コンピュータの手番とする if(!isComPassed) { isYouPassed = true; toolStripStatusLabel1.Text = "あなたの手番ですが手がありません"; } else { // 双方に「手」が存在しない場合はゲームセットとする OnGameset(); return; } } } } } |
ゲームセットになったときは双方の石の数を数えて勝ち負けを表示させています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public partial class Form1 : Form { void OnGameset() { var stones = StonePosition.Cast<Stone>(); int blackCount = stones.Count(xx => xx.StoneColor == StoneColor.Black); int whiteCount = stones.Count(xx => xx.StoneColor == StoneColor.White); string str = ""; if(blackCount != whiteCount) { string winner = blackCount > whiteCount ? "黒" : "白"; str = String.Format("終局しました。{0} 対 {1} で {2} の勝ちです。", blackCount, whiteCount, winner); } else { str = String.Format("終局しました。{0} 対 {1} で 引き分けです。", blackCount, whiteCount); } toolStripStatusLabel1.Text = str; return; } } |
それにしても弱すぎ・・・