Пример #1
0
def test_within_bounds_returns_true_if_move_is_within_index_range():
    new_board = Board()

    new_board.board = ["X", " ", " ", " ", " ", " ", " ", " ", " "]

    assert not new_board.within_bounds(10)
    assert new_board.within_bounds(1)
Пример #2
0
def test_human_player_can_make_a_move():
    new_board = Board()
    player = Player(token=["X", "O"])

    new_board.move(1, new_board.board, player.token[0])

    assert new_board.board[1] == "X"
Пример #3
0
def test_win_can_detect_a_winning_combination_present_on_the_game_board(
        board_state, win_status):
    new_board = Board()

    new_board.board = board_state

    assert new_board.win() == win_status
Пример #4
0
def test_winner_saves_the_winner(board_state, winner_token):
    new_board = Board()

    new_board.board = board_state

    assert new_board.winner()
    assert new_board.winner() == winner_token
Пример #5
0
def test_game_over_returns_true_when_a_game_is_won(board_state,
                                                   game_over_status):
    new_board = Board()

    new_board.board = board_state

    assert new_board.game_over() == game_over_status
Пример #6
0
def test_turn_count_keeps_track_of_number_of_turns(board_state, turn_count):
    new_board = Board()

    new_board.board = board_state

    player = Player(token=["X", "O"])

    assert new_board.turn_count(player) == turn_count
Пример #7
0
def test_position_taken_returns_true_if_square_is_already_occupied_and_false_if_not(
):
    new_board = Board()

    new_board.board = ["X", " ", " ", " ", " ", " ", " ", " ", " "]

    assert new_board.position_taken(0)
    assert not new_board.position_taken(1)
Пример #8
0
def test_board_raises_error_when_positions_are_taken():
    new_board = Board()
    player = Player(token=["X", "O"])

    new_board.board = ["X"]

    with pytest.raises(PositionAlreadyTakenError):
        new_board.turn(0, player)
Пример #9
0
def test_current_player_returns_current_player_token(board_state,
                                                     current_player):
    new_board = Board()

    new_board.board = board_state

    player = Player(token=["X", "O"])

    assert new_board.current_player(player) == current_player
Пример #10
0
def test_user_interface_congratulates_winner():
    spy = PrinterSpy()
    user_message = UserMessages(spy)
    board = Board()

    board.board = ["X", "O", " ", "X", "O", " ", "X", " ", " "]
    board.win()

    user_message.who_won(board)

    assert spy.printed_item == "X, you're the winner!"
