forked from jpypi/othello-rl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathboard.py
149 lines (124 loc) · 4.83 KB
/
board.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
import sys
from collections import defaultdict
import numpy as np
from colorama import init, Fore, Back, Style
init(autoreset=True)
class Board(object):
BLACK = 1
WHITE = -1
def __init__(self):
self.board = np.zeros((8,8), int)
self.board[3][3] = Board.BLACK
self.board[4][4] = Board.BLACK
self.board[4][3] = Board.WHITE
self.board[3][4] = Board.WHITE
self.remaining_squares = 8*8 - 4
self.score = {Board.BLACK: 2, Board.WHITE: 2}
def getScore(self):
return self.score
def getState(self):
return self.board
def isOnBoard(self, x, y):
"""
Returns True if the coordinates are located on the board.
"""
return x >= 0 and x <= 7 and y >= 0 and y <= 7
def updateBoard(self, tile, row, col):
"""
@param int tile
either 1 or -1
1 for player 1 (black)
-1 for player 2 (white)
@param int row
0-7 which row
@param int col
0-7 which col
@return bool
true if valid
false if invalid move - doesn't update board
"""
result = self.isValidMove(tile, row, col)
if result:
# Flip the disks
self.board[row][col] = tile
for row in result:
self.board[row[0]][row[1]] = tile
# Update the players' scores
self.score[tile] += len(result) + 1
# The gross expression is a mapping for -1 -> 1 and 1 -> -1
# Rescales the range to [0,1] then mod 2 then rescale back to [-1,1]
self.score[(((tile+1)//2+1)%2)*2-1] -= len(result)
# Number of open squares decreases by 1
self.remaining_squares -= 1
return True
else:
return False
def isValidMove(self, tile, xstart, ystart):
"""
From https://inventwithpython.com/reversi.py
@param int tile
self.BLACK or self.WHITE
@param int xstart
@param int ystart
Returns False if the player's move on space xstart, ystart is invalid.
If it is a valid move, returns a list of spaces that would become the
player's if they made a move here.
"""
if not self.isOnBoard(xstart, ystart) or self.board[xstart][ystart] != 0:
return False
# temporarily set the tile on the board.
self.board[xstart][ystart] = tile
otherTile = tile * -1
tiles_to_flip = []
# loop through all directions around flipped tile
for xdirection, ydirection in ((0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1)):
x, y = xstart, ystart
x += xdirection # first step in the direction
y += ydirection # first step in the direction
if self.isOnBoard(x, y) and self.board[x][y] == otherTile:
# There is a piece belonging to the other player next to our piece.
x += xdirection
y += ydirection
if not self.isOnBoard(x, y):
continue
while self.board[x][y] == otherTile:
x += xdirection
y += ydirection
if not self.isOnBoard(x, y):
# break out of while loop, then continue in for loop
break
if not self.isOnBoard(x, y):
continue
if self.board[x][y] == tile:
# There are pieces to flip over. Go in the reverse direction
# until we reach the original space, noting all the tiles
# along the way.
while True:
x -= xdirection
y -= ydirection
if x == xstart and y == ystart:
break
tiles_to_flip.append([x, y])
# restore the empty space
self.board[xstart][ystart] = 0
# If no tiles were flipped, this is not a valid move.
return tiles_to_flip
def printBoard(self):
"""
Print board to terminal for debugging
"""
def getItem(item):
if item == Board.BLACK :
return Fore.WHITE + "|" + Fore.BLACK + "O"
elif item == Board.WHITE :
return Fore.WHITE + "|" + Fore.WHITE + "O"
else:
return Fore.WHITE + "| "
def getRow(row):
return "".join(map(getItem,row))
print("\t" + Back.GREEN + " BOARD ")
print("\t" + Back.GREEN + Fore.WHITE + " |0|1|2|3|4|5|6|7")
for i in range(8):
print("\t" + Back.GREEN + Fore.WHITE + "{}{}".format(i,
getRow(self.board[i])))
sys.stdout.write(Style.RESET_ALL)