Practice of Programming

プログラム とか Linuxとかの話題

あまり頭を使わずに負けない三目並べを作る

4月書き忘れてることに気づいて、もう、5月31日ではないか....。

StreamDeckで遊ぶために、以前に三目並べを作ったのですが、その解説です。割と力技で作った感じなので、もっと頭のいい方法が知りたい方はぐぐると出てきます。

三目並べとは

説明するまでもないですが、9マスに先手後手で、◯×を埋めていって、3つ並べたら勝ちですね。 先手後手に関わらず最適な手を打てば必ず引き分けになります。

負けないためにはどうするか?

負けないためにはどうしたら良いのかというと、

  1. 負けそうなとき(相手の三目が成立する時)は妨害する
  2. 負ける配置(二目が同時に2つ成立する)にさせない
  3. 勝ち筋が多くなる(二目が同時に2つ成立する)ところに置く

の3点を守るのが基本です。

実装方法

マスをビットで表す

9マスをビットで表します。

# 三目並べのビット
1   2    4
8   16  32
64 128 256

見やすいようにテーブルにします。

a b c
A 1 2 4
B 8 16 32
C 64 128 246

勝利条件bit和で考える

勝利条件のbit和は下記のようになります(8列分)。

  • 84 ... 斜め(cA,bB,cC)
  • 7 ... A行
  • 56 ... B行
  • 448 ... C行
  • 273 ... 斜め(aC,bB,cA)
  • 73 ... a列
  • 146 ... b列
  • 292 ... c列

次で勝つときのbit和と、次どこを打てばよいかのbit は下記のようになります(8列x3=24)。

  • 84
    • 20: 64 ... cA(4)とbB(16)をとっていたら、 aC(64)が勝利手
    • 80: 4
    • 68: 16
  • 7
    • 3: 4
    • 6: 1
    • 5: 2,
  • 56
    • 24: 32
    • 48: 8
    • 40: 16
  • 448
    • 192: 256
    • 384: 64
    • 320: 128
  • 273
    • 17: 256
    • 272: 1
    • 257: 16
  • 73
    • 9: 64
    • 72: 1
    • 65: 8
  • 146
    • 18: 128
    • 134: 2
    • 130: 16
  • 292
    • 36: 256
    • 288: 4
    • 260: 32

負けないための戦略を考える

最初の3つの負けないためのルールを実行するためには、下記のようにする必要があります。

  1. 初手真ん中に置かれた場合は、端を取る(二目が2つ成立するのを防ぐ)
  2. ユーザーが対角、CPUが真ん中の場合は、辺の中を取る(二目が2つ成立するのを防ぐ)
  3. 真ん中が空いているなら、真ん中を取る(勝ちやすいだっけかな...。そうでもないかも)
  4. CPUの三目が成立するところに置く(勝利条件なので)
  5. 次にユーザーの三目が成立するところに置く(負けないために必要)
  6. 次にユーザーの二目が成立しそうなところに置く(ただし、ユーザーの二目が同時tに2つ成立する場合のみ)
  7. CPUが勝てそうなところ(次で勝つbit和となるところに置く、勝ち筋が同時に2つ発生する場所を優先)
  8. それでも決まらなかったらランダムで良い

だいたいこんな感じでやると負けません。 もし、人相手に勝ちたいなら、上を守っていれば、相手が油断してれば勝てるかと思います。

終わり

以上、あまり頭を使わずに負けない三目並べを作る方法でした。 ソースコードは下記にあります。

github.com