Пример #11
0
def init_board_states():
    state = ['0'] * board_size
    for i in range(3):
        state[0] = str(i)
        for j in range(3):
            state[1] = str(j)
            for k in range(3):
                state[2] = str(k)
                for l in range(3):
                    state[3] = str(l)
                    for m in range(3):
                        state[4] = str(m)
                        for n in range(3):
                            state[5] = str(n)
                            for o in range(3):
                                state[6] = str(o)
                                for p in range(3):
                                    state[7] = str(p)
                                    for q in range(3):
                                        state[8] = str(q)
                                        if valid_state(state):
                                            state_str = "".join(state)
                                            states[state_str] = Board(copy.deepcopy(state))

    set_board_actions()
    def find_possible_states(self, output_path, export=True):
        '''
        Get all possible states
        :param output_path:
        :param export:
        :return:
        '''
        b = Board()
        print('get all possible states: player x plays at first')
        self.get_all_possible_states(b, Board.x_id)

        print('get all possible states: player o plays at first')
        self.get_all_possible_states(b, Board.o_id)

        print(f'Num of possible states = {len(t.states)}')

        # export to file
        if export:
            print(f'export possible states to file')

            with open(output_path, mode='w') as employee_file:
                writer = csv.writer(employee_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
                writer.writerow(['State_id', 'is_over', 'winner'])

                WINNER_COLUMN = 2
                OVER_COLUMN = 1
                STATE_ID_COLUMN = 0

                for pair in self.pairs:
                    if pair[WINNER_COLUMN] == None:
                        # in case that the game is not ended, there is no winner
                        writer.writerow([pair[STATE_ID_COLUMN], pair[OVER_COLUMN], 'None'])
                    else:
                        writer.writerow(pair)
Пример #13
0
def main():
    """main function to ran the game"""
    first, second = introduction()
    if isinstance(first, Player):
        player = 'x_symbol'
    else:
        player = 'o_symbol'
    board = Board()
    while True:
        if board.play:
            board = first.make_move(board, Board.CROSS)
            board.check_status()
        if board.play:
            board = second.make_move(board, Board.ZERO)
            board.check_status()
        else:
            break
    if board.draw:
        print('The game ended in a draw (ಥ_ಥ)')
    # representing end of the game
    if board.have_winner:
        winner = board.winner()
        if (winner == '✗' and player == 'x_symbol'):
            print('Cool, {}, you won the battle, but what about the the '
                  'war'.format(first.player_name))
        elif (winner == 'o' and player == 'o_symbol'):
            print('Cool, {}, you won the battle, but what about the the '
                  'war'.format(second.player_name))
        else:
            print('You lost the battle, but what about the war')
Пример #14
0
def test_tic_tac_toe_display_board_with_user_token():

    new_board = Board()
    view = CommandLineBoardPresenter()
    spy = PrinterSpy()

    new_board.board = ["X", " ", " ", " ", "X", " ", " ", " ", "X"]

    view.display_board(new_board, spy)

    expected = """\
              X |   |  
            --------------
                | X |  
            --------------
                |   | X
        """
    assert spy.printed() == expected
Пример #15
0
def test_tic_tac_toe_display_board():
    new_board = Board()
    view = CommandLineBoardPresenter()
    spy = PrinterSpy()

    view.display_board(new_board, spy)

    expected = """\
                |   |  
            --------------
                |   |  
            --------------
                |   |  
        """
    assert spy.printed() == expected
Пример #16
0
def main():
    print("Choosing player X...")
    player_x = _pick_agent(Player.X)

    print("Choosing player O...")
    player_o = _pick_agent(Player.O)

    size = int(input("Select size of the board >= 3: "))

    print("Select number in a row to win, <=",size,": ", end = '')
    to_win = int(input(""))

    random_board = input("Random board state? y/[n]:")

    play = "y"
    games = 0

    while play == "y":
        if(random_board == "y"):
            game_board = Board(size, to_win)
            game_board.randomize()
            winner = game_board.winner
            while(winner is not None):
                game_board = Board(size, to_win)
                game_board.randomize()
                winner = game_board.winner
        else:
            game_board = None

        game = Game(player_x, player_o, size, to_win, game_board)
        res = game.play()
        games += 1
        
        RESULTS[res + 1][1] += 1

        for line in RESULTS:
            print(*line)

        print("")

        print("X average runtime: ",player_x.average_runtime)
        print("O average runtime: ",player_o.average_runtime)
        print("States visited X", player_x.states_visited)
        print("States visited O", player_o.states_visited)

        play = input("Play again? y/[n]: ")
Пример #17
0
def run():
    board = Board()
    player = Player(token=["X", "O"])
    view = CommandLineBoardPresenter()
    printer = Printer()
    user_messages = UserMessages(printer)
    errors = Errors(printer)

    user_messages.countdown()

    user_messages.logo()

    user_messages.instructions_option()

    if player.get_input() == 0:
        user_messages.display_instructions()
        view.display_board(board, printer)
    else:
        view.display_board(board, printer)
        user_messages.whos_turn(player, board)

    while not board.game_over():
        try:
            selection = player.get_input()
            board.turn(selection, player)
        except InputNotNumericError:
            errors.input_not_numeric_error_message()
        except InvalidBoardIndexError:
            errors.invalid_board_index_error_message()
        except PositionAlreadyTakenError:
            errors.position_already_taken_error_message()
        finally:
            view.display_board(board, printer)
            if not board.win() and not board.tie():
                user_messages.whos_turn(player, board)

    if board.win():
        user_messages.who_won(board)

    if board.tie():
        user_messages.its_a_tie()
Пример #18
0
def read_board_states():
    with open('tic_tac_toe_x_actions.csv') as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=',')
        for row in csv_reader:
            board = row[0]
            states[board] = Board(list(board))

    with open('tic_tac_toe_x_actions.csv') as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=',')
        for row in csv_reader:
            board = row[0]
            row_length = len(row)
            for i in range(1, row_length):
                action = states[row[i]]
                states[board].add_action(action, player_dict['X'])

    with open('tic_tac_toe_o_actions.csv') as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=',')
        for row in csv_reader:
            board = row[0]
            row_length = len(row)
            for i in range(1, row_length):
                action = states[row[i]]
                states[board].add_action(action, player_dict['O'])
