3目並べ(ランダム)

3目並べ

3目並べは、3×3のマス目に〇と×を交互に書いて、縦・横・斜めのいずれかに3つを並べたほうが勝ちとなるゲームです。

解き方・ソースコード

ビット演算を使って3目並べを実装してみます。

先手と後手を別々の変数で保持します。

また、2進数の各桁を9か所のマスに割り当てます。

縦3マス、横3マスを2進数の1次元配列に対応づけると、空いているマスは先手と後手の変数に対してOR演算を行うと簡単にチェックできます。
(すべてのマスが埋まっていると、OR演算の結果として全てのビットが1になります。)


勝負の判定は、同じ記号が3つ並んだ場合で行うため、3つ並んだパターンを事前に用意しておきます。(goal変数)

このパターンとAND演算を行った結果が、パターンと同じであれば3つ並んだと判定できます。(check関数)


プレイ方法として、コンピュータ同士の対戦で、マス目の空いているところにランダムに置いていくことにします。
(実行するたびに結果が変わります。)

空いている場所(マス目)は、現在の盤面(双方のOR演算した結果)に対して1桁ずつAND演算を行い、0となったものを探します。(28行目)

[Google Colaboratory]

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
import random

goal = [0b111000000, 0b000111000, 0b000000111, # 横に3つ並んだケース
0b100100100, 0b010010010, 0b001001001, # 縦に3つ並んだケース
0b100010001, 0b001010100] # 斜めに3つ並んでケース

# 3つが並んだか判定
def check(player):
for mask in goal:
if player & mask == mask:
return True
return False

# 交互に置く
def play(p1, p2):
if check(p2): # 3つ並んでいたら出力して終了
print('勝負あり')
print([bin(p1), bin(p2)])
return

board = p1 | p2
if board == 0b111111111: # すべて置いたら引き分けで終了
print('引き分け')
print([bin(p1), bin(p2)])
return

# 置ける場所(マス目)を探す
w = [i for i in range(9) if (board & (1 << i)) == 0]
# ランダムに置く
r = random.choice(w)
play(p2, p1 | (1 << r)) # 手番を入れ替えて次を探す

play(0, 0) # プレイ開始

[実行結果(勝負がつく場合)]

勝負あり
['0b10101000', '0b1000111']

下段が3つ並んでいるので勝負がついています。

[実行結果(引き分けの場合)]

引き分け
['0b10100101', '0b101011010']

全てのマスが埋まっていて、3つ並んでいる箇所がないため引き分けとなります。