import unittest
import const
from game_board import GameBoardADT
from chain_finder import ChainFinder
from helper import edge_setter, unplay_all

finder = ChainFinder()
board = GameBoardADT()


class TestTraverse(unittest.TestCase):
    def test_single(self):
        """
        should return a list of one square when the chain is one long
        """
        unplay_all(board)
        board.setEdgeState(66, const.PLAYED)
        board.setEdgeState(71, const.PLAYED)
        self.assertEqual([37], finder.traverse(37, board))
        board.setEdgeState(66, const.UNPLAYED)
        board.setEdgeState(71, const.UNPLAYED)

    def test_complex_chain_middle(self):
        """
        should return all the squares in the chain, including the one given, even when starting in the middle of the chain
        """
        unplay_all(board)

        # Set some random edges to played
        random_edges = (14, 33, 59, 60, 70, 71)
        edge_setter(random_edges, const.PLAYED, board)
def playGame(gui,player1name,player2name,player1,player2,playsfirst,scorePlayer1,scorePlayer2):
    # Setup and draw board
    board = GameBoardADT()
    drawBoard(gui,board)
    gui.drawNames(player1name,player2name,scorePlayer1,scorePlayer2)
    scores = [None,0,0]
    
    turn = playsfirst

    # For every edge on the board, take a turn. If a square is not captured, switch players. If a square is captured, update scores and states and request another move from the same player.
    for i in range(72):
        gui.drawCurrentPlayer(turn)
        #        print board.getGameState()
        #edge = getEdge(board)
        # Request the current game state
        state = board.getGameState()
        # Send game state to current player and request move
        edge = player1.chooseMove(state) if turn==const.PLAYER1 else player2.chooseMove(state)
        if isValidEdge(board,edge)==False:
            # Current player has made an invalid move and forfeits the game
            scores[turn]=-1
            break
        # Draw the new edge on the board and update the game state
        drawEdge(gui,board,edge)
        board.setEdgeState(edge,const.PLAYED)
        # Check whether any squares have been captured and update scores accordingly
        captured = board.findCaptured(edge)
        if len(captured)==0:
            # No squares captured so switch turns
            turn = const.PLAYER1 if turn==const.PLAYER2 else const.PLAYER2
        elif len(captured)==1:
            # One square captured
            scores[turn]+=1
            fillSquare(gui,board,captured[0],turn)
            board.setSquareState(captured[0],turn)
            gui.addPie(turn,scores[turn])
        elif len(captured)==2:
            # Two squares captured
            scores[turn]+=2
            fillSquare(gui,board,captured[0],turn)
            board.setSquareState(captured[0],turn)
            gui.addPie(turn,scores[turn]-1)
            fillSquare(gui,board,captured[1],turn)
            board.setSquareState(captured[1],turn)
            gui.addPie(turn,scores[turn])
    # Game is over. Return match score (one-nil win or draw)
    if scores[const.PLAYER1]>scores[const.PLAYER2]:
        return (1,0)
    elif scores[const.PLAYER2]>scores[const.PLAYER1]:
        return (0,1)
    else:
        return (0.5,0.5)
def playGame(gui, player1name, player2name, player1, player2, playsfirst,
             scorePlayer1, scorePlayer2):
    print("Starting game")
    stats = GameStats()
    stats.startGame()

    # Setup and draw board
    board = GameBoardADT()
    if const.GUI_ENABLED:
        drawBoard(gui, board)
        gui.drawNames(player1name, player2name, scorePlayer1, scorePlayer2)
    scores = [None, 0, 0]

    turn = playsfirst

    # For every edge on the board, take a turn. If a square is not captured, switch players. If a square is captured, update scores and states and request another move from the same player.
    for i in range(72):
        if const.GUI_ENABLED:
            gui.drawCurrentPlayer(turn)
        #        print board.getGameState()
        #edge = getEdge(board)
        # Request the current game state
        state = board.getGameState()

        # Send game state to current player and request move
        preMoveTime = datetime.datetime.now()
        if turn == const.PLAYER1:
            edge = player1.chooseMove(state)
            stats.p1ResponseTimes.append(datetime.datetime.now() - preMoveTime)
        else:
            edge = player2.chooseMove(state)
            stats.p2ResponseTimes.append(datetime.datetime.now() - preMoveTime)

        if isValidEdge(board, edge) == False:
            # Current player has made an invalid move and forfeits the game
            scores[turn] = -1
            break
        # Draw the new edge on the board and update the game state
        if const.GUI_ENABLED:
            drawEdge(gui, board, edge)
        board.setEdgeState(edge, const.PLAYED)
        # Check whether any squares have been captured and update scores accordingly
        captured = board.findCaptured(edge)
        #print((player1name if turn == const.PLAYER1 else player2name) + " takes " + str(edge) + " for " + str(len(captured)) + " points")
        #print("Score: " + player1name + "(" + str(scorePlayer1) + ") = " + str(scores[const.PLAYER1]) + ", " + player2name + "(" + str(scorePlayer2) + ") = " + str(scores[const.PLAYER2]))
        if len(captured) == 0:
            # No squares captured so switch turns
            turn = const.PLAYER1 if turn == const.PLAYER2 else const.PLAYER2
        elif len(captured) == 1:
            # One square captured
            scores[turn] += 1
            board.setSquareState(captured[0], turn)
            if const.GUI_ENABLED:
                fillSquare(gui, board, captured[0], turn)
                gui.addPie(turn, scores[turn])
        elif len(captured) == 2:
            # Two squares captured
            scores[turn] += 2
            board.setSquareState(captured[0], turn)
            board.setSquareState(captured[1], turn)
            if const.GUI_ENABLED:
                fillSquare(gui, board, captured[0], turn)
                gui.addPie(turn, scores[turn] - 1)
                fillSquare(gui, board, captured[1], turn)
                gui.addPie(turn, scores[turn])

    stats.endGame()
    print("Stats:")
    print("Game duration: {0}".format(str(stats.getGameDuration())))
    print("Player 1 score: " + str(scores[1]))
    print("Player 2 score: " + str(scores[2]))
    print("Player 1 average response time: {0}".format(
        microsecondsToSecondsString(stats.getP1AverageTime())))
    print("Player 2 average response time: {0}".format(
        microsecondsToSecondsString(stats.getP2AverageTime())))

    # Game is over. Return match score (one-nil win or draw)
    if scores[const.PLAYER1] > scores[const.PLAYER2]:
        print(player1name + " wins game")
        return (1, 0)
    elif scores[const.PLAYER2] > scores[const.PLAYER1]:
        print(player2name + " wins game")
        return (0, 1)
    else:
        print("Draw")
        return (0.5, 0.5)