Пример #19
0
def play_with_machine(V_machine, human=Board.x_symbol, machine=Board.o_symbol):
    '''

    :param V: value functions of machine
    :param human: 'x' or 'o'
    :param machine: 'o' or 'x'
    :return:
    '''
    current_turn = human

    b = Board()
    board = b.board

    states = []
    states_reward = []

    while not b.is_game_over():

        if current_turn == human:
            print(f'>>> Human turn ({human})')
        else:
            print(f'>>> Machine turn ({machine})')

        if current_turn == human:
            # ask human for move
            available_move = False

            while not available_move:
                print('Let choose the cell you want to play (e.g., 1 2): ')
                inp = input().split(' ')

                row = int(inp[0])
                col = int(inp[1])

                if row > b.height or col > b.width or row < 0 or col < 0:
                    available_move = False
                    print('Wrong move!')
                elif board[row, col] == Board.empty_id:
                    board[row, col] = b.convert_turn_symbol2id(current_turn)
                    available_move = True
                else:
                    available_move = False
                    print('Wrong move!')

        else:
            # find potential moves
            potential_states = []
            potential_moves = []

            for i in range(b.height):
                for j in range(b.width):

                    if board[i, j] == b.empty_id:
                        board[i, j] = b.convert_turn_symbol2id(current_turn)

                        potential_states.append(b.get_state())
                        potential_moves.append([i, j])

                        board[i, j] = b.empty_id

            # find the best move
            if len(potential_moves) > 0:
                best_move_value = 0
                best_move = []
                #print(f'potential_moves = {potential_moves}')

                for idx, state in enumerate(potential_states):
                    print(f'potential move {potential_moves[idx]} = {np.round(V_machine[potential_states[idx]],2)}')

                for move, state in zip(potential_moves, potential_states):
                    if V_machine[state] > best_move_value:
                        best_move_value = V_machine[state]
                        best_move = move

                # play
                print(f'best move: {best_move}')
                board[int(best_move[0]), int(best_move[1])] = b.convert_turn_symbol2id(current_turn)

        # store the state of the board
        states.append(b.get_state())
        states_reward.append(Training.AVERAGE_REWARD)

        # change turn
        if current_turn == human:
            current_turn = machine
        else:
            current_turn = human

        b.draw_board()

    print(f'Winner = {b.winner_symbol}')
Пример #20
0
class SuboptimalAgent(Agent):
    board = Board()

    def get_appended_board_state(self, board_state, cell_value, i, j):
        board_state[i][j] = cell_value
        return board_state

    def minimax(self, board_state, maximizer, depth):
        self.board._board = board_state
        # self.board.print_board()
        current_utility = None
        chosen_utility = None
        if self._player == Player.X:
            if self.board.winner == Player.X:
                return 1 / depth
            if self.board.winner == Player.O:
                return -1 / depth
        else:
            if self.board.winner == Player.O:
                return 1 / depth
            if self.board.winner == Player.X:
                return -1 / depth
        if depth == self.board.size**2:
            return 0

        # self.board.print_board()
        for i in range(self.board.size):
            for j in range(self.board.size):
                if self.board.cell(i, j) == CellState.EMPTY:
                    if self._player == Player.X:
                        if maximizer and chosen_utility != 1:
                            current_utility = self.minimax(
                                self.get_appended_board_state(
                                    board_state, 0, i, j), not maximizer,
                                depth + 1)
                            #here the state would be restored, but instead the board simply fills up
                            self.board._board = board_state
                        if not maximizer and chosen_utility != -1:
                            current_utility = self.minimax(
                                self.get_appended_board_state(
                                    board_state, 1, i, j), not maximizer,
                                depth + 1)
                            self.board._board = board_state
                    else:
                        if maximizer and chosen_utility != 1:
                            current_utility = self.minimax(
                                self.get_appended_board_state(
                                    board_state, 1, i, j), not maximizer,
                                depth + 1)
                            self.board._board = board_state
                        if not maximizer and chosen_utility != -1:
                            current_utility = self.minimax(
                                self.get_appended_board_state(
                                    board_state, 0, i, j), not maximizer,
                                depth + 1)
                            self.board._board = board_state

                    if current_utility is not None:
                        if maximizer:
                            if chosen_utility is None or current_utility > chosen_utility:
                                chosen_utility = current_utility
                        else:
                            if chosen_utility is None or current_utility < chosen_utility:
                                chosen_utility = current_utility
        return chosen_utility

    def next_move(self, given_board):
        self.board._size = given_board._size
        self.board._k = given_board._k

        best_move_i = -1
        best_move_j = -1
        maximum = -100
        depth = given_board.size**2

        maximizer = True

        for i in range(given_board.size):
            for j in range(given_board.size):
                if given_board.cell(i, j) == CellState.EMPTY:
                    depth -= 1

        for i in range(given_board.size):
            for j in range(given_board.size):
                if given_board.cell(i, j) == CellState.EMPTY:
                    if self._player == Player.X:
                        current = self.minimax(
                            self.get_appended_board_state(
                                deepcopy(given_board._board), 0, i, j),
                            not maximizer, depth + 1)
                    else:
                        current = self.minimax(
                            self.get_appended_board_state(
                                deepcopy(given_board._board), 1, i, j),
                            not maximizer, depth + 1)
                    if current is not None:
                        if current > maximum:
                            maximum = current
                            best_move_i = i
                            best_move_j = j
        return Move(self._player, best_move_i, best_move_j)
