diff --git a/board.py b/board.py new file mode 100644 index 0000000..89bf7c7 --- /dev/null +++ b/board.py @@ -0,0 +1,154 @@ +#!/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 +