class TicTacToeTest(unittest.TestCase):

    def setUp(self):
        self.ai = TicTacToeAI()

    def test_solve_state(self):
        states = ["xexeoeeoe", "xexooxeee", "xoxxoeoxe", "xeeeeeeee",
                  "xeeeoeeex", "xxxeoeoee", "oooexexex", "xoxxoooxx",
                  "xxoeoxeee", "eeeeeeeee"]
        expected_results = ["win", "loss", "tie", "tie", "tie", "loss",
                            "loss", "tie", "win", "tie"]
        results = [self.ai.solve_state(s) for s in states]
        for i in range(len(expected_results)):
            self.assertEqual(expected_results[i], results[i], "For state: " +
                             states[i] + " Expected: " + expected_results[i] +
                             " Got: " + results[i])

    def test_get_move(self):
        states = ["xexeoeeoe", "xexooxeee", "xoxxoeoxe", "xeeeeeeee",
                  "xeeeoeeex", "xxxeoeoee", "oooexexex", "xoxxoooxx",
                  "eeeeeeeee"]
        expected_moves = [[(0, 1)],
                          [(0, 1)],
                          [(1, 2), (2, 2)],
                          [(1, 1)],
                          [(0, 1), (1, 0), (1, 2), (2, 1)],
                          [None],
                          [None],
                          [None],
                          [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2),
                           (2, 0), (2, 1), (2, 2)]]
        moves = [self.ai.get_move(s) for s in states]
        for i in range(len(expected_moves)):
            if moves[i] not in expected_moves[i]:
                self.assertTrue(False, "%s is not a correct move for state: "
                                % (moves[i],) + states[i])
示例#2
0
class TicTacToeGUI:

    ai = None

    def __init__(self, master):
        # Initial Frame
        self.frame = Frame(master)
        self.frame.pack(fill="both", expand=True)

        # Board canvas
        self.canvas = Canvas(self.frame, width=300, height=300)

        # Symbol selection buttons
        self.x_button = Button(self.frame, text='Play as X', height=4,
                               command=self.set_player_x, bg='white',
                               fg='black')
        self.o_button = Button(self.frame, text='Play as O', height=4,
                               command=self.set_player_o, bg='white',
                               fg='red')

        # Game start button and info box
        self.start_button = Button(self.frame, text="START", height=4,
                                   command=self.start, bg='white', fg='purple')
        self.info_box = Label(self.frame, text='Tic Tac Toe Game', height=4,
                              bg='white', fg='blue')

        self.clean_game_board()

    def start(self):
        """Sets up game board, starts a tic tac toe game,
        and a new AI if one doesn't exist. AI makes first move if
        playing as X
        """
        self.set_game_board()
        self.game = TicTacToe()
        self.game.start()
        if not self.ai:
            self.ai = TicTacToeAI()

        if self.ai_symbol == 'x':
            self.ai_action()

    def _board(self):
        """Draws tic tac toe board"""
        self.canvas.create_rectangle(0, 0, 300, 300, outline="black")
        self.canvas.create_rectangle(100, 300, 200, 0, outline="black")
        self.canvas.create_rectangle(0, 100, 300, 200, outline="black")

    def user_action(self, event):
        """Attempts to take action that matches user click. If the move is valid,
        then calls the AI to make the next move. If not, displays the error.
        """
        move_x = event.x // 100
        move_y = event.y // 100
        move_result = self.game.update(self.player_symbol, (move_x, move_y))
        if move_result == "Success":
            board_x = (200 * move_x + 100) / 2
            board_y = (200 * move_y + 100) / 2
            if self.player_symbol == 'x':
                self.draw_x(board_x, board_y)
            else:
                self.draw_o(board_x, board_y)
            if not self.completed():
                # Wait a bit before calling the ai, for visual style
                self.frame.after(500, self.ai_action)
        else:
            self.info_box['text'] = move_result

    def ai_action(self):
        """Gets the next move from the AI based on current game state,
        and plays.
        """
        state = self.game.get_board()
        move = self.ai.get_move(state)
        move_result = self.game.update(self.ai_symbol, move)
        if move_result == "Success":
            board_x = (200 * move[0] + 100) / 2
            board_y = (200 * move[1] + 100) / 2
            if self.ai_symbol == 'x':
                self.draw_x(board_x, board_y)
            else:
                self.draw_o(board_x, board_y)
            self.completed()

    def completed(self):
        """Checks the game status. If completed, displays the result,
        and asks whether the player would like to start another game.
        """
        status = self.game.done()
        if status == 'e':
            return False
        message = "Click to start a new game."
        if status == 't':
            message = "Tie game. " + message
        else:
            message = "Player " + status.upper() + " has won. " + message
        self.info_box.pack_forget()
        self.start_button.pack(fill="both", expand=True)
        self.start_button["text"] = message
        self.start_button["command"] = self.clean_game_board

    def draw_x(self, x, y):
        self.canvas.create_line(x + 20, y + 20, x - 20, y - 20, width=4,
                                fill="black")
        self.canvas.create_line(x - 20, y + 20, x + 20, y - 20, width=4,
                                fill="black")

    def draw_o(self, x, y):
        self.canvas.create_oval(x + 25, y + 25, x - 25, y - 25, width=4,
                                outline="red")

    def set_game_board(self):
        """Hides game start buttons, reveals the game board and info box."""
        self.start_button.pack_forget()
        self.x_button.pack_forget()
        self.o_button.pack_forget()
        self.canvas.delete(ALL)
        self.canvas.pack(fill="both", expand=True)
        self.info_box.pack(fill="both", expand=True)
        self.canvas.bind("<ButtonPress-1>", self.user_action)
        self._board()

    def clean_game_board(self):
        """Hides game board and label, reveals game start buttons."""
        self.canvas.pack_forget()
        self.info_box.pack_forget()
        self.start_button.pack_forget()
        self.x_button.pack(fill="both", expand=True)
        self.o_button.pack(fill="both", expand=True)

    def set_player_x(self):
        self.player_symbol = 'x'
        self.ai_symbol = 'o'
        self.start()

    def set_player_o(self):
        self.player_symbol = 'o'
        self.ai_symbol = 'x'
        self.start()