Пример #21
0
def test_tie_can_detect_a_full_board_with_no_winners():
    new_board = Board()

    new_board.board = ["X", "O", "X", "O", "X", "O", "O", "X", "O"]

    assert new_board.tie()
class BruteForceAgent(Agent):
    #initializes the board object and the state space
    board = Board()
    state_space = 0

    #returns a board state with a changed cell value at the given coordinates
    def get_appended_board_state(self, board_state, cell_value, i, j):
        board_state[i][j] = cell_value
        return board_state

    #minimax algorithm for brute force, taking a board configuration integer array, a maximizer boolean, and a depth integer as parameters
    def minimax(self, board_state, maximizer, depth):
        #increments state space and fixes the new board state to the board object at each recursive call
        self.state_space += 1
        self.board._board = board_state

        #initialize current and chosen utility
        current_utility = None
        chosen_utility = None

        #this code block catches any winning boards and returns their evaluations; it minimizes calculation by only calculating board.winner once and setting it
        #to a variable; calculation is reduced further by only calculating board.winner in cases where the depth is deep enough for a winner to be possible,
        #i.e. the depth is greater than or equal to the depth of the winning sequence
        winner = None
        if depth > self.board._k - 1:
            winner = self.board.winner
        if self._player == Player.X:
            if winner == Player.X:
                #depth is accounted for in evaluating the winning board states; this allows the agent to find the quickest path to victory within the game,
                #but it does not change the winrate of the agent (since it will only cause the agent to win in less moves, not more frequently), and it
                #increases calculation time fairly significantly
                return 1 / depth
            if winner == Player.O:
                return -1 / depth
        else:
            if winner == Player.O:
                return 1 / depth
            if winner == Player.X:
                return -1 / depth

        #accounts for the case of a drawn board, returning an evaluation of 0
        if depth == self.board.size**2:
            return 0

        #this code block is the main body of the algorithm; it loops through the given board and calculates minimax on every empty square
        for i in range(self.board.size):
            for j in range(self.board.size):
                if self.board.cell(i, j) == CellState.EMPTY:
                    #this if duplicates the functionality of the loop for players X and O
                    if self._player == Player.X:
                        #this if duplicates the functionality of the loop for the maximizer and the minimizer
                        if maximizer and chosen_utility != 1:
                            #sets the currently examined utility equal to the minimax evaluation of the current blank square; the current player's
                            #symbol (X or O) is placed in the coordinates of the blank, and the resulting board is passed as a new board state;
                            #the maximizer/minimizer is swapped and passed; the new depth is passed
                            current_utility = self.minimax(
                                self.get_appended_board_state(
                                    board_state, 0, i, j), not maximizer,
                                depth + 1)
                            #once the recursion is exited, the value that was changed and tested is returned to a blank
                            board_state[i][j] = -1
                            #the board's integer array is reinitialized to the restored board state
                            self.board._board = board_state
                        if not maximizer and chosen_utility != -1:
                            current_utility = self.minimax(
                                self.get_appended_board_state(
                                    board_state, 1, i, j), not maximizer,
                                depth + 1)
                            board_state[i][j] = -1
                            self.board._board = board_state
                    else:
                        #again, duplicates the functionality of the loop for the maximizer and minimizer
                        if maximizer and chosen_utility != 1:
                            current_utility = self.minimax(
                                self.get_appended_board_state(
                                    board_state, 1, i, j), not maximizer,
                                depth + 1)
                            board_state[i][j] = -1
                            self.board._board = board_state
                        if not maximizer and chosen_utility != -1:
                            current_utility = self.minimax(
                                self.get_appended_board_state(
                                    board_state, 0, i, j), not maximizer,
                                depth + 1)
                            board_state[i][j] = -1
                            self.board._board = board_state

                    #this code block controls the algorithm's decisionmaking; in the case of the maximizer, each utility is compared to the current best and the
                    #greater of the two is stored; the minimizer does the opposite, storing the lowest utility
                    if current_utility is not None:
                        if maximizer:
                            if chosen_utility is None or current_utility > chosen_utility:
                                chosen_utility = current_utility
                        else:
                            if chosen_utility is None or current_utility < chosen_utility:
                                chosen_utility = current_utility

        #when each non-leaf recursive call is complete, the chosen utility is returned instead of a raw value
        return chosen_utility

    def next_move(self, given_board):
        #initializes the state space, the board size, and the k-value
        self.state_space = 0
        self.board._k = given_board._k
        self.board._size = given_board._size

        #initializes the local variables for the best i and j, the chosen utility, and the depth
        best_move_i = -1
        best_move_j = -1
        chosen = -100

        #the player making a move should maximize utility, so they begin as the maximizer
        maximizer = True

        #sets the depth equal to the number of occupied squares by decrementing from a full board of size^2 based on how
        #many empty squares there are
        depth = given_board.size**2
        for i in range(given_board.size):
            for j in range(given_board.size):
                if given_board.cell(i, j) == CellState.EMPTY:
                    depth -= 1

        #this code block duplicates the function of the main loop in the recursion (but with only the maximizer accounted for)
        #this serves as the preliminary step to start off the recursion
        for i in range(given_board.size):
            for j in range(given_board.size):
                if given_board.cell(i, j) == CellState.EMPTY:
                    if self._player == Player.X:
                        current = self.minimax(
                            self.get_appended_board_state(
                                deepcopy(given_board._board), 0, i, j),
                            not maximizer, depth + 1)
                    else:
                        current = self.minimax(
                            self.get_appended_board_state(
                                deepcopy(given_board._board), 1, i, j),
                            not maximizer, depth + 1)
                    if current is not None:
                        #keeps track not only of the best utility, but of the coordinates where it was found
                        if current > chosen:
                            chosen = current
                            best_move_i = i
                            best_move_j = j
        #prints the state space after each move
        print("State space traversed contained " + str(self.state_space) +
              " states")
        #returns the best move
        return Move(self._player, best_move_i, best_move_j)
