forked from kenjyoung/KHex
/
gamestate.py
172 lines (153 loc) · 4.66 KB
/
gamestate.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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import numpy as np
from unionfind import unionfind
class gamestate:
"""
Stores information representing the current state of a game of hex, namely
the board and the current turn. Also provides functions for playing the game
and returning information about it.
"""
#dictionary associating numbers with players for book keeping
PLAYERS = {"none" : 0, "white" : 1, "black" : 2}
PLAYER_STR = {0 : "none", 1 : "white", 2: "black"}
OPPONENT ={0 : 0, 1 : 2, 2 : 1}
#move value of -1 indicates the game has ended so no move is possible
GAMEOVER = -1
#represent edges in the union find strucure for win detection
EDGE1 = 1
EDGE2 = 2
neighbor_patterns = ((-1,0), (0,-1), (-1,1), (0,1), (1,0), (1,-1))
def __init__(self, size):
"""
Initialize the game board and give white first turn.
Also create our union find structures for win checking.
"""
self.size = size
self.toplay = self.PLAYERS["black"]
self.board = np.zeros((size, size))
self.white_groups = unionfind()
self.black_groups = unionfind()
def play(self, cell):
"""
Play a stone of the current turns color in the passed cell.
"""
if(self.toplay == self.PLAYERS["white"]):
self.place_white(cell)
self.toplay = self.PLAYERS["black"]
elif(self.toplay == self.PLAYERS["black"]):
self.place_black(cell)
self.toplay = self.PLAYERS["white"]
def place(self, color, cell):
"""
Place a stone of the given color regardless of whose turn it is
"""
if(color == self.PLAYERS["white"]):
self.place_white(cell)
elif(color == self.PLAYERS["black"]):
self.place_black(cell)
else:
raise ValueError("Unrecognized color")
def place_white(self, cell):
"""
Place a white stone regardless of whose turn it is.
"""
if(self.board[cell] == self.PLAYERS["none"]):
self.board[cell] = self.PLAYERS["white"]
else:
raise ValueError("Cell occupied")
#if the placed cell touches a white edge connect it appropriately
if(cell[0] == 0):
self.white_groups.join(self.EDGE1, cell)
if(cell[0] == self.size -1):
self.white_groups.join(self.EDGE2, cell)
#join any groups connected by the new white stone
for n in self.neighbors(cell):
if(self.board[n] == self.PLAYERS["white"]):
self.white_groups.join(n, cell)
def place_black(self, cell):
"""
Place a black stone regardless of whose turn it is.
"""
if(self.board[cell] == self.PLAYERS["none"]):
self.board[cell] = self.PLAYERS["black"]
else:
raise ValueError("Cell occupied")
#if the placed cell touches a black edge connect it appropriately
if(cell[1] == 0):
self.black_groups.join(self.EDGE1, cell)
if(cell[1] == self.size -1):
self.black_groups.join(self.EDGE2, cell)
#join any groups connected by the new black stone
for n in self.neighbors(cell):
if(self.board[n] == self.PLAYERS["black"]):
self.black_groups.join(n, cell)
def turn(self):
"""
Return the player with the next move.
"""
return self.toplay
def set_turn(self, player):
"""
Set the player to take the next move.
"""
if(player in self.PLAYERS.values() and player !=self.PLAYERS["none"]):
self.toplay = player
else:
raise ValueError('Invalid turn: ' + str(player))
def winner(self):
"""
Return a number corresponding to the winning player,
or none if the game is not over.
"""
if(self.white_groups.connected(self.EDGE1, self.EDGE2)):
return self.PLAYERS["white"]
elif(self.black_groups.connected(self.EDGE1, self.EDGE2)):
return self.PLAYERS["black"]
else:
return self.PLAYERS["none"]
def neighbors(self, cell):
"""
Return list of neighbors of the passed cell.
"""
x = cell[0]
y=cell[1]
return [(n[0]+x , n[1]+y) for n in self.neighbor_patterns\
if (0<=n[0]+x and n[0]+x<self.size and 0<=n[1]+y and n[1]+y<self.size)]
def cell_color(self, cell):
return self.board[cell]
def moves(self):
"""
Get a list of all moves possible on the current board.
"""
moves = []
for y in range(self.size):
for x in range(self.size):
if self.board[x,y] == self.PLAYERS["none"]:
moves.append((x,y))
return moves
def __str__(self):
"""
Print an ascii representation of the game board.
"""
white = 'O'
black = '@'
empty = '.'
ret = '\n'
coord_size = len(str(self.size))
offset = 1
ret+=' '*(offset+1)
for x in range(self.size):
ret+=chr(ord('A')+x)+' '*offset*2
ret+='\n'
for y in range(self.size):
ret+=str(y+1)+' '*(offset*2+coord_size-len(str(y+1)))
for x in range(self.size):
if(self.board[x, y] == self.PLAYERS["white"]):
ret+=white
elif(self.board[x,y] == self.PLAYERS["black"]):
ret+=black
else:
ret+=empty
ret+=' '*offset*2
ret+=white+"\n"+' '*offset*(y+1)
ret+=' '*(offset*2+1)+(black+' '*offset*2)*self.size
return ret