def playGame(gui,player1name,player2name,player1,player2,playsfirst,scorePlayer1,scorePlayer2):
    print("Starting game")
    stats = GameStats()
    stats.startGame()

    # Setup and draw board
    board = GameBoardADT()
    if const.GUI_ENABLED:
        drawBoard(gui,board)
        gui.drawNames(player1name,player2name,scorePlayer1,scorePlayer2)
    scores = [None,0,0]
    
    turn = playsfirst

    # For every edge on the board, take a turn. If a square is not captured, switch players. If a square is captured, update scores and states and request another move from the same player.
    for i in range(72):
        if const.GUI_ENABLED:
            gui.drawCurrentPlayer(turn)
        #        print board.getGameState()
        #edge = getEdge(board)
        # Request the current game state
        state = board.getGameState()

        # Send game state to current player and request move
        preMoveTime = datetime.datetime.now()
        if turn == const.PLAYER1:
            edge = player1.chooseMove(state)
            stats.p1ResponseTimes.append(datetime.datetime.now() - preMoveTime)
        else:
            edge = player2.chooseMove(state)
            stats.p2ResponseTimes.append(datetime.datetime.now() - preMoveTime)

        if isValidEdge(board,edge)==False:
            # Current player has made an invalid move and forfeits the game
            scores[turn]=-1
            break
        # Draw the new edge on the board and update the game state
        if const.GUI_ENABLED:
            drawEdge(gui,board,edge)
        board.setEdgeState(edge,const.PLAYED)
        # Check whether any squares have been captured and update scores accordingly
        captured = board.findCaptured(edge)
        #print((player1name if turn == const.PLAYER1 else player2name) + " takes " + str(edge) + " for " + str(len(captured)) + " points")
        #print("Score: " + player1name + "(" + str(scorePlayer1) + ") = " + str(scores[const.PLAYER1]) + ", " + player2name + "(" + str(scorePlayer2) + ") = " + str(scores[const.PLAYER2]))
        if len(captured)==0:
            # No squares captured so switch turns
            turn = const.PLAYER1 if turn==const.PLAYER2 else const.PLAYER2
        elif len(captured)==1:
            # One square captured
            scores[turn]+=1
            board.setSquareState(captured[0],turn)
            if const.GUI_ENABLED:
                fillSquare(gui,board,captured[0],turn)
                gui.addPie(turn,scores[turn])
        elif len(captured)==2:
            # Two squares captured
            scores[turn]+=2
            board.setSquareState(captured[0],turn)
            board.setSquareState(captured[1],turn)
            if const.GUI_ENABLED:
                fillSquare(gui,board,captured[0],turn)
                gui.addPie(turn,scores[turn]-1)
                fillSquare(gui,board,captured[1],turn)
                gui.addPie(turn,scores[turn])

    stats.endGame()
    print("Stats:")
    print("Game duration: {0}".format(str(stats.getGameDuration())))
    print("Player 1 score: " + str(scores[1]))
    print("Player 2 score: " + str(scores[2]))
    print("Player 1 average response time: {0}".format(microsecondsToSecondsString(stats.getP1AverageTime())))
    print("Player 2 average response time: {0}".format(microsecondsToSecondsString(stats.getP2AverageTime())))

    # Game is over. Return match score (one-nil win or draw)
    if scores[const.PLAYER1]>scores[const.PLAYER2]:
        print(player1name + " wins game")
        return (1,0)
    elif scores[const.PLAYER2]>scores[const.PLAYER1]:
        print(player2name + " wins game")
        return (0,1)
    else:
        print("Draw")
        return (0.5,0.5)