Пример #23
0
        def recurse(p):
            """
            make new board for branch
            :param p: BSTNode
            :return: None
            """
            if p is not None and p.data.check_win() is None:
                new_board = Board()
                for i in range(3):
                    for j in range(3):
                        new_board.add_value(i, j,
                                            p.data._game_board[i, j])
                move1_x = random.randint(0, 2)
                move1_y = random.randint(0, 2)
                move2_x = random.randint(0, 2)
                move2_y = random.randint(0, 2)

                while not new_board.is_good_move(move1_x, move1_y):
                    move1_x = random.randint(0, 2)
                    move1_y = random.randint(0, 2)
                new_board.second_player_move(move1_x, move1_y)

                if new_board.check_win() is None:
                    while not new_board.is_good_move(move2_x,
                                                     move2_y) or (
                            move1_x == move2_x and move1_y == move2_y):
                        move2_x = random.randint(0, 2)
                        move2_y = random.randint(0, 2)
                    new_board.first_player_move(move2_x, move2_y)

                self._builded_tree._add_right(p, new_board)
                recurse(self._builded_tree.super_find(new_board))

                if new_board.check_win() is None:
                    for i in range(3):
                        for j in range(3):
                            new_board.add_value(i, j,
                                                p.data._game_board[i, j])

                    move1_x = random.randint(0, 2)
                    move1_y = random.randint(0, 2)
                    move2_x = random.randint(0, 2)
                    move2_y = random.randint(0, 2)
                    while not new_board.is_good_move(move1_x, move1_y):
                        move1_x = random.randint(0, 2)
                        move1_y = random.randint(0, 2)

                    new_board.second_player_move(move1_x, move1_y)
                    if new_board.check_win() is None:
                        while not new_board.is_good_move(move2_x,
                                                         move2_y) or (
                                move1_x == move2_x and move1_y == move2_y):
                            move2_x = random.randint(0, 2)
                            move2_y = random.randint(0, 2)
                        new_board.first_player_move(move2_x, move2_y)

                    self._builded_tree._add_left(p, new_board)
                    recurse(self._builded_tree.super_find(new_board))
            return None
    def play_to_train(self, Vo, Vx, n_iterations=10000, initial_player=Board.x_symbol):
        '''
        Train
        :param Vo: the value functions of player 'o' (is a dictionary).
                    Example: Vo[1000010000] = 0.35,
                    where 1000010000 is the id of the state,
                    0.35 is the value function of the state 1000010000.
        :param Vx: the value functions of player 'x' (is a dictionary)
        :param n_iterations: the number of times we play
        :return:
        '''
        assert (initial_player == Board.x_symbol or initial_player == Board.o_symbol)
        assert (len(Vx) == len(Vo))
        assert (n_iterations > 0)

        current_turn = initial_player

        for iteration in range(n_iterations):
            if iteration % 1000 == 0:
                print(f'iteration = {iteration}')

            b = Board()
            board = b.board

            current_Vx = []
            current_Vo = []
            current_id_states = []

            draw = False
            game_over = False

            while not draw and not game_over:
                # print('++++++++++++++++++++++++++++++')

                # retrieve all empty cells
                empty_cells = []
                for i in range(b.height):
                    for j in range(b.width):
                        if board[i, j] == 0:
                            empty_cells.append([i, j])
                # print(f'Empty cells = {empty_cells}')

                # just choose one empty cell to play
                if len(empty_cells) > 0:
                    played_cell = np.random.choice(len(empty_cells))
                    board[empty_cells[played_cell][0], empty_cells[played_cell][1]] = b.convert_turn_symbol2id(
                        current_turn)
                    # print(f'Play {current_turn} on {empty_cells[played_cell]}')

                    # update states
                    state = b.get_state()
                    current_id_states.append(state)

                    current_Vx.append(self.AVERAGE_REWARD)
                    current_Vo.append(self.AVERAGE_REWARD)

                    game_over = b.is_game_over()
                    # print(f'Over: {over}')
                    # print(f'Winner: {b.winner}')
                    # print(f'State id: {b.get_state()}')

                    # update turn
                    if current_turn == Board.x_symbol:
                        current_turn = Board.o_symbol
                    else:
                        current_turn = Board.x_symbol
                else:
                    draw = True

                # b.draw()

            # update the value function of states
            if game_over:
                winner = b.get_winner()

                if winner == Board.x_symbol:
                    current_Vx[-1] = self.HIGHEST_REWARD
                    current_Vo[-1] = self.LOWEST_REWARD
                elif winner == Board.o_symbol:
                    current_Vx[-1] = self.LOWEST_REWARD
                    current_Vo[-1] = self.HIGHEST_REWARD

                Vx = self.update_value_function(Vx, current_id_states, current_Vx)
                Vo = self.update_value_function(Vo, current_id_states, current_Vo)

            else:
                # print('Draw')
                pass

            # change the turn in the next play
            # 50% the game starts with the player 1
            # 50% the game starts with the player 2
            if current_turn == Board.x_symbol:
                current_turn = Board.o_symbol
            else:
                current_turn = Board.x_symbol
