155 lines
4.8 KiB
Python
155 lines
4.8 KiB
Python
|
#!/usr/bin/env python3
|
||
|
# todo list:
|
||
|
# - fix all the todos in the document
|
||
|
# - move 'position' data to its own class with dynamic conversion between
|
||
|
|
||
|
class Board:
|
||
|
unplayed = 0
|
||
|
cross = 1
|
||
|
nought = 2
|
||
|
mappings = {
|
||
|
'a': 0,
|
||
|
'b': 1,
|
||
|
'c': 2,
|
||
|
'd': 3,
|
||
|
'e': 4,
|
||
|
'f': 5,
|
||
|
'g': 6,
|
||
|
'h': 7,
|
||
|
'i': 8,
|
||
|
}
|
||
|
reverse = {i[1]:i[0] for i in mappings.items()}
|
||
|
def __init__(self):
|
||
|
self.board = [[[
|
||
|
[Board.unplayed for i in range(3)] for j in range(3)
|
||
|
] for k in range(3) ] for l in range(3) ]
|
||
|
self.movestring = []
|
||
|
self.turn = Board.cross
|
||
|
def push(self, movestring):
|
||
|
pos = self.translateGlobal(movestring)
|
||
|
self.movestring.append(movestring)
|
||
|
self.board[pos[0]][pos[1]][pos[2]][pos[3]] = self.turn
|
||
|
|
||
|
if self.turn == Board.cross:
|
||
|
self.turn = Board.nought
|
||
|
else:
|
||
|
self.turn = Board.cross
|
||
|
def subboardWin(self, x, y):
|
||
|
b = self.board
|
||
|
for i in range(3):
|
||
|
if b[x][y][i][0] == b[x][y][i][1] == b[x][y][i][2]:
|
||
|
if b[x][y][i][0] != Board.unplayed:
|
||
|
return b[x][y][i][0]
|
||
|
if b[x][y][0][i] == b[x][y][1][i] == b[x][y][2][i]:
|
||
|
if b[x][y][0][i] != Board.unplayed:
|
||
|
return b[x][y][0][i]
|
||
|
if b[x][y][0][0] == b[x][y][1][1] == b[x][y][2][2]:
|
||
|
if b[x][y][0][0] != Board.unplayed:
|
||
|
return b[x][y][0][0]
|
||
|
if b[x][y][2][0] == b[x][y][1][1] == b[x][y][0][2]:
|
||
|
if b[x][y][2][0] != Board.unplayed:
|
||
|
return b[x][y][2][0]
|
||
|
return Board.unplayed
|
||
|
def allEmpty(self):
|
||
|
buf = []
|
||
|
for i in range(3):
|
||
|
for j in range(3):
|
||
|
for k in range(3):
|
||
|
for l in range(3):
|
||
|
if self.board[i][j][k][l] == Board.unplayed:
|
||
|
buf.append(self.translateLocal((i, j, k, l)))
|
||
|
def possibleMoves(self):
|
||
|
# get last move
|
||
|
try:
|
||
|
lastpos = self.movestring[-1]
|
||
|
except IndexError:
|
||
|
# if no moves have been made, return the whole board
|
||
|
ret = []
|
||
|
for i in range(9):
|
||
|
for j in range(9):
|
||
|
buf = []
|
||
|
buf.append(Board.reverse[i])
|
||
|
buf.append(str(j))
|
||
|
ret.append(''.join(buf))
|
||
|
|
||
|
return ret
|
||
|
|
||
|
# get global tuple
|
||
|
lastpos = self.translateGlobal(lastpos)
|
||
|
# check for a subboard win condition in the indicated
|
||
|
# position; if so, just return self.allEmpty()
|
||
|
|
||
|
# WARNING: this will select positions in already won boards that are empty
|
||
|
# needs to be fixed
|
||
|
if self.subboardWin(lastpos[0], lastpos[1]):
|
||
|
return self.allEmpty()
|
||
|
|
||
|
# get all squares in metasquare
|
||
|
# this doesn't work because it's getting the *current* square
|
||
|
# and not the square the move is referring to
|
||
|
# this needs to be fixed
|
||
|
square = self.returnInSquare(self.movestring[-1])
|
||
|
buf = []
|
||
|
for i in square:
|
||
|
# if empty, we can move
|
||
|
if self.isEmpty(i):
|
||
|
buf.append(i)
|
||
|
|
||
|
return buf
|
||
|
def translateGlobal(self, movestring):
|
||
|
globcoords = (
|
||
|
Board.mappings[movestring[0]],
|
||
|
int(movestring[1]) - 1,
|
||
|
)
|
||
|
|
||
|
subboard = (
|
||
|
int(globcoords[0] / 3),
|
||
|
int(globcoords[1] / 3),
|
||
|
)
|
||
|
|
||
|
localpos = (
|
||
|
globcoords[0] % 3,
|
||
|
globcoords[1] % 3,
|
||
|
)
|
||
|
|
||
|
return (subboard[0], subboard[1], localpos[0], localpos[1])
|
||
|
|
||
|
def translateLocal(self, globaltuple):
|
||
|
globcoords = (
|
||
|
globaltuple[0] * 3 + globaltuple[2],
|
||
|
globaltuple[1] * 3 + globaltuple[3] + 1,
|
||
|
)
|
||
|
|
||
|
movestring = []
|
||
|
movestring.append(Board.reverse[globcoords[0]])
|
||
|
movestring.append(str(globcoords[1]))
|
||
|
|
||
|
return ''.join(movestring)
|
||
|
|
||
|
def returnInSquare(self, movestring, convert=True):
|
||
|
orig = self.translateGlobal(movestring)
|
||
|
buf = []
|
||
|
for i in range(3):
|
||
|
for j in range(3):
|
||
|
buf.append((orig[0], orig[1], i, j))
|
||
|
|
||
|
if convert:
|
||
|
rbuf = []
|
||
|
for i in buf:
|
||
|
rbuf.append(Board.translateLocal(self, i))
|
||
|
|
||
|
return rbuf
|
||
|
|
||
|
return buf
|
||
|
def isEmpty(self, movestring):
|
||
|
orig = self.translateGlobal(movestring)
|
||
|
item = self.board[orig[0]][orig[1]][orig[2]][orig[3]]
|
||
|
if item == Board.unplayed:
|
||
|
return True
|
||
|
return False
|
||
|
def isFull(self, movestring):
|
||
|
return not self.isEmpty(movestring)
|
||
|
def getInnerBoard(self, x, y):
|
||
|
pass
|
||
|
|