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)
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"
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
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
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
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
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)
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)
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
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!"
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)
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')
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
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
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]: ")
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()
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'])
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}')
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)
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)
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
# 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:
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)
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)
def test_tic_tac_toe_initialized_with_a_3_x_3_board(): new_board = Board() assert len(new_board.board) == 9
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()