Пример #25
0
# Author: Kyle Olsen <*****@*****.**>

from __future__ import print_function, absolute_import
from tic_tac_toe.board import Board

if __name__ == '__main__':
    game = Board()

    current_player = 1
    err_msg = None
    while True:
        game.display()

        # Figure out who the current player is and gather input
        mark = 'X'
        if current_player == 2:
            mark = 'O'
        if err_msg is not None:
            print(err_msg)
            err_msg = None
        try:
            row = int(raw_input('Player {} ({}s), select a row: '.format(current_player, mark)))
            cell = int(raw_input('Player {} ({}s), select a cell: '.format(current_player, mark)))
        except ValueError:
            err_msg = 'Row and Cell must be integers'
            continue

        # Try to mark the cell the player has chosen
        try:
            game.mark_cell(row, cell, mark)
        except IndexError:
Пример #26
0
def test_board_raises_error_if_index_not_on_board():
    new_board = Board()
    player = Player(token=["X", "O"])

    with pytest.raises(InvalidBoardIndexError):
        new_board.turn(9, player)
Пример #27
0
 def __init__(self):
     self._board = Board()
class AlphaBetaAgent(Agent):
    board = Board()
    state_space = 0

    def get_appended_board_state(self, board_state, cell_value, i, j):
        board_state[i][j] = cell_value
        return board_state
    
    #minimax algorithm for pruning, taking the same parameters as the brute force algorithm but this time with alpha and beta
    def minimax(self, board_state, maximizer, depth, alpha, beta):
        self.state_space += 1
        self.board._board = board_state

        current_utility = None
        chosen_utility = None

        #static evaluations
        winner = None
        if depth > self.board._k - 1:
            winner = self.board.winner
        if self._player == Player.X:
            if winner == Player.X:
                return 1 / depth
            if winner == Player.O:
                return -1 / depth
        else:
            if winner == Player.O:
                return 1 / depth
            if winner == Player.X:
                return -1 / depth
        if depth == self.board.size ** 2:
            return 0

        #main recursion block
        for i in range(self.board.size):
            for j in range(self.board.size):
                if self.board.cell(i, j) == CellState.EMPTY:
                    if self._player == Player.X:
                        #in any case where alpha < beta, the recursion will not be entered; this is because if the current greatest choice for the maximizer is
                        #less than the current least choice for the minimizer, there is no other step that can be taken by either player to prevent the outcome 
                        #of the current branch, so the rest of the branch can be pruned
                        if maximizer and chosen_utility != 1 and alpha < beta:
                            current_utility = self.minimax(self.get_appended_board_state(board_state, 0, i, j), not maximizer, depth+1, alpha, beta)
                            board_state[i][j] = -1
                            self.board._board = board_state
                            #in the case of the maximizer, alpha is stored as the current greatest choice
                            if current_utility > alpha:
                                alpha = current_utility
                        if not maximizer and chosen_utility != -1 and alpha < beta:
                            current_utility = self.minimax(self.get_appended_board_state(board_state, 1, i, j), not maximizer, depth+1, alpha, beta)
                            board_state[i][j] = -1
                            self.board._board = board_state
                            #in the case of the minimizer, beta is stored as the current least choice
                            if current_utility < beta:
                                beta = current_utility
                    else:
                        if maximizer and chosen_utility != 1 and alpha < beta:
                            current_utility = self.minimax(self.get_appended_board_state(board_state, 1, i, j), not maximizer, depth+1, alpha, beta)
                            board_state[i][j] = -1
                            self.board._board = board_state
                            if current_utility > alpha:
                                alpha = current_utility
                        if not maximizer and chosen_utility != -1 and alpha < beta:
                            current_utility = self.minimax(self.get_appended_board_state(board_state, 0, i, j), not maximizer, depth+1, alpha, beta)
                            board_state[i][j] = -1
                            self.board._board = board_state
                            if current_utility < beta:
                                beta = current_utility

                    if current_utility is not None:
                        if maximizer:
                            if chosen_utility is None or current_utility > chosen_utility:
                                chosen_utility = current_utility
                        else:
                            if chosen_utility is None or current_utility < chosen_utility:
                                chosen_utility = current_utility
        return chosen_utility
        
       
        

    def next_move(self, given_board):
        self.state_space = 0
        self.board._k = given_board._k
        self.board._size = given_board._size

        best_move_i = -1
        best_move_j = -1
        maximum = -100
        depth = given_board.size ** 2

        #alpha and beta are initialized to negative and positive infinity
        alpha = float("-inf")
        beta = float("inf")

        maximizer = True

        for i in range(given_board.size):
            for j in range(given_board.size):
                if given_board.cell(i, j) == CellState.EMPTY:
                    depth -= 1

        for i in range(given_board.size):
            for j in range(given_board.size):
                if given_board.cell(i, j) == CellState.EMPTY:
                    if self._player == Player.X:
                        #alpha and beta are passed into minimax
                        current = self.minimax(self.get_appended_board_state(deepcopy(given_board._board), 0, i, j), not maximizer, depth+1, alpha, beta)
                    else:
                        #alpha and beta are passed into minimax
                        current = self.minimax(self.get_appended_board_state(deepcopy(given_board._board), 1, i, j), not maximizer, depth+1, alpha, beta)
                    if current is not None:
                        if current > maximum:
                            maximum = current
                            best_move_i = i
                            best_move_j = j
        print("State space traversed contained " + str(self.state_space) + " states")
        #the best move is returned
        return Move(self._player, best_move_i, best_move_j)
Пример #29
0
def test_tic_tac_toe_initialized_with_a_3_x_3_board():
    new_board = Board()

    assert len(new_board.board) == 9
Пример #30
0
class Game:
    """
    represent game in tic tac toe
    """
    def __init__(self):
        self._board = Board()

    def _build_tree(self):
        """
        build tree with random move for computer
        :return: None
        """

        def recurse(p):
            """
            make new board for branch
            :param p: BSTNode
            :return: None
            """
            if p is not None and p.data.check_win() is None:
                new_board = Board()
                for i in range(3):
                    for j in range(3):
                        new_board.add_value(i, j,
                                            p.data._game_board[i, j])
                move1_x = random.randint(0, 2)
                move1_y = random.randint(0, 2)
                move2_x = random.randint(0, 2)
                move2_y = random.randint(0, 2)

                while not new_board.is_good_move(move1_x, move1_y):
                    move1_x = random.randint(0, 2)
                    move1_y = random.randint(0, 2)
                new_board.second_player_move(move1_x, move1_y)

                if new_board.check_win() is None:
                    while not new_board.is_good_move(move2_x,
                                                     move2_y) or (
                            move1_x == move2_x and move1_y == move2_y):
                        move2_x = random.randint(0, 2)
                        move2_y = random.randint(0, 2)
                    new_board.first_player_move(move2_x, move2_y)

                self._builded_tree._add_right(p, new_board)
                recurse(self._builded_tree.super_find(new_board))

                if new_board.check_win() is None:
                    for i in range(3):
                        for j in range(3):
                            new_board.add_value(i, j,
                                                p.data._game_board[i, j])

                    move1_x = random.randint(0, 2)
                    move1_y = random.randint(0, 2)
                    move2_x = random.randint(0, 2)
                    move2_y = random.randint(0, 2)
                    while not new_board.is_good_move(move1_x, move1_y):
                        move1_x = random.randint(0, 2)
                        move1_y = random.randint(0, 2)

                    new_board.second_player_move(move1_x, move1_y)
                    if new_board.check_win() is None:
                        while not new_board.is_good_move(move2_x,
                                                         move2_y) or (
                                move1_x == move2_x and move1_y == move2_y):
                            move2_x = random.randint(0, 2)
                            move2_y = random.randint(0, 2)
                        new_board.first_player_move(move2_x, move2_y)

                    self._builded_tree._add_left(p, new_board)
                    recurse(self._builded_tree.super_find(new_board))
            return None

        self._builded_tree = LinkedBST()
        self._builded_tree.add(self._board)
        recurse(self._builded_tree.find(self._board))

    def search_max(self):
        """
        calculate which move computer is better
        :return: None
        """
        def recurse(item):
            """
            calculate how many points have branch
            :param item: BSTNode
            :return: int
            """
            if item is None:
                return 0
            if item.data.check_win() is not None and item.right is None and item.left is None:
                if item.data.check_win() == "draw":
                    return 0
                elif item.data.check_win()[1] == "first player win":
                    return -1
                else:
                    return 1
            else:
                try:
                    item.right
                    try:
                        item.left
                        return recurse(item.right) + recurse(item.left)
                    except:
                        return recurse(item.right)
                except:
                    try:
                        item.left
                        return recurse(item.left)
                    except:
                        return 0

        item = self._builded_tree._root
        left_item = item.left
        rigth_item = item.right
        print(recurse(left_item), recurse(rigth_item))
        if recurse(left_item) >= recurse(rigth_item):
            return "left"
        else:
            return "right"

    def move_computer(self):
        """
        generate computer move
        :return: None
        """
        self._build_tree()
        max = self.search_max()
        if max == "left" and self._builded_tree._root.left is not None:
            self._board = self._builded_tree._root.left.data
            row = self._builded_tree._root.left.data._last_move[0]
            col = self._builded_tree._root.left.data._last_move[1]
            if self._board._game_board[row, col] == "x":
                self._board.add_value(row, col, None)
        elif self._builded_tree._root.right is not None:
            self._board = self._builded_tree._root.right.data
            row = self._builded_tree._root.right.data._last_move[0]
            col = self._builded_tree._root.right.data._last_move[1]
            if self._board._game_board[row, col] == "x":
                self._board.add_value(row, col, None)

    def run(self):
        """
        run game
        :return: None
        """
        def check_win():
            """
            check if someone win
            :return: None
            """
            if self._board.check_win() is not None:
                if self._board.check_win() == "draw":
                    print("Draw!")
                elif self._board.check_win()[1] == "first player win":
                    print("You win!")
                else:
                    print("You lose!")
                sys.exit()

        print("Hello!")
        print("Let`s play game/ You will be move first because if you move "
              "second you will lose")

        while not self._board.check_win():
            move1 = int(input("Input your row move: "))
            move2 = int(input("Input your col move: "))

            while not self._board.is_good_move(move1, move2):
                move1 = int(input("Reinput your row move: "))
                move2 = int(input("Reinput your col move: "))

            self._board.first_player_move(move1, move2)
            check_win()
            print("Your move\n", self._board)
            self.move_computer()
            print("Computer move\n", self._board)
            check_win()