LoginSignup
28
33

More than 5 years have passed since last update.

オセロ(リバーシ)で遊ぶ

Last updated at Posted at 2016-06-11

これはなに

Pythonでオセロ対戦してみます。

盤面の初期化と表示

盤面は、サイズ64の1次元配列で持つことにし、値は下記の通りとします。

  • 0: 空きマス
  • 1: 黒駒(*で表現)
  • 2: 白駒(oで表現)
python3
import numpy as np
def create_board():
    a = np.zeros(64, dtype=int)
    a[27] = a[36] = 1
    a[28] = a[35] = 2
    return a
def print_board(a):
    print('  a b c d e f g h')
    for i in range(8):
        print(i+1, end=' ')
        print(' '.join('.*o'[j] for j in a[i*8:][:8]))

a = create_board()
print_board(a)
>>>
  a b c d e f g h
1 . . . . . . . .
2 . . . . . . . .
3 . . . . . . . .
4 . . . * o . . .
5 . . . o * . . .
6 . . . . . . . .
7 . . . . . . . .
8 . . . . . . . .

駒を置く

自駒w(1 or 2)を位置p(0~63)に置く関数を作ります。
縦横斜めの8通りは、1次元データなので、現在位置から[-9, -8, -7, -1, 1, 7, 8, 9] ずれた方向を見ます。これは、[-1, 0, 1]と[-8, 0, 8]の組合せで調べます(0と0のペアは除く)。
各方向毎に配列(b)を取り出し、相手の駒かどうか(b==3-w)の0-1を累積でかけると、とれる駒が1で表されるので、合計(sum)をとると、とれる駒数nがわかります。
位置20("e3")に置いてみましょう。

python3
def put_piece(a, p, w, puton=True, chk=True):
    t, x, y = 0, p%8, p//8
    for di, fi in zip([-1, 0, 1], [x, 7, 7-x]):
        for dj, fj in zip([-8, 0, 8], [y, 7, 7-y]):
            if not di == dj == 0:
                b = a[p+di+dj::di+dj][:min(fi, fj)]
                n = (b==3-w).cumprod().sum()
                if b.size <= n or b[n] != w: n = 0
                t += n
                if puton:
                    b[:n] = w
    if puton:
        if chk: assert(a[p] == 0 and t > 0)
        a[p] = w
    return t
put_piece(a, 20, 1)
print_board(a)
>>>
  a b c d e f g h
1 . . . . . . . .
2 . . . . . . . .
3 . . . . * . . .
4 . . . * * . . .
5 . . . o * . . .
6 . . . . . . . .
7 . . . . . . . .
8 . . . . . . . .

ベストポジションを探す

良い手は、下記のポイントを適当に重みをつけて足して探しましょう。

  • たくさんとれる。
  • 相手の打つところが少なくなる
python3
def best(a, w):
    from math import exp
    r, b, c = [], a.copy(), 1+exp(-np.count_nonzero(a)/16)
    for i in range(64):
        if b[i] != 0: continue
        t = put_piece(b, i, w, True, False)
        if t == 0:
            b[i] = 0
            continue
        u = sum(b[j]==0 and put_piece(b, j, 3-w, False) > 0 for j in range(64))
        r.append((t-c*u+np.random.rand()*0.5, i))
        b = a.copy()
    return sorted(r)[-1][1] if r else -1

対戦してみる

pでパス、qで終了します。

python3
if __name__ == '__main__':
    a = create_board()
    w = 1
    while np.count_nonzero(a) < 64:
        print_board(a)
        s = input('> ')
        if not s or s=='q': break
        if s != 'p':
            try:
                x, y = ord(s[0])-97, int(s[1])-1
                put_piece(a, x+8*y, w)
            except:
                continue
        p = best(a, 3-w)
        if p >= 0:
            put_piece(a, p, 3-w)
    print_board(a)
    n1, n2 = (a==1).sum(), (a==2).sum()
    print('%d - %d %s' % (n1, n2,
        'You win' if n1 > n2 else
        'You lose' if n1 < n2 else 'Draw'))
>>>
  a b c d e f g h
1 . . . . . . . .
2 . . . . . . . .
3 . . . . . . . .
4 . . . * o . . .
5 . . . o * . . .
6 . . . . . . . .
7 . . . . . . . .
8 . . . . . . . .
> e3
  a b c d e f g h
1 . . . . . . . .
2 . . . . . . . .
3 . . . . * o . .
4 . . . * o . . .
5 . . . o * . . .
6 . . . . . . . .
7 . . . . . . . .
8 . . . . . . . .
> f4
  a b c d e f g h
1 . . . . . . . .
2 . . . . . . . .
3 . . . . * o . .
4 . . . * * o . .
5 . . . o o o . .
6 . . . . . . . .
7 . . . . . . . .
8 . . . . . . . .
> g3
  a b c d e f g h
1 . . . . . . . .
2 . . . . . . . .
3 . . . . * * * .
4 . . o o o o . .
5 . . . o o o . .
6 . . . . . . . .
7 . . . . . . . .
8 . . . . . . . .
> c5
  a b c d e f g h
1 . . . . . . . .
2 . . . . . . . .
3 . . . o * * * .
4 . . o o o o . .
5 . . * o o o . .
6 . . . . . . . .
7 . . . . . . . .
8 . . . . . . . .
> 

もう少し先まで読む方がいいですね。

Docker用意しました

bash
docker run -it --rm tsutomu7/reversi python reversi.py

ブラウザでやるときは、下記のようにしてください。

bash
firefox http://localhost:8888 &
docker run -it --rm -p 8888:8888 tsutomu7/reversi

以上

28
33
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
33