Let's play Othello in Python.
The board will be held in a one-dimensional array of size 64, and the values will be as follows.
--0: Free space ―― 1: Kurokoma (expressed by *) ―― 2: Shirakoma (expressed by 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 . . . . . . . .
Create a function that puts its own piece w (1 or 2) at position p (0 to 63). Since the eight vertical, horizontal, and diagonal data are one-dimensional data, look in the direction deviated from the current position by [-9, -8, -7, -1, 1, 7, 8, 9]. This is checked with a combination of [-1, 0, 1] and [-8, 0, 8](excluding 0 and 0 pairs). If you take out the array (b) for each direction and multiply by 0-1 of whether it is the opponent's piece (b == 3-w) cumulatively, the pieces that can be taken are represented by 1, so if you take the sum (sum) , You can see the number of pieces n that can be taken. Let's put it in position 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 . . . . . . . .
To find a good hand, add the following points with appropriate weight.
――You can get a lot. ――There are fewer places to hit the opponent
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 to pass, q to end.
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 . . . . . . . .
>
You should read it a little further.
bash
docker run -it --rm tsutomu7/reversi python reversi.py
When doing it with a browser, please do as follows.
bash
firefox http://localhost:8888 &
docker run -it --rm -p 8888:8888 tsutomu7/reversi
that's all
Recommended Posts