Advertisement
max2201111

gives 2 plies instead of 4

Mar 16th, 2024
1,029
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.94 KB | Science | 0 0
  1. import chess
  2.  
  3. def simplify_fen(fen):
  4.     """Simplifies a FEN string to include only position, turn, castling availability, and en passant target."""
  5.     return ' '.join(fen.split(' ')[:4])
  6.  
  7. def initialize_game_tree(initial_fen):
  8.     """Initializes the game tree with the root node based on the initial FEN."""
  9.     simplified_fen = simplify_fen(initial_fen)
  10.     game_tree = {1: {'fen': simplified_fen, 'parent': None, 'color': chess.WHITE if 'w' in initial_fen else chess.BLACK, 'children': [], 'moves_to_mate': None}}
  11.     fen_to_node_id = {simplified_fen: 1}
  12.     return game_tree, fen_to_node_id
  13.  
  14. def add_descendants_iteratively(game_tree, fen_to_node_id):
  15.     """Expands the game tree by iteratively adding legal move descendants of each game state."""
  16.     queue = [(1, 0)]
  17.     while queue:
  18.         node_id, _ = queue.pop(0)
  19.         board = chess.Board(game_tree[node_id]['fen'] + " 0 1")
  20.         for move in board.legal_moves:
  21.             board.push(move)
  22.             simplified_fen = simplify_fen(board.fen())
  23.             if simplified_fen not in fen_to_node_id:
  24.                 new_node_id = len(game_tree) + 1
  25.                 game_tree[new_node_id] = {'fen': simplified_fen, 'parent': node_id, 'color': chess.WHITE if board.turn else chess.BLACK, 'children': [], 'moves_to_mate': None}
  26.                 fen_to_node_id[simplified_fen] = new_node_id
  27.                 game_tree[node_id]['children'].append(new_node_id)
  28.                 queue.append((new_node_id, 0))
  29.             board.pop()
  30.  
  31. def update_game_outcomes(game_tree):
  32.     """Updates game outcomes focusing only on checkmates."""
  33.     for node_id, node in game_tree.items():
  34.         board = chess.Board(node['fen'] + " 0 1")
  35.         if board.is_checkmate():
  36.             node['result'] = 1 if board.turn == chess.BLACK else -1  # Black's turn but checkmate means White wins, and vice versa
  37.             node['moves_to_mate'] = 0  # Checkmate is immediate, no more moves required.
  38.         elif board.is_game_over():
  39.             node['result'] = 0  # For draws or stalemates, we consider the result as 0 (this will be ignored in propagation)
  40.            
  41.  
  42. # def update_parent_preferences(game_tree):
  43. #     def recurse(node_id):
  44. #         node = game_tree[node_id]
  45. #         # If a direct outcome is already determined at this node
  46. #         if 'result' in node:
  47. #             moves_to_mate = 0 if 'moves_to_mate' in node and node['result'] in [-1, 1] else None
  48. #             return node['result'], [node_id], moves_to_mate
  49.  
  50. #         # Initialize variables to track the best outcome
  51. #         best_result = 0  # Assume draw as default
  52. #         best_path = []
  53. #         best_moves_to_mate = None
  54.  
  55. #         for child_id in node['children']:
  56. #             child_result, child_path, child_moves_to_mate = recurse(child_id)
  57.  
  58. #             # Skip paths that don't lead to a decisive outcome
  59. #             if child_result == 0 or child_moves_to_mate is None:
  60. #                 continue
  61.  
  62. #             # Logic to select the optimal path based on the current node's perspective
  63. #             if best_moves_to_mate is None:
  64. #                 # First child with a decisive outcome sets the initial values
  65. #                 best_result, best_path, best_moves_to_mate = child_result, child_path, child_moves_to_mate
  66. #             else:
  67. #                 if node['color'] == chess.WHITE:
  68. #                     # White seeks to minimize moves to mate when winning
  69. #                     if child_result == 1 and child_moves_to_mate < best_moves_to_mate:
  70. #                         best_result, best_path, best_moves_to_mate = child_result, child_path, child_moves_to_mate
  71. #                 else:
  72. #                     # Black seeks to minimize moves to mate when winning
  73. #                     if child_result == -1 and child_moves_to_mate < best_moves_to_mate:
  74. #                         best_result, best_path, best_moves_to_mate = child_result, child_path, child_moves_to_mate
  75.  
  76. #         # Update the current node with the optimal outcome found
  77. #         if best_moves_to_mate is not None:
  78. #             node['result'] = best_result
  79. #             node['moves_to_mate'] = 1 + best_moves_to_mate  # Increment for the move to this node
  80. #         else:
  81. #             node['result'] = best_result  # Could be 0 if all children result in a draw
  82. #             node['moves_to_mate'] = None
  83.  
  84. #         return node['result'], [node_id] + best_path, node.get('moves_to_mate')
  85.  
  86. #     _, path, _ = recurse(1)  # Start the recursion from the root of the game tree
  87. #     return path
  88.  
  89. def update_parent_preferences(game_tree):
  90.     def recurse(node_id):
  91.         node = game_tree[node_id]
  92.         if 'result' in node:
  93.             # Node has a direct outcome (win, loss, or draw)
  94.             moves_to_mate = 0 if 'moves_to_mate' in node and node['result'] in [-1, 1] else None
  95.             return node['result'], [node_id], moves_to_mate
  96.  
  97.         best_result = None  # Track the best outcome (initially undefined)
  98.         best_path = []  # Best path leading to this outcome
  99.         best_moves_to_mate = float('inf')  # Use infinity as a comparison basis for finding the minimum
  100.  
  101.         for child_id in node['children']:
  102.             child_result, child_path, child_moves_to_mate = recurse(child_id)
  103.  
  104.             # Skip draws or paths not leading to a decisive outcome
  105.             if child_result == 0 or child_moves_to_mate is None:
  106.                 continue
  107.  
  108.             # Identify and select the best outcome for the current player
  109.             if best_result is None or (child_result == -1 and node['color'] == chess.WHITE and child_moves_to_mate < best_moves_to_mate):
  110.                 # For White, a result of -1 (Black win) with fewer moves is worse, so it's avoided unless it's the only outcome
  111.                 best_result, best_path, best_moves_to_mate = child_result, child_path, child_moves_to_mate
  112.             elif child_result == 1 and node['color'] == chess.BLACK and child_moves_to_mate < best_moves_to_mate:
  113.                 # For Black, similar logic applies but reversed
  114.                 best_result, best_path, best_moves_to_mate = child_result, child_path, child_moves_to_mate
  115.  
  116.         # If a winning path was found, update the node
  117.         if best_result in [-1, 1]:
  118.             node['result'] = best_result
  119.             node['moves_to_mate'] = best_moves_to_mate + 1  # Adjust for the current move
  120.         else:
  121.             # No winning path found, consider it a draw or maintain undefined result
  122.             node['result'] = 0 if best_result is None else best_result
  123.             node['moves_to_mate'] = None
  124.  
  125.         return node['result'], [node_id] + best_path, node.get('moves_to_mate')
  126.  
  127.     _, path, _ = recurse(1)  # Starting from the root of the game tree
  128.     return path
  129.  
  130.  
  131.  
  132. # This function assumes that 'game_tree' is a dictionary representing the nodes of your game tree,
  133. # where each node ID maps to a dictionary containing:
  134. # 'fen': The FEN string of the board position,
  135. # 'parent': The parent node ID,
  136. # 'color': The color to move (True for White, False for Black),
  137. # 'children': A list of child node IDs,
  138. # 'result': The game outcome from this position (-1 for Black win, 1 for White win, 0 for draw),
  139. # 'moves_to_mate': The shortest number of moves to mate from this position (if applicable).
  140.  
  141. # To execute this code, you'll need to define your 'game_tree' variable with the initial game state and
  142. # have the chess positions added to the tree using the 'add_descendants_iteratively' function you've defined.
  143.  
  144.            
  145.            
  146. # def update_parent_preferences(game_tree):
  147. #     def recurse(node_id):
  148. #         node = game_tree[node_id]
  149. #         if 'result' in node:
  150. #             # Direct outcome detected, set moves_to_mate accordingly
  151. #             moves_to_mate = 0 if 'moves_to_mate' in node and node['result'] in [-1, 1] else None
  152. #             return node['result'], [node_id], moves_to_mate
  153.  
  154. #         best_result = 0  # Default to draw
  155. #         best_path = []
  156. #         best_moves_to_mate = float('inf')  # Initialize with a large number for comparison
  157.  
  158. #         for child_id in node['children']:
  159. #             child_result, child_path, child_moves_to_mate = recurse(child_id)
  160.            
  161. #             if child_result == 0 or child_moves_to_mate is None:
  162. #                 continue  # Skip non-result or draw paths
  163.  
  164. #             # Logic for selecting the shortest path to victory
  165. #             if ((node['color'] == chess.WHITE and child_result == 1) or
  166. #                 (node['color'] == chess.BLACK and child_result == -1)) and child_moves_to_mate < best_moves_to_mate:
  167. #                 best_result, best_path, best_moves_to_mate = child_result, child_path, child_moves_to_mate
  168.  
  169. #         if best_moves_to_mate != float('inf'):
  170. #             node['result'] = best_result
  171. #             node['moves_to_mate'] = best_moves_to_mate + 1  # Correctly increment for the move to this node
  172. #         else:
  173. #             node['result'] = best_result  # Draw if no better path found
  174. #             node['moves_to_mate'] = None  # No valid path to victory
  175.  
  176. #         return node['result'], [node_id] + best_path, node.get('moves_to_mate')
  177.  
  178. #     result, path, moves_to_mate = recurse(1)  # Assuming 1 is the root node's ID
  179. #     return path
  180.            
  181.            
  182. # def update_parent_preferences(game_tree):
  183. #     def recurse(node_id):
  184. #         node = game_tree[node_id]
  185. #         if 'result' in node:  # Check if the node has a direct outcome
  186. #             return node['result'], [node_id], 0 if 'moves_to_mate' in node else None
  187.  
  188. #         best_result = 0  # Assume draw as the default outcome
  189. #         best_path = []
  190. #         best_moves_to_mate = None
  191.  
  192. #         for child_id in node['children']:
  193. #             child_result, child_path, child_moves_to_mate = recurse(child_id)
  194.  
  195. #             if child_result == 0 or child_moves_to_mate is None:  # Skip draws or paths not leading to checkmate
  196. #                 continue
  197.  
  198. #             # Ensure we have a valid best_moves_to_mate for comparison
  199. #             if best_moves_to_mate is None:
  200. #                 best_moves_to_mate = child_moves_to_mate
  201. #                 best_result, best_path = child_result, child_path
  202. #             else:
  203. #                 # Compare only if child_moves_to_mate is not None and update accordingly
  204. #                 if node['color'] == chess.WHITE and child_result == 1:
  205. #                     if child_moves_to_mate < best_moves_to_mate:
  206. #                         best_result, best_path, best_moves_to_mate = child_result, child_path, child_moves_to_mate
  207. #                 elif node['color'] == chess.BLACK and child_result == -1:
  208. #                     if child_moves_to_mate > best_moves_to_mate:
  209. #                         best_result, best_path, best_moves_to_mate = child_result, child_path, child_moves_to_mate
  210.  
  211. #         if best_moves_to_mate is not None:
  212. #             node['result'] = best_result
  213. #             node['moves_to_mate'] = 1 + best_moves_to_mate
  214. #         else:
  215. #             node['result'] = best_result  # could still be 0 if no child paths lead to a win
  216. #             node['moves_to_mate'] = None
  217.  
  218. #         return node['result'], [node_id] + best_path, node.get('moves_to_mate')
  219.  
  220. #     result, path, moves_to_mate = recurse(1)  # Start the recursion from the root node.
  221. #     return path
  222.  
  223.  
  224. # Make sure to replace or integrate this function into your main execution logic and re-run your analysis.
  225.  
  226. # def update_parent_preferences(game_tree):
  227. #     def recurse(node_id):
  228. #         node = game_tree[node_id]
  229. #         if 'result' in node:
  230. #             moves_to_mate = 0 if 'moves_to_mate' in node and node['result'] in [-1, 1] else None
  231. #             return node['result'], [node_id], moves_to_mate
  232.  
  233. #         best_result = 0  # Default outcome
  234. #         best_path = []
  235. #         best_moves_to_mate = float('inf')  # Use infinity as the initial comparison value
  236.  
  237. #         for child_id in node['children']:
  238. #             child_result, child_path, child_moves_to_mate = recurse(child_id)
  239.  
  240. #             if child_result == 0 or child_moves_to_mate is None:
  241. #                 continue  # Skip non-result paths
  242.  
  243. #             # Looking for the shortest path to checkmate for both colors
  244. #             if (child_result == 1 and node['color'] == chess.WHITE) or (child_result == -1 and node['color'] == chess.BLACK):
  245. #                 if child_moves_to_mate < best_moves_to_mate:
  246. #                     best_result, best_path, best_moves_to_mate = child_result, child_path, child_moves_to_mate
  247.  
  248. #         if best_moves_to_mate != float('inf'):
  249. #             node['result'] = best_result
  250. #             node['moves_to_mate'] = 1 + best_moves_to_mate  # Incrementing for the current move
  251. #         else:
  252. #             node['result'] = 0  # Draw or no path to checkmate found
  253. #             node['moves_to_mate'] = None
  254.  
  255. #         return node['result'], [node_id] + best_path, node.get('moves_to_mate')
  256.  
  257. #     _, path, _ = recurse(1)
  258. #     return path
  259.  
  260.  
  261. def print_path(game_tree, path):
  262.     """Prints the board positions along the path."""
  263.     for node_id in path:
  264.         node = game_tree[node_id]
  265.         board = chess.Board(node['fen'] + " 0 1")
  266.         moves_to_mate = "N/A" if node.get('moves_to_mate') is None else node.get('moves_to_mate')
  267.         print(f"Node ID: {node_id}, Result: {node.get('result', 'N/A')}, Moves to Mate: {moves_to_mate}")
  268.         print(board,node,"<<\n")
  269.         print("---")
  270.  
  271. def main():
  272.     initial_fen = "8/8/8/3k4/8/8/2K2Q2/8 w - - 0 1"  # Example FEN
  273.     initial_fen = "8/8/8/3k4/8/2K5/5q2/8 w - - 0 1"
  274.     initial_fen = "8/8/8/3k4/1K6/8/5q2/8 b - - 0 1"
  275.     initial_fen = "5K2/q7/6k1/8/8/8/8/8 w - - 0 1"
  276.   #  initial_fen = "6K1/q7/6k1/8/8/8/8/8 b - - 0 1"
  277.  
  278.     game_tree, fen_to_node_id = initialize_game_tree(initial_fen)
  279.     add_descendants_iteratively(game_tree, fen_to_node_id)
  280.     update_game_outcomes(game_tree)
  281.     path = update_parent_preferences(game_tree)
  282.     print(game_tree[1])
  283.     print("Path to the outcome:")
  284.     print_path(game_tree, path)
  285.  
  286. if __name__ == "__main__":
  287.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement