from abc import ABC
from abc import abstractmethod
from typing import List, Tuple

class Strategy(ABC):
    @abstractmethod
    def returnMove(self, board: List[List[bool]]) -> Tuple[int, int]:
        '''Returns a tuple(row, column) which indicates where to move 
           in a 3x3 grid.'''
        pass

class CornerStrategy(Strategy):
    def returnMove(self, board: List[List[bool]]) -> Tuple[int, int]:
        if board[0][0] == None:
            return (0, 0)
        elif board[0][2] == None:
            return (0, 2)
        elif board[2][0] == None:
            return (2, 0)
        elif board[2][2] == None:
            return (2, 2)
        else:
            raise Exception
        
class Game:
    def __init__(self, player1: Strategy, player2: Strategy):
        self.playerOne = player1
        self.playerTwo = player2
        self.board = [[None for _ in range(3)] for _ in range(3)]

    def player1Won(self):
        playerTurn = True
        while not self.playerXWon(True) and not self.playerXWon(False) and not self.gameOver():
             strat = self.playerOne if playerTurn else self.playerTwo
             move = strat.returnMove(self.board)
             self.board[move[0]][move[1]] = playerTurn
             playerTurn = not playerTurn
        if self.gameOver():
            return False
        else:
            return self.playerXWon(True)


    def gameOver(self):
        for row in self.board:
            for col in row:
                if col == None:
                    return False
        return True
    
    def playerXWon(self, x: bool):
        for i in range(3):
            if self.rowNX(i, x):
                return True
        for i in range(3):
            if self.colNX(i, x):
                return True
        downDiag = self.board[0][0] == x and self.board[1][1] == x and self.board[2][2] == x
        upDiag = self.board[2][0] == x and self.board[1][1] == x and self.board[0][2] == x
        return downDiag or upDiag
    


    def rowNX(self, n: int, x: bool):
        for col in self.board[n]:
            if col != x:
                return False
        return True
    def colNX(self, n: int, x: bool):
        for row in self.board:
            if row[n] != x:
                return False
        return True