Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Advertisement
max2201111

excellent 2

Apr 10th, 2025
351
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.63 KB | Science | 0 0
  1. import time
  2. import math
  3.  
  4. MATE_SCORE = 10000
  5. INF = 10000000
  6.  
  7. # Parse FEN string into board matrix and side to move
  8. def parse_fen(fen_str):
  9.     parts = fen_str.split()
  10.     rows = parts[0].split('/')
  11.     side_to_move = parts[1]
  12.     board = []
  13.     for rank in rows:
  14.         row = []
  15.         for ch in rank:
  16.             if ch.isdigit():
  17.                 row.extend(['.'] * int(ch))
  18.             else:
  19.                 row.append(ch)
  20.         board.append(row)
  21.     # Ensure 8 columns per rank
  22.     for i in range(len(board)):
  23.         if len(board[i]) < 8:
  24.             board[i].extend(['.'] * (8 - len(board[i])))
  25.     # Ensure 8 ranks
  26.     while len(board) < 8:
  27.         board.append(['.'] * 8)
  28.     return board, side_to_move
  29.  
  30. # Directions for moves of each piece type
  31. king_dirs   = [(-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)]
  32. rook_dirs   = [(-1,0), (1,0), (0,-1), (0,1)]
  33. bishop_dirs = [(-1,-1), (-1,1), (1,-1), (1,1)]
  34. knight_moves = [(-2,-1), (-2,1), (-1,-2), (-1,2), (1,-2), (1,2), (2,-1), (2,1)]
  35.  
  36. # Czech piece names
  37. piece_names = {
  38.     'p': "pěšec",
  39.     'r': "věž",
  40.     'n': "jezdec",
  41.     'b': "střelec",
  42.     'q': "dáma",
  43.     'k': "král",
  44.     'a': "amazonka",
  45.     'c': "kardinál",
  46.     'e': "eve"
  47. }
  48.  
  49. # Dictionary defining how each piece moves
  50. piece_moves = {
  51.     'p': {'dirs': [], 'sliding': False},                           # Pawn (special handling)
  52.     'r': {'dirs': rook_dirs, 'sliding': True},                     # Rook
  53.     'n': {'dirs': knight_moves, 'sliding': False},                 # Knight
  54.     'b': {'dirs': bishop_dirs, 'sliding': True},                   # Bishop
  55.     'q': {'dirs': rook_dirs + bishop_dirs, 'sliding': True},       # Queen
  56.     'k': {'dirs': king_dirs, 'sliding': False},                    # King
  57.     'a': {'dirs': rook_dirs + bishop_dirs + knight_moves,          # Amazonka (queen + knight)
  58.           'sliding': True, 'knight_like': True},
  59.     'c': {'dirs': rook_dirs + knight_moves,                        # Cardinal (rook + knight)
  60.           'sliding': True, 'knight_like': True},
  61.     'e': {'dirs': bishop_dirs + knight_moves,                      # Eve (bishop + knight)
  62.           'sliding': True, 'knight_like': True}
  63. }
  64.  
  65. # Generate all moves for the given side
  66. def generate_moves(board, side):
  67.     moves = []
  68.    
  69.     for r in range(8):
  70.         for c in range(8):
  71.             piece = board[r][c]
  72.             if piece == '.':
  73.                 continue
  74.                
  75.             # Skip pieces of the opposite side
  76.             if side == 'w' and not piece.isupper():
  77.                 continue
  78.             if side == 'b' and not piece.islower():
  79.                 continue
  80.                
  81.             piece_type = piece.lower()
  82.            
  83.             # Handle pawns specially
  84.             if piece_type == 'p':
  85.                 if side == 'w':
  86.                     # Move forward
  87.                     if r > 0 and board[r-1][c] == '.':
  88.                         moves.append((r, c, r-1, c))
  89.                         # Double move from starting position
  90.                         if r == 6 and board[r-2][c] == '.':
  91.                             moves.append((r, c, r-2, c))
  92.                     # Captures
  93.                     for dc in [-1, 1]:
  94.                         if 0 <= c+dc < 8 and r > 0:
  95.                             target = board[r-1][c+dc]
  96.                             if target != '.' and target.islower():
  97.                                 moves.append((r, c, r-1, c+dc))
  98.                 else:  # Black pawn
  99.                     # Move forward
  100.                     if r < 7 and board[r+1][c] == '.':
  101.                         moves.append((r, c, r+1, c))
  102.                         # Double move from starting position
  103.                         if r == 1 and board[r+2][c] == '.':
  104.                             moves.append((r, c, r+2, c))
  105.                     # Captures
  106.                     for dc in [-1, 1]:
  107.                         if 0 <= c+dc < 8 and r < 7:
  108.                             target = board[r+1][c+dc]
  109.                             if target != '.' and target.isupper():
  110.                                 moves.append((r, c, r+1, c+dc))
  111.             # Handle all other pieces
  112.             elif piece_type in piece_moves:
  113.                 movement = piece_moves[piece_type]
  114.                
  115.                 # Handle knight-like moves separately for special pieces
  116.                 if movement.get('knight_like', False):
  117.                     for dr, dc in knight_moves:
  118.                         nr, nc = r + dr, c + dc
  119.                         if 0 <= nr < 8 and 0 <= nc < 8:
  120.                             target = board[nr][nc]
  121.                             if target == '.' or (side == 'w' and target.islower()) or (side == 'b' and target.isupper()):
  122.                                 moves.append((r, c, nr, nc))
  123.                
  124.                 # Handle sliding or non-sliding moves
  125.                 dirs = movement['dirs']
  126.                 for dr, dc in dirs:
  127.                     # Skip knight moves which are handled separately above
  128.                     if movement.get('knight_like', False) and (abs(dr) == 2 or abs(dc) == 2):
  129.                         continue
  130.                        
  131.                     nr, nc = r + dr, c + dc
  132.                     # For non-sliding pieces, just check one step
  133.                     if not movement['sliding']:
  134.                         if 0 <= nr < 8 and 0 <= nc < 8:
  135.                             target = board[nr][nc]
  136.                             if target == '.' or (side == 'w' and target.islower()) or (side == 'b' and target.isupper()):
  137.                                 moves.append((r, c, nr, nc))
  138.                     # For sliding pieces, check the entire ray
  139.                     else:
  140.                         while 0 <= nr < 8 and 0 <= nc < 8:
  141.                             target = board[nr][nc]
  142.                             if target == '.':
  143.                                 moves.append((r, c, nr, nc))
  144.                             elif (side == 'w' and target.islower()) or (side == 'b' and target.isupper()):
  145.                                 moves.append((r, c, nr, nc))
  146.                                 break
  147.                             else:
  148.                                 break
  149.                             nr += dr
  150.                             nc += dc
  151.    
  152.     return moves
  153.  
  154. # Check if king is in check
  155. def is_in_check(board, side):
  156.     # Find the king
  157.     king_char = 'K' if side == 'w' else 'k'
  158.     king_pos = None
  159.    
  160.     for r in range(8):
  161.         for c in range(8):
  162.             if board[r][c] == king_char:
  163.                 king_pos = (r, c)
  164.                 break
  165.         if king_pos:
  166.             break
  167.            
  168.     if not king_pos:
  169.         return False  # No king found (shouldn't happen in normal chess)
  170.        
  171.     # Check if the king is attacked by any opponent piece
  172.     attacking_side = 'b' if side == 'w' else 'w'
  173.     opponent_moves = generate_moves(board, attacking_side)
  174.    
  175.     for move in opponent_moves:
  176.         _, _, tr, tc = move
  177.         if (tr, tc) == king_pos:
  178.             return True
  179.    
  180.     return False
  181.  
  182. # Get legal moves (not leaving king in check)
  183. def get_legal_moves(board, side):
  184.     moves = generate_moves(board, side)
  185.     legal_moves = []
  186.    
  187.     for move in moves:
  188.         fr, fc, tr, tc = move
  189.        
  190.         # Make the move on a copy of the board
  191.         board_copy = [row[:] for row in board]
  192.         board_copy[tr][tc] = board_copy[fr][fc]
  193.         board_copy[fr][fc] = '.'
  194.        
  195.         # Check if the move leaves the king in check
  196.         if not is_in_check(board_copy, side):
  197.             legal_moves.append(move)
  198.    
  199.     return legal_moves
  200.  
  201. # Apply a move to a board
  202. def make_move(board, move):
  203.     fr, fc, tr, tc = move
  204.     new_board = [row[:] for row in board]
  205.     new_board[tr][tc] = new_board[fr][fc]
  206.     new_board[fr][fc] = '.'
  207.     return new_board
  208.  
  209. # Print board in ASCII format
  210. def print_board(board):
  211.     print("  a b c d e f g h")
  212.     for r in range(8):
  213.         print(f"{8-r} {' '.join(board[r])} {8-r}")
  214.     print("  a b c d e f g h")
  215.  
  216. # Get move notation
  217. def get_move_notation(board, move):
  218.     fr, fc, tr, tc = move
  219.     piece = board[fr][fc]
  220.     piece_type = piece.lower()
  221.    
  222.     from_square = chr(ord('a') + fc) + str(8 - fr)
  223.     to_square = chr(ord('a') + tc) + str(8 - tr)
  224.    
  225.     if piece_type == 'p':
  226.         return from_square + '-' + to_square
  227.     else:
  228.         piece_symbol = piece_type.upper()
  229.         if piece.islower():
  230.             piece_symbol = piece_symbol.lower()
  231.         return piece_symbol + from_square + '-' + to_square
  232.  
  233. # Pure minimax without alpha-beta pruning, focused on finding mate
  234. def minimax(board, depth, maximizing_player, side):
  235.     # Terminal state check
  236.     legal_moves = get_legal_moves(board, side)
  237.    
  238.     if not legal_moves:
  239.         if is_in_check(board, side):
  240.             return -MATE_SCORE if maximizing_player else MATE_SCORE, None
  241.         else:
  242.             return 0, None  # Stalemate
  243.    
  244.     if depth == 0:
  245.         # At max depth, if no terminal state is found, return a neutral score
  246.         return 0, None
  247.    
  248.     if maximizing_player:
  249.         max_eval = -INF
  250.         best_move = None
  251.        
  252.         for move in legal_moves:
  253.             new_board = make_move(board, move)
  254.             next_side = 'b' if side == 'w' else 'w'
  255.            
  256.             eval_score, _ = minimax(new_board, depth - 1, False, next_side)
  257.            
  258.             if eval_score > max_eval:
  259.                 max_eval = eval_score
  260.                 best_move = move
  261.        
  262.         return max_eval, best_move
  263.     else:
  264.         min_eval = INF
  265.         best_move = None
  266.        
  267.         for move in legal_moves:
  268.             new_board = make_move(board, move)
  269.             next_side = 'b' if side == 'w' else 'w'
  270.            
  271.             eval_score, _ = minimax(new_board, depth - 1, True, next_side)
  272.            
  273.             if eval_score < min_eval:
  274.                 min_eval = eval_score
  275.                 best_move = move
  276.        
  277.         return min_eval, best_move
  278.  
  279. # Find complete mate sequence
  280. def find_mate_sequence(board, side, max_depth=100):
  281.     # Matovou posloupnost hledáme iterativním prohlubováním
  282.     for depth in range(1, max_depth + 1):
  283.         start_time = time.time()
  284.        
  285.         # Spustíme minimax s aktuální hloubkou
  286.         maximizing = (side == 'w')
  287.         score, best_move = minimax(board, depth, maximizing, side)
  288.        
  289.         end_time = time.time()
  290.         search_time = end_time - start_time
  291.        
  292.         # Vypíšeme informace o aktuální hloubce na jednom řádku
  293.         print(f"Hloubka {depth}: Čas = {search_time:.3f}s", end="")
  294.        
  295.         # Pokud byl nalezen mat
  296.         if abs(score) >= MATE_SCORE - 100:
  297.             print(f", Nalezen mat v hloubce {depth}!")
  298.            
  299.             # Generujeme posloupnost tahů až do matu
  300.             move_sequence = []
  301.             current_board = [row[:] for row in board]
  302.             current_side = side
  303.             current_depth = depth
  304.            
  305.             # Budeme postupně generovat nejlepší tahy až do matu
  306.             while current_depth > 0:
  307.                 # Najdeme nejlepší tah pro současnou stranu
  308.                 maximizing = (current_side == 'w')
  309.                 _, best_move = minimax(current_board, current_depth, maximizing, current_side)
  310.                
  311.                 if not best_move:
  312.                     break
  313.                
  314.                 # Přidáme tah do sekvence
  315.                 move_sequence.append((current_side, best_move))
  316.                
  317.                 # Vytiskneme stav po každém tahu
  318.                 fr, fc, tr, tc = best_move
  319.                 piece = current_board[fr][fc]
  320.                 piece_type = piece.lower()
  321.                 piece_name = piece_names.get(piece_type, f"figura {piece_type}")
  322.                
  323.                 move_from = chr(ord('a') + fc) + str(8 - fr)
  324.                 move_to = chr(ord('a') + tc) + str(8 - tr)
  325.                
  326.                 print(f"\nTah {len(move_sequence)}: {'Bílý' if current_side == 'w' else 'Černý'} - {piece_name.capitalize()} {move_from}-{move_to}")
  327.                
  328.                 # Aplikujeme tah
  329.                 current_board = make_move(current_board, best_move)
  330.                 print_board(current_board)
  331.                
  332.                 # Přepneme stranu
  333.                 current_side = 'b' if current_side == 'w' else 'w'
  334.                
  335.                 # Když byl tento tah mat, skončíme
  336.                 if not get_legal_moves(current_board, current_side) and is_in_check(current_board, current_side):
  337.                     print("\nŠach mat!")
  338.                     break
  339.                
  340.                 # Zmenšíme hloubku o 1 pro další tah
  341.                 current_depth -= 1
  342.            
  343.             return move_sequence
  344.         else:
  345.             print("")  # Nový řádek po výpisu informací o hloubce
  346.    
  347.     print("Žádný mat nebyl nalezen do zadané hloubky.")
  348.     return []
  349.  
  350. # Hlavní funkce pro analýzu pozice z FEN řetězce
  351. def analyze_position(fen, max_depth=100):
  352.     print("Šachový engine s čistým minimaxem")
  353.     print("=================================")
  354.     print(f"Analyzuji pozici: {fen}")
  355.    
  356.     board, side = parse_fen(fen)
  357.    
  358.     print("\nPočáteční pozice:")
  359.     print_board(board)
  360.     print(f"Na tahu je: {'Bílý' if side == 'w' else 'Černý'}")
  361.    
  362.     # Najdeme matovou posloupnost
  363.     mate_sequence = find_mate_sequence(board, side, max_depth)
  364.    
  365.     if mate_sequence:
  366.         print("\nKompletní matová posloupnost:")
  367.         for i, (move_side, move) in enumerate(mate_sequence):
  368.             fr, fc, tr, tc = move
  369.            
  370.             # Zjistit typ figury a její název
  371.             piece = board[fr][fc]
  372.             piece_type = piece.lower()
  373.             piece_name = piece_names.get(piece_type, f"figura {piece_type}")
  374.            
  375.             # Formát tahu v šachové notaci
  376.             move_from = chr(ord('a') + fc) + str(8 - fr)
  377.             move_to = chr(ord('a') + tc) + str(8 - tr)
  378.            
  379.             # Výpis tahu
  380.             print(f"{i+1}. {'Bílý' if move_side == 'w' else 'Černý'}: {piece_name.capitalize()} {move_from}-{move_to}")
  381.            
  382.             # Aplikovat tah na šachovnici pro další iteraci
  383.             board = make_move(board, move)
  384.     else:
  385.         print("Nebyla nalezena žádná matová posloupnost.")
  386.  
  387. # Hlavní spuštění
  388. if __name__ == "__main__":
  389.     # Pozice s věží
  390.     fen = "8/1K2k3/r7/8/8/8/8/8 b - - 0 1"
  391.  
  392.     fen = "8/1K6/3k1r2/8/8/8/8/8 b - - 6 4"
  393.  
  394.     fen = "8/AK6/3k1a2/8/8/8/8/8 b - - 0 1"
  395.    
  396.     # Spustíme analýzu s hledáním matové posloupnosti
  397.     analyze_position(fen, max_depth=20)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement