-
Notifications
You must be signed in to change notification settings - Fork 0
/
go_rules.py
executable file
·149 lines (119 loc) · 4.66 KB
/
go_rules.py
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env python
import time
import matplotlib.pyplot as plt
from itertools import chain,product
import numpy as np
BOARD_LEN = 9
class Stone:
def __init__(self,coords,color):
self.coords = coords
self.group = None
self.color = color
def neighbors(self,state,color=None,invert=False):
neighbors = []
i,j = self.coords
intersections = [[i,i,i+1,i-1],[j+1,j-1,j,j]]
for k,l in zip([i,i,i+1,i-1],[j+1,j-1,j,j]):
try:
if state[k,l] is not None and not invert:
if color is None:
neighbors.append(state[k,l])
else:
if state[k,l].color == color:
neighbors.append(state[k,l])
elif state[k,l] is None and invert: # we are counting liberties
neighbors.append((k,l))
except KeyError:
pass
return neighbors
class Goban():
def __init__(self):
self.state = { (i,j): None
for (i,j) in product(
range(BOARD_LEN),range(BOARD_LEN),repeat=True)
}
self.group_libs = {}
self.initialize()
def initialize(self):
self.add_stone(Stone((4,4),'black'))
self.add_stone(Stone((5,5),'black'))
self.add_stone(Stone((4,5),'white'))
self.add_stone(Stone((5,4),'white'))
def get_stones(self):
return [stone for stone in self.state.values()
if stone is not None]
def to_int(self,color):
board = np.zeros([BOARD_LEN]*2)
for coord,stone in self.state.items():
if stone is not None:
board[coord] = 2*int(stone.color==color)-1
return board
# Merge groupe g1 and g2 and compute new liberties
def merge_groups(self,g1,g2):
for stone in self.get_stones():
if stone.group == g2:
stone.group = g1
del self.group_libs[g2]
self.count_liberties(g1)
# Count liberties in group
def count_liberties(self,group):
stones = [ stone_g for stone_g
in self.get_stones()
if stone_g.group == group ]
neighs = chain(*[stone.neighbors(self.state,
color=stone.color,
invert=True)
for stone in stones])
self.group_libs[group] = len(set(neighs))
# Add stone on goban and creates new group/call merging if needed
def add_stone(self,stone):
self.state[stone.coords] = stone
neighbors = stone.neighbors(self.state)
N_common = 0
for neigh in neighbors:
# Stone added to a new group
if neigh.color == stone.color and N_common == 0:
N_common += 1
stone.group = neigh.group
self.count_liberties(neigh.group)
# Stone links 2 groups
if neigh.color == stone.color and \
stone.group != neigh.group and \
N_common == 1:
self.merge_groups(stone.group,neigh.group)
N_common = 1
# Stone touch ennemy group
if neigh.color != stone.color:
self.group_libs[neigh.group] -= 1
# Stone has no friends -> new group
if N_common == 0:
if len(self.group_libs)>0:
stone.group = np.max(list(self.group_libs.keys())) + 1
else:
stone.group = 0
self.count_liberties(stone.group)
def is_over(self):
return (0 in self.group_libs.values())
def show(self,display_time=2):
fig,ax = plt.subplots()
ax.set_facecolor((0.66, 0.34, 0))
ax.set_xlim([0,8])
ax.set_ylim([0,8])
stones = self.get_stones()
points = [stone.coords for stone in stones]
colors = ['k' if stone.color == 'black' else 'w'
for stone in stones]
plt.scatter(*zip(*points),c=colors,s=800)
for stone in stones:
col = 'w'*(stone.color=='black')+'k'*(stone.color=='white')
ax.annotate(self.group_libs[stone.group],
stone.coords,
color=col,
fontsize=12)
plt.show(block=False)
plt.grid(True)
plt.pause(display_time)
plt.close()
if __name__ == '__main__':
game = Goban()
game.show()