def simulation(board, screen, clock, show): # Get the legal moves from current board state legal_moves = board.get_legal_moves() # Check if the game ended if board.checkmate or board.stalemate: # Return the correct result in a number if board.checkmate and board.white_move: print("Simulated Win Black") return -1 elif board.checkmate and not board.white_move: print("Simulated Win White") return 1 else: print("Simulated Draw") return 0 else: # If not the simulation continues # Pick a random legal move random_move = find_random_move(legal_moves) # Check if something went wrong if random_move is None: raise Exception("Random move is None") # Make the move board.make_move(random_move) # Check if the move should be displayed if show: # Display the board based on the state, selected position and highlighted squares display_board(board, screen, (), []) # Pygame refresh p.display.flip() clock.tick(30) # Recursion until the game ends return simulation(board, screen, clock, show)
def train_monte_carlo_tree(board, screen, clock, show=False): # Prepare the board and the images if the training games should be shown if show: load_images() # Display the board based on the state, selected position and highlighted squares display_board(board, screen, (), []) # Pygame refresh p.display.flip() clock.tick(30) # Number of iterations of the training training_cycles = 5000 # Saving rate (How often the file should be saved saving_rate = 50 # Iteration counter (for debug purposes) counter = 1 # Iterate through the saving iterations for i in range(int(training_cycles / saving_rate)): # Open the file with open("mcts1.json", "r") as file: # Load the tree tree = json.load(file) # Iterate through training for j in range(saving_rate): # Select the best node (based on ucb value) node = selection(tree["start"], board, screen, clock, show) print("Selection completed") # Get the new expanded child child_index = expansion(node, board) print("Expansion completed") new_node = node["children"][child_index] # Simulate and get the result of the game result = simulation(board, screen, clock, show) print("Simulation completed") # Update the parent values and win rates backpropagation(result, tree["start"], new_node) print("Backpropagation completed") # Reset the board board.reset_board() # Update the counter print(str(counter) + "/" + str(training_cycles)) counter += 1 # Save the file with open("mcts1.json", "w") as file: json.dump(tree, file, indent=8) print("SAVED") # DEBUG the first moves and their visits most_explored = float("-inf") highest_win_rate = float("-inf") move_with_best_win_rate = None for child in tree["start"]["children"]: if child["visits"] > most_explored: most_explored = child["visits"] if (child["win"] / child["visits"]) > highest_win_rate: highest_win_rate = (child["win"] / child["visits"]) move_with_best_win_rate = child print(str(child["move_history"]) + ": " + str(child["visits"])) print("most explored node was visited: " + str(most_explored) + " times") print("Highest win rate is " + str(highest_win_rate) + " at move " + str(move_with_best_win_rate["move_history"]))
def selection(node, board, screen, clock, show): # Get the legal moves in current game state legal_moves = board.get_legal_moves() # Check if the node is not the first (there would not be any move to make) if len(node["move_history"]) != 0: # Get the move of the node move = notation_list_to_moves(node["move_history"])[-1] # Iterate through the legal moves for legal_move in legal_moves: # Check if the move is a legal move if move == legal_move: print("made move " + str(move_to_notation(legal_move))) # The legal move is made, because it has extra properties (e.g. pawn promotion or castling) # while the move converted from notation is a simple move without special booleans board.make_move(legal_move) # Check if the move should be displayed if show: # Display the board based on the state, selected position and highlighted squares display_board(board, screen, (), []) # Pygame refresh p.display.flip() clock.tick(30) # Get new legal moves (the state changed) legal_moves = board.get_legal_moves() # Check if the current node has every possible child => if not then we stop the selection and expand if len(node["children"]) < len(legal_moves): print("Legal moves: " + str([move_to_notation(move) for move in legal_moves])) print("Length of children: " + str(len(node["children"]))) print("Found something unexplored") return node # Get the child with the best ucb # Initially the max ucb is -infinity so there will be a node which is higher max_ucb = float("-inf") # Keeps track of the best child best_child = None # Iterate through all the children of the current node for child in node["children"]: # Get the ucb value of the current child current_ucb = ucb_val(child) # Check if there is a new best child if current_ucb > max_ucb: # If so, update the max ucb and the best child max_ucb = current_ucb best_child = child # Recursion until the case above return selection(best_child, board, screen, clock, show)
def test_display_shows_all_fields(self): with patch('sys.stdout', new=StringIO()) as fake_out: MainClass.display_board() self.assertEqual(fake_out.getvalue(), "1")
# return static_evaluation(board) # board for testing double capture scenarios test_board1 = [[0 for _ in range(8)] for _ in range(8)] test_board1[0][7] = Piece((7, 0), False) test_board1[1][2] = Piece((2, 1), False) test_board1[1][6] = Piece((6, 1), False) test_board1[2][1] = Piece((1, 2)) test_board1[2][5] = Piece((5, 2)) test_board1[4][5] = Piece((5, 4)) test_board1[2][3] = Piece((3, 2)) test_board1[4][3] = Piece((3, 4)) test_board1[6][3] = Piece((3, 6)) display_board(test_board1) def piece_recursive_moves(board, piece): moves = piece.potential_moves(board) print(moves) # Base case - piece can make no moves or only non-capturing moves if moves == None: return [] # Else if only non-capturing moves can be made return these elif moves[0] == False: return moves # Otherwise simulate capturing move for each possible capture for move in moves[1]: print(move) x, y = piece.x, piece.y