Advertisement
max2201111

almost good optimal play 11

Feb 29th, 2024
623
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.51 KB | Science | 0 0
  1. import chess
  2.  
  3. def simplify_fen(fen):
  4.     """Simplifies a FEN string by keeping only the position, turn, castling availability, and en passant target square."""
  5.     return ' '.join(fen.split(' ')[:4])
  6.  
  7. def add_descendants_iteratively(A, fen_to_node_id):
  8.     queue = [(1, 0)]
  9.     while queue:
  10.         node_id, depth = queue.pop(0)
  11.         board = chess.Board(A[node_id]['fen'] + " 0 1")
  12.         for move in board.legal_moves:
  13.             if move.promotion:
  14.                 move = chess.Move(move.from_square, move.to_square, promotion=chess.QUEEN)
  15.             board.push(move)
  16.             simplified_fen = simplify_fen(board.fen())
  17.             if simplified_fen not in fen_to_node_id:
  18.                 new_node_id = len(A) + 1
  19.                 A[new_node_id] = {
  20.                     'fen': simplified_fen,
  21.                     'moves_to_mate': None,
  22.                     'parent': node_id,
  23.                     'color': chess.WHITE if simplified_fen.split()[1] == 'w' else chess.BLACK,
  24.                     'result': None,
  25.                     'processed': False,
  26.                     'sequence': [],
  27.                     'children': [],
  28.                     'to_end': None,
  29.                 }
  30.                 fen_to_node_id[simplified_fen] = new_node_id
  31.                 A[node_id]['children'].append(new_node_id)
  32.                 queue.append((new_node_id, depth + 1))
  33.             board.pop()
  34.  
  35. def initialize_game_tree(initial_fen):
  36.     simplified_fen = simplify_fen(initial_fen)
  37.     A = {1: {'fen': simplified_fen, 'moves_to_mate': None, 'parent': None,
  38.              'color': chess.WHITE if initial_fen.split()[1] == 'w' else chess.BLACK,
  39.              'result': None, 'processed': False, 'sequence': [], 'children': [], 'to_end': None}}
  40.     fen_to_node_id = {simplified_fen: 1}
  41.     return A, fen_to_node_id
  42.  
  43. def update_game_outcomes(A):
  44.     for key, node in A.items():
  45.         board = chess.Board(node['fen'] + " 0 1")
  46.         if board.is_game_over():
  47.             outcome = board.outcome()
  48.             node['processed'] = True
  49.             if outcome.termination == chess.Termination.CHECKMATE:
  50.                 node['result'] = 1 if outcome.winner == chess.WHITE else -1
  51.                 node['moves_to_mate'] = 0
  52.             else:
  53.                 node['result'] = 0
  54.                 node['moves_to_mate'] = None
  55.             node['to_end'] = 0
  56.  
  57. # def update_parent_preferences(node_id, A):
  58. #     node = A[node_id]
  59. #     if node['processed']:
  60. #         return node.get('to_end'), node.get('moves_to_mate'), node.get('result')
  61.  
  62. #     best_child_id = None
  63. #     # Initialize best_result with the current node result, ensuring it's an integer for comparison
  64. #     best_result = node['result'] if node['result'] is not None else -float('inf')
  65. #     best_path_length = float('inf')
  66.  
  67. #     for child_id in node['children']:
  68. #         child_to_end, child_moves_to_mate, child_result = update_parent_preferences(child_id, A)
  69. #         # Ensure child_result is comparable
  70. #         child_result = child_result if child_result is not None else -float('inf')
  71.  
  72. #         if child_to_end is not None:
  73. #             path_length = 1 + child_to_end
  74. #             if (child_result > best_result) or (child_result == best_result and path_length < best_path_length):
  75. #                 best_child_id = child_id
  76. #                 best_result = child_result
  77. #                 best_path_length = path_length
  78.  
  79. #     # After evaluating all children, update the node
  80. #     if best_child_id is not None:
  81. #         node['sequence'] = [best_child_id]
  82. #         node['to_end'] = best_path_length
  83. #         node['moves_to_mate'] = best_path_length if best_result in [1, -1] else None
  84. #         node['result'] = best_result
  85. #     else:
  86. #         # If no viable children, mark this node accordingly
  87. #         node['to_end'] = None if best_path_length == float('inf') else best_path_length
  88. #         node['moves_to_mate'] = None
  89. #         node['result'] = 0 if node['result'] is None else node['result']
  90.  
  91. #     node['processed'] = True
  92. #     return node.get('to_end'), node.get('moves_to_mate'), node.get('result')
  93.  
  94. # def update_parent_preferences(node_id, A):
  95. #     """
  96. #     Recursively updates parent node preferences based on the best child outcomes.
  97.  
  98. #     Args:
  99. #     - node_id: The ID of the current node in the game tree.
  100. #     - A: The game tree, a dictionary mapping node IDs to node properties.
  101.  
  102. #     The function updates the following properties for each node:
  103. #     - 'to_end': The number of moves to reach a determined game outcome.
  104. #     - 'moves_to_mate': The number of moves to mate from the current position, if applicable.
  105. #     - 'result': The game outcome from the current position (1 for White win, -1 for Black win, 0 for draw).
  106. #     - 'sequence': The list of child node IDs leading to the best game outcome.
  107. #     - 'processed': A flag indicating that the node has been processed.
  108. #     """
  109. #     node = A[node_id]
  110. #     # Base case: If the node is already processed, return its values
  111. #     if node['processed']:
  112. #         return node.get('to_end'), node.get('moves_to_mate'), node.get('result')
  113.  
  114. #     # Initialize variables to track the best child node and its outcomes
  115. #     best_child_id = None
  116. #     best_result = -float('inf') if node['color'] == chess.WHITE else float('inf')
  117. #     best_to_end = None
  118.  
  119. #     # Iterate over all children to find the best outcome
  120. #     for child_id in node['children']:
  121. #         child_to_end, child_moves_to_mate, child_result = update_parent_preferences(child_id, A)
  122.        
  123. #         # Determine if the current child node is preferable
  124. #         is_preferable = False
  125. #         if node['color'] == chess.WHITE:
  126. #             # White's move: Prefer higher results and shorter paths to outcome
  127. #             is_preferable = child_result > best_result or (child_result == best_result and (best_to_end is None or child_to_end < best_to_end))
  128. #         else:
  129. #             # Black's move: Prefer lower results and longer paths to delay outcome
  130. #             is_preferable = child_result < best_result or (child_result == best_result and child_to_end > best_to_end)
  131.        
  132. #         if is_preferable:
  133. #             best_child_id = child_id
  134. #             best_result = child_result
  135. #             best_to_end = child_to_end
  136.  
  137. #     # Update the current node based on the best child node found
  138. #     if best_child_id is not None:
  139. #         node['sequence'] = [best_child_id]  # Update or append to the sequence based on your design choice
  140. #         node['to_end'] = 1 + best_to_end if best_to_end is not None else None
  141. #         node['moves_to_mate'] = 1 + best_to_end if best_to_end is not None else None
  142. #         node['result'] = best_result
  143. #     else:
  144. #         # No preferable child found, or no children exist
  145. #         node['to_end'] = None
  146. #         node['moves_to_mate'] = None
  147. #         # The result remains as initialized if no children influence the outcome
  148.  
  149. #     node['processed'] = True
  150. #     return node.get('to_end'), node.get('moves_to_mate'), node.get('result')
  151.  
  152. # # Example usage:
  153. # # A = {1: {'fen': 'initial FEN here', 'children': [2, 3], 'color': chess.WHITE, 'processed': False, ...}}
  154. # # update_parent_preferences(1, A)
  155. # # print(A[1])
  156.  
  157.  
  158. def update_parent_preferences(node_id, A):
  159.     node = A[node_id]
  160.     # Return the current values if the node has already been processed
  161.     if node['processed']:
  162.         return node['to_end'], node['moves_to_mate'], node['result']
  163.  
  164.     best_child_id = None
  165.     # Initialize best_result with an appropriate value based on the color to play
  166.     best_result = float('-inf') if node['color'] else float('inf')
  167.     best_to_end = None
  168.  
  169.     for child_id in node['children']:
  170.         child_to_end, child_moves_to_mate, child_result = update_parent_preferences(child_id, A)
  171.        
  172.         # Ensure comparisons are valid by checking for None
  173.         if child_result is None:
  174.             continue  # Skip this child because it has no result, indicating it's not a terminal node or not evaluated yet
  175.  
  176.         # Handle the logic for updating the best choice based on the color to play
  177.         if node['color']:  # If it's White's turn to play
  178.             if child_result > best_result or (child_result == best_result and (best_to_end is None or (child_to_end is not None and child_to_end < best_to_end))):
  179.                 best_child_id = child_id
  180.                 best_result = child_result
  181.                 best_to_end = child_to_end
  182.         else:  # If it's Black's turn to play
  183.             if child_result < best_result or (child_result == best_result and (best_to_end is None or (child_to_end is not None and child_to_end > best_to_end))):
  184.                 best_child_id = child_id
  185.                 best_result = child_result
  186.                 best_to_end = child_to_end
  187.  
  188.     # Update the current node based on the best child node found
  189.     if best_child_id is not None:
  190.         node['sequence'] = [best_child_id]
  191.         node['result'] = best_result
  192.         node['to_end'] = 1 + (best_to_end if best_to_end is not None else 0)
  193.         node['moves_to_mate'] = None if node['result'] == 0 else 1 + (best_to_end if best_to_end is not None else 0)
  194.     else:
  195.         node['to_end'] = None
  196.         node['moves_to_mate'] = None
  197.  
  198.     node['processed'] = True
  199.     return node['to_end'], node['moves_to_mate'], node['result']
  200.  
  201.  
  202. # Note: This function assumes the presence of an evaluate_board function or similar logic
  203. # that sets the initial 'result' for leaf nodes where the game is over.
  204.  
  205.  
  206.  
  207.  
  208. def print_sequence_from_root(A):
  209.     current_node_id = 1
  210.     while True:
  211.         node = A[current_node_id]
  212.         board = chess.Board(node['fen'] + " 0 1")
  213.         print(f"Node ID: {current_node_id}, Moves to Mate: {node['moves_to_mate']}, Result: {node['result']}")
  214.         print(board, "\n")
  215.        
  216.         if not node['sequence']:
  217.             break
  218.         current_node_id = node['sequence'][0]
  219.  
  220. def main():
  221.     initial_fen = "7Q/8/8/6k1/2K5/8/8/8 w - - 0 1"
  222.     A, fen_to_node_id = initialize_game_tree(initial_fen)
  223.     add_descendants_iteratively(A, fen_to_node_id)
  224.     update_game_outcomes(A)
  225.     update_parent_preferences(1, A)
  226.     print("Final Output:")
  227.     print(A[1])
  228.     print_sequence_from_root(A)
  229.  
  230. #    for key in [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]:
  231.     for key in range(1,100):
  232.         if A[key]['to_end'] != None: # and A[key]['to_end'] > 9:
  233.             print(f"{key}:: {A[key]['to_end']} {A[key]}\n{chess.Board(A[key]['fen'])}<\n")
  234.  
  235.        
  236. if __name__ == "__main__":
  237.     main()
  238.  
  239.    
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement