#!/usr/bin/env python import copy from pos import TwoDPos class BoardTools: def __init__(self): pass def winning(self, b): for i in range(3): if b[i][0] == b[i][1] == b[i][2]: if b[i][0] != Board.unplayed: return b[i][0] if b[0][i] == b[1][i] == b[2][i]: if b[0][i] != Board.unplayed: return b[0][i] if b[0][0] == b[1][1] == b[2][2]: if b[0][0] != Board.unplayed: return b[0][0] if b[2][0] == b[1][1] == b[0][2]: if b[2][0] != Board.unplayed: return b[2][0] spaces = 0 for i in range(3): for j in range(3): if b[i][j] != Board.unplayed: spaces += 1 if spaces == 9: return Board.tie return Board.unplayed class Board: unplayed = 0 cross = 1 nought = 2 tie = 3 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.moves = [] self.turn = Board.cross def copy(self): new = Board() new.board = copy.deepcopy(self.board) new.moves = copy.deepcopy(self.moves) new.turn = copy.deepcopy(self.turn) return new def set(self, a, b, c, d, val): self.board[a][b][c][d] = val def get(self, a, b, c, d): return self.board[a][b][c][d] def alternate(self): if self.turn == Board.cross: self.turn = Board.nought else: self.turn = Board.cross def subWin(self, x, y): return BoardTools.winning(None, self.board[x][y]) def metaboard(self): return [[BoardTools.winning(None, self.board[x][y]) for x in range(3)] for y in range(3)] def win(self): return BoardTools.winning(self.metaboard()) def append(self, move): self.moves.append(move) self.set(*move.local(), self.turn) self.alternate() def reachableEmpty(self): metaboard = self.metaboard() buf = [] for i in range(3): for j in range(3): if metaboard[j][i] == Board.unplayed: for k in range(3): for l in range(3): if self.board[i][j][k][l] == Board.unplayed: buf.append(TwoDPos(TwoDPos.l, (i, j, k, l))) return buf def possible(self): # check if board is in final state isFinal = BoardTools.winning(self, self.metaboard()) if isFinal in [Board.tie, Board.cross, Board.nought]: return [] try: move = self.moves[-1] except IndexError: buf = [] for i in range(3): for j in range(3): for k in range(3): for l in range(3): buf.append(TwoDPos(TwoDPos.l, (i, j, k, l))) return buf local = move.local() if self.subWin(local[2], local[3]) in [Board.tie, Board.nought, Board.cross]: return self.reachableEmpty() buf = [] for i in range(3): for j in range(3): if self.board[local[2]][local[3]][i][j] == Board.unplayed: buf.append(TwoDPos(TwoDPos.l, (local[2], local[3], i, j))) return buf