max2201111

Cele OK OK

Jul 20th, 2025
389
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 75.38 KB | Science | 0 0
  1. import time
  2. from datetime import datetime
  3. from collections import deque, defaultdict
  4. import copy
  5.  
  6. def print_board(board):
  7.     print(str(board))
  8.  
  9. def print_ascii_board(board, title="Pozice"):
  10.     """Print simple ASCII chess board with coordinates"""
  11.     print(f"\n{title}:")
  12.    
  13.     for rank in range(7, -1, -1):
  14.         row_str = f"{rank + 1} "
  15.         for file in range(8):
  16.             piece = board.board[rank][file]
  17.             if piece is None:
  18.                 row_str += "."
  19.             else:
  20.                 color, piece_type = piece
  21.                 if color == 'w':
  22.                     row_str += piece_type.upper()
  23.                 else:
  24.                     row_str += piece_type.lower()
  25.         print(row_str)
  26.    
  27.     print("  abcdefgh")
  28.     print()
  29.  
  30. def coords_to_algebraic(from_pos, to_pos):
  31.     """Convert coordinates to algebraic notation"""
  32.     from_file = chr(ord('a') + from_pos[1])
  33.     from_rank = str(from_pos[0] + 1)
  34.     to_file = chr(ord('a') + to_pos[1])
  35.     to_rank = str(to_pos[0] + 1)
  36.    
  37.     return f"{from_file}{from_rank}", f"{to_file}{to_rank}"
  38.  
  39. def move_to_algebraic(board, from_pos, to_pos, check_status=""):
  40.     """Convert move to proper algebraic notation"""
  41.     piece = board.board[from_pos[0]][from_pos[1]]
  42.     if not piece:
  43.         return "invalid"
  44.    
  45.     color, piece_type = piece
  46.     target = board.board[to_pos[0]][to_pos[1]]
  47.     is_capture = target is not None
  48.    
  49.     from_square, to_square = coords_to_algebraic(from_pos, to_pos)
  50.    
  51.     # Pawn moves
  52.     if piece_type == 'P':
  53.         if is_capture:
  54.             notation = f"{from_square[0]}x{to_square}"
  55.         else:
  56.             notation = to_square
  57.     else:
  58.         # Piece moves
  59.         notation = piece_type
  60.        
  61.         # Check for ambiguity (multiple pieces of same type can reach target)
  62.         ambiguous_pieces = []
  63.         for rank in range(8):
  64.             for file in range(8):
  65.                 other_piece = board.board[rank][file]
  66.                 if (other_piece and other_piece[0] == color and
  67.                     other_piece[1] == piece_type and (rank, file) != from_pos):
  68.                     # This piece could potentially move to the same square
  69.                     ambiguous_pieces.append((rank, file))
  70.        
  71.         # Add disambiguation if needed
  72.         if ambiguous_pieces:
  73.             notation += from_square[0]  # Add file for disambiguation
  74.        
  75.         if is_capture:
  76.             notation += "x"
  77.        
  78.         notation += to_square
  79.    
  80.     # Add check/mate indicators
  81.     notation += check_status
  82.    
  83.     return notation
  84.  
  85. class ChessBoard:
  86.     """Enhanced chess board implementation for fairy pieces"""
  87.    
  88.     def __init__(self, fen=None):
  89.         self.board = [[None for _ in range(8)] for _ in range(8)]
  90.         self.turn = True  # True = white, False = black
  91.         self.castling_rights = {'K': True, 'Q': True, 'k': True, 'q': True}
  92.         self.en_passant = None
  93.         self.halfmove_clock = 0
  94.         self.fullmove_number = 1
  95.         self.position_history = []  # For repetition detection
  96.         self.move_history = []  # Store moves in algebraic notation
  97.        
  98.         if fen:
  99.             self.set_fen(fen)
  100.         else:
  101.             self.setup_initial_position()
  102.  
  103.     def __str__(self):
  104.         """Simple text representation"""
  105.         rows = []
  106.         for i, row in enumerate(self.board[::-1], 1):
  107.             safe_row = []
  108.             for piece in row:
  109.                 if piece is None:
  110.                     safe_row.append('.')
  111.                 elif isinstance(piece, tuple):
  112.                     color, symbol = piece
  113.                     safe_row.append(symbol.upper() if color == 'w' else symbol.lower())
  114.                 else:
  115.                     safe_row.append(str(piece))
  116.             rows.append(f"{8 - i + 1} " + " ".join(safe_row))
  117.         rows.append("  a b c d e f g h")
  118.         return "\n".join(rows)
  119.  
  120.     def setup_initial_position(self):
  121.         """Set up starting position"""
  122.         pieces = ['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R']
  123.         for i, piece in enumerate(pieces):
  124.             self.board[0][i] = ('w', piece)
  125.         for i in range(8):
  126.             self.board[1][i] = ('w', 'P')
  127.        
  128.         pieces = ['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R']
  129.         for i, piece in enumerate(pieces):
  130.             self.board[7][i] = ('b', piece)
  131.         for i in range(8):
  132.             self.board[6][i] = ('b', 'P')
  133.    
  134.     def set_fen(self, fen_string):
  135.         """Set position from FEN string"""
  136.         parts = fen_string.split()
  137.        
  138.         # Board position
  139.         rows = parts[0].split('/')
  140.         for rank, row in enumerate(rows):
  141.             file_idx = 0
  142.             for char in row:
  143.                 if char.isdigit():
  144.                     for _ in range(int(char)):
  145.                         self.board[7-rank][file_idx] = None
  146.                         file_idx += 1
  147.                 else:
  148.                     color = 'w' if char.isupper() else 'b'
  149.                     self.board[7-rank][file_idx] = (color, char.upper())
  150.                     file_idx += 1
  151.        
  152.         self.turn = parts[1] == 'w'
  153.        
  154.         castling = parts[2] if len(parts) > 2 else '-'
  155.         self.castling_rights = {
  156.             'K': 'K' in castling, 'Q': 'Q' in castling,
  157.             'k': 'k' in castling, 'q': 'q' in castling
  158.         }
  159.        
  160.         self.en_passant = parts[3] if len(parts) > 3 and parts[3] != '-' else None
  161.         self.halfmove_clock = int(parts[4]) if len(parts) > 4 else 0
  162.         self.fullmove_number = int(parts[5]) if len(parts) > 5 else 1
  163.    
  164.     def get_fen(self):
  165.         """Return FEN string of position"""
  166.         fen_parts = []
  167.         for rank in range(7, -1, -1):
  168.             row_fen = ""
  169.             empty_count = 0
  170.            
  171.             for file in range(8):
  172.                 piece = self.board[rank][file]
  173.                 if piece is None:
  174.                     empty_count += 1
  175.                 else:
  176.                     if empty_count > 0:
  177.                         row_fen += str(empty_count)
  178.                         empty_count = 0
  179.                     color, piece_type = piece
  180.                     row_fen += piece_type if color == 'w' else piece_type.lower()
  181.            
  182.             if empty_count > 0:
  183.                 row_fen += str(empty_count)
  184.            
  185.             fen_parts.append(row_fen)
  186.        
  187.         position = '/'.join(fen_parts)
  188.         turn = 'w' if self.turn else 'b'
  189.        
  190.         castling = ''
  191.         for right in ['K', 'Q', 'k', 'q']:
  192.             if self.castling_rights[right]:
  193.                 castling += right
  194.         if not castling:
  195.             castling = '-'
  196.        
  197.         en_passant = self.en_passant if self.en_passant else '-'
  198.        
  199.         return f"{position} {turn} {castling} {en_passant} {self.halfmove_clock} {self.fullmove_number}"
  200.    
  201.     def get_position_key(self):
  202.         """Get position key for repetition detection (without clocks)"""
  203.         parts = self.get_fen().split()
  204.         return f"{parts[0]} {parts[1]} {parts[2]} {parts[3]}"
  205.    
  206.     def copy(self):
  207.         """Create a copy of the board"""
  208.         new_board = ChessBoard()
  209.         new_board.board = [row[:] for row in self.board]
  210.         new_board.turn = self.turn
  211.         new_board.castling_rights = self.castling_rights.copy()
  212.         new_board.en_passant = self.en_passant
  213.         new_board.halfmove_clock = self.halfmove_clock
  214.         new_board.fullmove_number = self.fullmove_number
  215.         new_board.position_history = self.position_history[:]
  216.         new_board.move_history = self.move_history[:]
  217.         return new_board
  218.    
  219.     def make_move(self, from_pos, to_pos):
  220.         """Make a move and update board state"""
  221.         from_rank, from_file = from_pos
  222.         to_rank, to_file = to_pos
  223.        
  224.         # Store position for repetition detection
  225.         self.position_history.append(self.get_position_key())
  226.        
  227.         piece = self.board[from_rank][from_file]
  228.         captured = self.board[to_rank][to_file]
  229.        
  230.         # Generate algebraic notation before making the move
  231.         algebraic = move_to_algebraic(self, from_pos, to_pos)
  232.        
  233.         # Update halfmove clock
  234.         if piece[1] == 'P' or captured is not None:
  235.             self.halfmove_clock = 0
  236.         else:
  237.             self.halfmove_clock += 1
  238.        
  239.         # Make the move
  240.         self.board[to_rank][to_file] = piece
  241.         self.board[from_rank][from_file] = None
  242.        
  243.         # Check if this move puts opponent in check
  244.         opponent_color = 'b' if piece[0] == 'w' else 'w'
  245.         if self.is_check(opponent_color):
  246.             # Check if it's mate
  247.             temp_board = self.copy()
  248.             temp_board.turn = not temp_board.turn
  249.             if not temp_board.has_legal_moves():
  250.                 algebraic += "#"  # Checkmate
  251.             else:
  252.                 algebraic += "+"  # Check
  253.        
  254.         self.move_history.append(algebraic)
  255.        
  256.         # Update castling rights if king or rook moves
  257.         if piece[1] == 'K':
  258.             if piece[0] == 'w':
  259.                 self.castling_rights['K'] = False
  260.                 self.castling_rights['Q'] = False
  261.             else:
  262.                 self.castling_rights['k'] = False
  263.                 self.castling_rights['q'] = False
  264.         elif piece[1] == 'R':
  265.             if from_pos == (0, 0):
  266.                 self.castling_rights['Q'] = False
  267.             elif from_pos == (0, 7):
  268.                 self.castling_rights['K'] = False
  269.             elif from_pos == (7, 0):
  270.                 self.castling_rights['q'] = False
  271.             elif from_pos == (7, 7):
  272.                 self.castling_rights['k'] = False
  273.        
  274.         # Change turn
  275.         self.turn = not self.turn
  276.         if self.turn:  # If white to move, increment fullmove
  277.             self.fullmove_number += 1
  278.    
  279.     def has_legal_moves(self):
  280.         """Check if current player has any legal moves"""
  281.         for rank in range(8):
  282.             for file in range(8):
  283.                 piece = self.board[rank][file]
  284.                 if piece and piece[0] == ('w' if self.turn else 'b'):
  285.                     # This is simplified - would need full move generation
  286.                     return True
  287.         return False
  288.    
  289.     def find_king(self, color):
  290.         """Find king of given color"""
  291.         for rank in range(8):
  292.             for file in range(8):
  293.                 piece = self.board[rank][file]
  294.                 if piece and piece[0] == color and piece[1] == 'K':
  295.                     return (rank, file)
  296.         return None
  297.    
  298.     def is_check(self, color):
  299.         """Check if king is in check"""
  300.         king_pos = self.find_king(color)
  301.         if not king_pos:
  302.             return False
  303.        
  304.         enemy_color = 'b' if color == 'w' else 'w'
  305.        
  306.         for rank in range(8):
  307.             for file in range(8):
  308.                 piece = self.board[rank][file]
  309.                 if piece and piece[0] == enemy_color:
  310.                     if self.attacks_square((rank, file), king_pos):
  311.                         return True
  312.         return False
  313.    
  314.     def is_threefold_repetition(self):
  315.         """Check for threefold repetition"""
  316.         current_pos = self.get_position_key()
  317.         count = self.position_history.count(current_pos)
  318.         return count >= 2
  319.    
  320.     def is_fifty_move_rule(self):
  321.         """Check for fifty move rule"""
  322.         return self.halfmove_clock >= 100
  323.    
  324.     def attacks_square(self, from_pos, to_pos):
  325.         """Check if piece attacks given square"""
  326.         rank, file = from_pos
  327.         piece = self.board[rank][file]
  328.        
  329.         if not piece:
  330.             return False
  331.        
  332.         color, piece_type = piece
  333.        
  334.         if piece_type == 'P':
  335.             return self.pawn_attacks(from_pos, to_pos, color)
  336.         elif piece_type == 'R':
  337.             return self.rook_attacks(from_pos, to_pos)
  338.         elif piece_type == 'N':
  339.             return self.knight_attacks(from_pos, to_pos)
  340.         elif piece_type == 'B':
  341.             return self.bishop_attacks(from_pos, to_pos)
  342.         elif piece_type == 'Q':
  343.             return self.queen_attacks(from_pos, to_pos)
  344.         elif piece_type == 'K':
  345.             return self.king_attacks(from_pos, to_pos)
  346.         elif piece_type == 'A':  # Amazon (Q+N)
  347.             return self.queen_attacks(from_pos, to_pos) or self.knight_attacks(from_pos, to_pos)
  348.         elif piece_type == 'C':  # Cyril (R+N)
  349.             return self.rook_attacks(from_pos, to_pos) or self.knight_attacks(from_pos, to_pos)
  350.         elif piece_type == 'E':  # Eve (B+N)
  351.             return self.bishop_attacks(from_pos, to_pos) or self.knight_attacks(from_pos, to_pos)
  352.        
  353.         return False
  354.    
  355.     def pawn_attacks(self, from_pos, to_pos, color):
  356.         """Check pawn attack"""
  357.         from_rank, from_file = from_pos
  358.         to_rank, to_file = to_pos
  359.        
  360.         direction = 1 if color == 'w' else -1
  361.         return (abs(from_file - to_file) == 1 and
  362.                 to_rank - from_rank == direction)
  363.    
  364.     def knight_attacks(self, from_pos, to_pos):
  365.         """Check knight attack"""
  366.         from_rank, from_file = from_pos
  367.         to_rank, to_file = to_pos
  368.        
  369.         dr = abs(from_rank - to_rank)
  370.         df = abs(from_file - to_file)
  371.        
  372.         return (dr == 2 and df == 1) or (dr == 1 and df == 2)
  373.    
  374.     def rook_attacks(self, from_pos, to_pos):
  375.         """Check rook attack"""
  376.         from_rank, from_file = from_pos
  377.         to_rank, to_file = to_pos
  378.        
  379.         if from_rank != to_rank and from_file != to_file:
  380.             return False
  381.        
  382.         if from_rank == to_rank:  # Horizontal
  383.             start = min(from_file, to_file) + 1
  384.             end = max(from_file, to_file)
  385.             for f in range(start, end):
  386.                 if self.board[from_rank][f] is not None:
  387.                     return False
  388.         else:  # Vertical
  389.             start = min(from_rank, to_rank) + 1
  390.             end = max(from_rank, to_rank)
  391.             for r in range(start, end):
  392.                 if self.board[r][from_file] is not None:
  393.                     return False
  394.        
  395.         return True
  396.    
  397.     def bishop_attacks(self, from_pos, to_pos):
  398.         """Check bishop attack"""
  399.         from_rank, from_file = from_pos
  400.         to_rank, to_file = to_pos
  401.        
  402.         dr = to_rank - from_rank
  403.         df = to_file - from_file
  404.        
  405.         if abs(dr) != abs(df) or dr == 0:
  406.             return False
  407.        
  408.         step_r = 1 if dr > 0 else -1
  409.         step_f = 1 if df > 0 else -1
  410.        
  411.         steps = abs(dr)
  412.         for i in range(1, steps):
  413.             check_rank = from_rank + i * step_r
  414.             check_file = from_file + i * step_f
  415.             if self.board[check_rank][check_file] is not None:
  416.                 return False
  417.        
  418.         return True
  419.    
  420.     def queen_attacks(self, from_pos, to_pos):
  421.         """Check queen attack"""
  422.         return self.rook_attacks(from_pos, to_pos) or self.bishop_attacks(from_pos, to_pos)
  423.    
  424.     def king_attacks(self, from_pos, to_pos):
  425.         """Check king attack"""
  426.         from_rank, from_file = from_pos
  427.         to_rank, to_file = to_pos
  428.        
  429.         return (abs(from_rank - to_rank) <= 1 and
  430.                 abs(from_file - to_file) <= 1 and
  431.                 from_pos != to_pos)
  432.  
  433.  
  434. class EnhancedFairyChessAnalyzer:
  435.     """Enhanced analyzer focused on recursive search for fairy chess - FIXED VERSION"""
  436.    
  437.     def __init__(self, start_fen):
  438.         self.start_fen = start_fen
  439.         self.transposition_table = {}
  440.         self.nodes_evaluated = 0
  441.         self.depth_stats = {}
  442.         self.move_count = 0
  443.         self.total_moves = 0
  444.         self.current_search_depth = 0  # FIXED: Initialize search depth tracking
  445.        
  446.         # Time tracking
  447.         self.start_time = None
  448.         self.total_analysis_time = 0
  449.         self.mate_sequence_time = 0
  450.         self.depth_times = {}  # Time per depth level
  451.        
  452.     def print_time(self, message=""):
  453.         """Print time with message and elapsed time"""
  454.         now = datetime.now()
  455.         time_str = now.strftime("%H:%M:%S")
  456.        
  457.         # Calculate elapsed time if analysis started
  458.         if self.start_time:
  459.             elapsed = time.time() - self.start_time
  460.             elapsed_str = f" | Celkem: {elapsed:.1f}s"
  461.         else:
  462.             elapsed_str = ""
  463.        
  464.         print(f"[{time_str}]{elapsed_str} {message}")
  465.    
  466.     def start_timing(self, operation_name="Analýza"):
  467.         """Start timing an operation"""
  468.         self.start_time = time.time()
  469.         self.print_time(f"🚀 Začátek: {operation_name}")
  470.    
  471.     def stop_timing(self, operation_name="Analýza"):
  472.         """Stop timing and return elapsed time"""
  473.         if self.start_time:
  474.             elapsed = time.time() - self.start_time
  475.             self.print_time(f"⏹️  Konec: {operation_name} ({elapsed:.1f}s)")
  476.             return elapsed
  477.         return 0
  478.    
  479.     def print_intermediate_time(self, message=""):
  480.         """Print intermediate timing"""
  481.         if self.start_time:
  482.             elapsed = time.time() - self.start_time
  483.             self.print_time(f"⏱️  {message} (mezičas: {elapsed:.1f}s)")
  484.         else:
  485.             self.print_time(f"⏱️  {message}")
  486.    
  487.     def print_position_info(self, board, title="Pozice"):
  488.         """Print basic position information"""
  489.         print_ascii_board(board, title)
  490.         print(f"FEN: {board.get_fen()}")
  491.         print(f"Na tahu: {'Bílý' if board.turn else 'Černý'}")
  492.    
  493.     def print_depth_progress(self, depth, move_num, total_moves):
  494.         """Print minimal progress for current depth"""
  495.         if move_num % 3 == 0 or move_num == total_moves:
  496.             percentage = (move_num / total_moves * 100) if total_moves > 0 else 0
  497.             print(f"Hloubka {depth}: {move_num}/{total_moves} ({percentage:.0f}%)")
  498.    
  499.     def evaluate_material(self, board):
  500.         """Evaluate material balance - enhanced for fairy pieces"""
  501.         piece_values = {
  502.             'P': 1, 'N': 3, 'B': 3, 'R': 5, 'Q': 9, 'K': 0,
  503.             'A': 13,  # Amazon is very powerful (Q+N)
  504.             'C': 8,   # Cyril (R+N)
  505.             'E': 6    # Eve (B+N)
  506.         }
  507.        
  508.         white_material = 0
  509.         black_material = 0
  510.        
  511.         for rank in range(8):
  512.             for file in range(8):
  513.                 piece = board.board[rank][file]
  514.                 if piece:
  515.                     color, piece_type = piece
  516.                     value = piece_values.get(piece_type, 0)
  517.                     if color == 'w':
  518.                         white_material += value
  519.                     else:
  520.                         black_material += value
  521.        
  522.         return white_material - black_material
  523.    
  524.     def determine_stronger_side(self, board):
  525.         """Determine which side is stronger based on material"""
  526.         material_diff = self.evaluate_material(board)
  527.         if abs(material_diff) < 1:
  528.             return None
  529.         return 'w' if material_diff > 0 else 'b'
  530.    
  531.     def evaluate_position(self, board):
  532.         """Enhanced position evaluation for fairy pieces"""
  533.         score = 0
  534.        
  535.         # 1. Material evaluation
  536.         material = self.evaluate_material(board)
  537.         score += material
  538.        
  539.         # 2. Piece activity and centralization
  540.         activity_bonus = 0
  541.         for rank in range(8):
  542.             for file in range(8):
  543.                 piece = board.board[rank][file]
  544.                 if piece:
  545.                     color, piece_type = piece
  546.                    
  547.                     # Center control bonus
  548.                     center_distance = abs(3.5 - rank) + abs(3.5 - file)
  549.                     center_bonus = (7 - center_distance) * 0.05
  550.                    
  551.                     # Enhanced bonus for fairy pieces in center
  552.                     if piece_type in ['A', 'C', 'E']:
  553.                         center_bonus *= 2
  554.                    
  555.                     if color == 'w':
  556.                         activity_bonus += center_bonus
  557.                     else:
  558.                         activity_bonus -= center_bonus
  559.        
  560.         score += activity_bonus
  561.        
  562.         # 3. Mobility (very important for fairy pieces)
  563.         current_side = 'w' if board.turn else 'b'
  564.         mobility = len(self.generate_legal_moves(board))
  565.        
  566.         # Switch sides to count opponent mobility
  567.         temp_board = board.copy()
  568.         temp_board.turn = not temp_board.turn
  569.         opponent_mobility = len(self.generate_legal_moves(temp_board))
  570.        
  571.         mobility_diff = mobility - opponent_mobility
  572.         if current_side == 'w':
  573.             score += mobility_diff * 0.1
  574.         else:
  575.             score -= mobility_diff * 0.1
  576.        
  577.         # 4. King safety
  578.         for color in ['w', 'b']:
  579.             king_pos = board.find_king(color)
  580.             if king_pos:
  581.                 king_rank, king_file = king_pos
  582.                 # Penalty for king in center (dangerous with fairy pieces)
  583.                 if 2 <= king_rank <= 5 and 2 <= king_file <= 5:
  584.                     danger_penalty = -1.0
  585.                     if color == 'w':
  586.                         score += danger_penalty
  587.                     else:
  588.                         score -= danger_penalty
  589.        
  590.         # 5. Check bonus/penalty
  591.         if board.is_check('w'):
  592.             score -= 0.5
  593.         if board.is_check('b'):
  594.             score += 0.5
  595.        
  596.         return score
  597.    
  598.     def generate_legal_moves(self, board):
  599.         """Generate all legal moves for current position"""
  600.         moves = []
  601.        
  602.         for rank in range(8):
  603.             for file in range(8):
  604.                 piece = board.board[rank][file]
  605.                 if piece and piece[0] == ('w' if board.turn else 'b'):
  606.                     piece_moves = self.generate_piece_moves(board, (rank, file))
  607.                     for to_pos in piece_moves:
  608.                         if self.is_move_legal(board, (rank, file), to_pos):
  609.                             moves.append(((rank, file), to_pos))
  610.        
  611.         return moves
  612.    
  613.     def generate_piece_moves(self, board, from_pos):
  614.         """Generate moves for a specific piece"""
  615.         rank, file = from_pos
  616.         piece = board.board[rank][file]
  617.        
  618.         if not piece:
  619.             return []
  620.        
  621.         color, piece_type = piece
  622.        
  623.         if piece_type == 'P':
  624.             return self.generate_pawn_moves(board, from_pos)
  625.         elif piece_type == 'R':
  626.             return self.generate_sliding_moves(board, from_pos, [(0,1), (0,-1), (1,0), (-1,0)])
  627.         elif piece_type == 'N':
  628.             return self.generate_knight_moves(board, from_pos)
  629.         elif piece_type == 'B':
  630.             return self.generate_sliding_moves(board, from_pos, [(1,1), (1,-1), (-1,1), (-1,-1)])
  631.         elif piece_type == 'Q':
  632.             return self.generate_sliding_moves(board, from_pos,
  633.                 [(0,1), (0,-1), (1,0), (-1,0), (1,1), (1,-1), (-1,1), (-1,-1)])
  634.         elif piece_type == 'K':
  635.             return self.generate_king_moves(board, from_pos)
  636.         elif piece_type == 'A':  # Amazon
  637.             queen_moves = self.generate_sliding_moves(board, from_pos,
  638.                 [(0,1), (0,-1), (1,0), (-1,0), (1,1), (1,-1), (-1,1), (-1,-1)])
  639.             knight_moves = self.generate_knight_moves(board, from_pos)
  640.             return queen_moves + knight_moves
  641.         elif piece_type == 'C':  # Cyril
  642.             rook_moves = self.generate_sliding_moves(board, from_pos, [(0,1), (0,-1), (1,0), (-1,0)])
  643.             knight_moves = self.generate_knight_moves(board, from_pos)
  644.             return rook_moves + knight_moves
  645.         elif piece_type == 'E':  # Eve
  646.             bishop_moves = self.generate_sliding_moves(board, from_pos, [(1,1), (1,-1), (-1,1), (-1,-1)])
  647.             knight_moves = self.generate_knight_moves(board, from_pos)
  648.             return bishop_moves + knight_moves
  649.        
  650.         return []
  651.    
  652.     def generate_pawn_moves(self, board, from_pos):
  653.         """Generate pawn moves"""
  654.         rank, file = from_pos
  655.         piece = board.board[rank][file]
  656.         color = piece[0]
  657.         moves = []
  658.        
  659.         direction = 1 if color == 'w' else -1
  660.         start_rank = 1 if color == 'w' else 6
  661.        
  662.         # Forward move
  663.         new_rank = rank + direction
  664.         if 0 <= new_rank <= 7 and board.board[new_rank][file] is None:
  665.             moves.append((new_rank, file))
  666.            
  667.             # Double move from starting position
  668.             if rank == start_rank and board.board[new_rank + direction][file] is None:
  669.                 moves.append((new_rank + direction, file))
  670.        
  671.         # Captures
  672.         for df in [-1, 1]:
  673.             new_file = file + df
  674.             if 0 <= new_file <= 7 and 0 <= new_rank <= 7:
  675.                 target = board.board[new_rank][new_file]
  676.                 if target and target[0] != color:
  677.                     moves.append((new_rank, new_file))
  678.        
  679.         return moves
  680.    
  681.     def generate_knight_moves(self, board, from_pos):
  682.         """Generate knight moves"""
  683.         rank, file = from_pos
  684.         piece = board.board[rank][file]
  685.         color = piece[0]
  686.         moves = []
  687.        
  688.         knight_moves = [(2,1), (2,-1), (-2,1), (-2,-1), (1,2), (1,-2), (-1,2), (-1,-2)]
  689.        
  690.         for dr, df in knight_moves:
  691.             new_rank = rank + dr
  692.             new_file = file + df
  693.            
  694.             if 0 <= new_rank <= 7 and 0 <= new_file <= 7:
  695.                 target = board.board[new_rank][new_file]
  696.                 if not target or target[0] != color:
  697.                     moves.append((new_rank, new_file))
  698.        
  699.         return moves
  700.    
  701.     def generate_sliding_moves(self, board, from_pos, directions):
  702.         """Generate sliding piece moves"""
  703.         rank, file = from_pos
  704.         piece = board.board[rank][file]
  705.         color = piece[0]
  706.         moves = []
  707.        
  708.         for dr, df in directions:
  709.             for distance in range(1, 8):
  710.                 new_rank = rank + dr * distance
  711.                 new_file = file + df * distance
  712.                
  713.                 if not (0 <= new_rank <= 7 and 0 <= new_file <= 7):
  714.                     break
  715.                
  716.                 target = board.board[new_rank][new_file]
  717.                
  718.                 if not target:
  719.                     moves.append((new_rank, new_file))
  720.                 elif target[0] != color:
  721.                     moves.append((new_rank, new_file))
  722.                     break
  723.                 else:
  724.                     break
  725.        
  726.         return moves
  727.    
  728.     def generate_king_moves(self, board, from_pos):
  729.         """Generate king moves"""
  730.         rank, file = from_pos
  731.         piece = board.board[rank][file]
  732.         color = piece[0]
  733.         moves = []
  734.        
  735.         for dr in [-1, 0, 1]:
  736.             for df in [-1, 0, 1]:
  737.                 if dr == 0 and df == 0:
  738.                     continue
  739.                
  740.                 new_rank = rank + dr
  741.                 new_file = file + df
  742.                
  743.                 if 0 <= new_rank <= 7 and 0 <= new_file <= 7:
  744.                     target = board.board[new_rank][new_file]
  745.                     if not target or target[0] != color:
  746.                         moves.append((new_rank, new_file))
  747.        
  748.         return moves
  749.    
  750.     def is_move_legal(self, board, from_pos, to_pos):
  751.         """Check if move is legal (doesn't leave king in check)"""
  752.         temp_board = board.copy()
  753.         temp_board.make_move(from_pos, to_pos)
  754.        
  755.         color = 'w' if board.turn else 'b'
  756.         return not temp_board.is_check(color)
  757.    
  758.     def is_terminal_position(self, board):
  759.         """Check if position is terminal and return evaluation"""
  760.         legal_moves = self.generate_legal_moves(board)
  761.         current_color = 'w' if board.turn else 'b'
  762.        
  763.         # Check for checkmate or stalemate
  764.         if not legal_moves:
  765.             if board.is_check(current_color):
  766.                 # Checkmate - losing side
  767.                 return ('mate', 0)
  768.             else:
  769.                 # Stalemate - draw
  770.                 return ('draw', 0)
  771.        
  772.         # Check for draw conditions
  773.         if board.is_fifty_move_rule() or board.is_threefold_repetition():
  774.             return ('draw', 0)
  775.        
  776.         # Check for insufficient material (basic check)
  777.         if self.is_insufficient_material(board):
  778.             return ('draw', 0)
  779.        
  780.         return None
  781.    
  782.     def is_insufficient_material(self, board):
  783.         """Basic insufficient material detection"""
  784.         pieces = []
  785.         for rank in range(8):
  786.             for file in range(8):
  787.                 piece = board.board[rank][file]
  788.                 if piece:
  789.                     pieces.append(piece[1])
  790.        
  791.         # King vs King
  792.         if len(pieces) == 2:
  793.             return True
  794.        
  795.         # King + Bishop/Knight vs King
  796.         if len(pieces) == 3 and any(p in pieces for p in ['B', 'N']):
  797.             return True
  798.        
  799.         return False
  800.    
  801.     def minimax_with_fairy_optimization(self, board, depth, alpha, beta, maximizing_player):
  802.         """FIXED minimax with correct mate detection for fairy chess pieces"""
  803.         self.nodes_evaluated += 1
  804.        
  805.         # Check transposition table first
  806.         position_key = board.get_position_key()
  807.         if position_key in self.transposition_table:
  808.             stored_depth, stored_value = self.transposition_table[position_key]
  809.             if stored_depth >= depth:
  810.                 return stored_value
  811.        
  812.         # FIXED: Terminal position check with correct mate distance calculation
  813.         terminal_result = self.is_terminal_position(board)
  814.         if terminal_result or depth == 0:
  815.             if terminal_result:
  816.                 result_type, moves_to_end = terminal_result
  817.                 if result_type == 'mate':
  818.                     # FIXED: Mate distance calculation
  819.                     # Current player is in checkmate, so opponent wins
  820.                     # Distance to mate = remaining depth (how many moves until mate)
  821.                     if maximizing_player:
  822.                         # Current maximizing player loses (gets mated)
  823.                         return -10000 + (self.current_search_depth - depth)
  824.                     else:
  825.                         # Current minimizing player loses (gets mated)
  826.                         return 10000 - (self.current_search_depth - depth)
  827.                 else:  # draw
  828.                     return 0
  829.             else:
  830.                 # Leaf node - evaluate position
  831.                 return self.evaluate_position(board)
  832.        
  833.         legal_moves = self.generate_legal_moves(board)
  834.        
  835.         # FIXED: If no legal moves but not detected as terminal, it's mate/stalemate
  836.         if not legal_moves:
  837.             current_color = 'w' if board.turn else 'b'
  838.             if board.is_check(current_color):
  839.                 # Checkmate
  840.                 if maximizing_player:
  841.                     return -10000 + (self.current_search_depth - depth)
  842.                 else:
  843.                     return 10000 - (self.current_search_depth - depth)
  844.             else:
  845.                 # Stalemate
  846.                 return 0
  847.        
  848.         # Move ordering for better alpha-beta pruning
  849.         legal_moves = self.order_moves_for_fairy_pieces(board, legal_moves)
  850.        
  851.         # Progress tracking for root level
  852.         if depth == self.current_search_depth:
  853.             self.total_moves = len(legal_moves)
  854.             self.move_count = 0
  855.        
  856.         if maximizing_player:
  857.             max_eval = float('-inf')
  858.             for move in legal_moves:
  859.                 if depth == self.current_search_depth:
  860.                     self.move_count += 1
  861.                     self.print_depth_progress(depth, self.move_count, self.total_moves)
  862.                
  863.                 temp_board = board.copy()
  864.                 temp_board.make_move(move[0], move[1])
  865.                
  866.                 eval_score = self.minimax_with_fairy_optimization(
  867.                     temp_board, depth - 1, alpha, beta, False)
  868.                
  869.                 if eval_score > max_eval:
  870.                     max_eval = eval_score
  871.                     if depth == self.current_search_depth:
  872.                         algebraic = move_to_algebraic(board, move[0], move[1])
  873.                         print(f"Nový nejlepší: {algebraic} ({max_eval:.1f})")
  874.                
  875.                 alpha = max(alpha, eval_score)
  876.                 if beta <= alpha:
  877.                     break  # Alpha-beta cutoff
  878.            
  879.             # Store result in transposition table
  880.             self.transposition_table[position_key] = (depth, max_eval)
  881.             return max_eval
  882.         else:
  883.             min_eval = float('inf')
  884.             for move in legal_moves:
  885.                 temp_board = board.copy()
  886.                 temp_board.make_move(move[0], move[1])
  887.                
  888.                 eval_score = self.minimax_with_fairy_optimization(
  889.                     temp_board, depth - 1, alpha, beta, True)
  890.                
  891.                 min_eval = min(min_eval, eval_score)
  892.                 beta = min(beta, eval_score)
  893.                 if beta <= alpha:
  894.                     break  # Alpha-beta cutoff
  895.            
  896.             # Store result in transposition table
  897.             self.transposition_table[position_key] = (depth, min_eval)
  898.             return min_eval
  899.    
  900.     def order_moves_for_fairy_pieces(self, board, moves):
  901.         """Order moves to improve alpha-beta pruning efficiency"""
  902.         def move_priority(move):
  903.             from_pos, to_pos = move
  904.             piece = board.board[from_pos[0]][from_pos[1]]
  905.             target = board.board[to_pos[0]][to_pos[1]]
  906.            
  907.             priority = 0
  908.            
  909.             # 1. Captures get highest priority
  910.             if target:
  911.                 piece_values = {'P': 1, 'N': 3, 'B': 3, 'R': 5, 'Q': 9, 'A': 13, 'C': 8, 'E': 6}
  912.                 priority += piece_values.get(target[1], 0) * 10
  913.            
  914.             # 2. Fairy piece moves get bonus
  915.             if piece and piece[1] in ['A', 'C', 'E']:
  916.                 priority += 5
  917.            
  918.             # 3. Center moves get small bonus
  919.             to_rank, to_file = to_pos
  920.             center_distance = abs(3.5 - to_rank) + abs(3.5 - to_file)
  921.             priority += (7 - center_distance) * 0.1
  922.            
  923.             # 4. Check-giving moves get bonus
  924.             temp_board = board.copy()
  925.             temp_board.make_move(from_pos, to_pos)
  926.             opponent_color = 'b' if board.turn else 'w'
  927.             if temp_board.is_check(opponent_color):
  928.                 priority += 3
  929.            
  930.             return priority
  931.        
  932.         # Sort moves by priority (highest first)
  933.         return sorted(moves, key=move_priority, reverse=True)
  934.    
  935.     def evaluate_position_static(self, board):
  936.         """Statické ohodnocení pozice bez rekurze"""
  937.         score = 0
  938.        
  939.         # 1. Materiálové ohodnocení
  940.         material_score = self.evaluate_material(board)
  941.         score += material_score
  942.        
  943.         # 2. Pozice figur (centralizace)
  944.         positional_score = 0
  945.         for rank in range(8):
  946.             for file in range(8):
  947.                 piece = board.board[rank][file]
  948.                 if piece:
  949.                     color, piece_type = piece
  950.                    
  951.                     # Bonus za centrální pozice
  952.                     center_distance = abs(3.5 - rank) + abs(3.5 - file)
  953.                     center_bonus = (7 - center_distance) * 0.1
  954.                    
  955.                     if color == 'w':
  956.                         positional_score += center_bonus
  957.                     else:
  958.                         positional_score -= center_bonus
  959.                    
  960.                     # Speciální bonusy pro pohádkové figury
  961.                     if piece_type in ['A', 'C', 'E']:  # Fairy pieces
  962.                         if color == 'w':
  963.                             positional_score += center_bonus * 2  # Double bonus
  964.                         else:
  965.                             positional_score -= center_bonus * 2
  966.        
  967.         score += positional_score
  968.        
  969.         # 3. Mobilita (počet legálních tahů)
  970.         legal_moves = len(self.generate_legal_moves(board))
  971.         mobility_bonus = legal_moves * 0.05
  972.        
  973.         if board.turn:  # White to move
  974.             score += mobility_bonus
  975.         else:  # Black to move
  976.             score -= mobility_bonus
  977.        
  978.         # 4. Bezpečnost krále
  979.         king_safety_score = 0
  980.         for color in ['w', 'b']:
  981.             king_pos = board.find_king(color)
  982.             if king_pos:
  983.                 # Penalizace za krále v centru
  984.                 king_rank, king_file = king_pos
  985.                 if 2 <= king_rank <= 5 and 2 <= king_file <= 5:
  986.                     king_danger = -0.5
  987.                 else:
  988.                     king_danger = 0
  989.                
  990.                 if color == 'w':
  991.                     king_safety_score += king_danger
  992.                 else:
  993.                     king_safety_score -= king_danger
  994.        
  995.         score += king_safety_score
  996.        
  997.         # 5. Kontrola šachu (důležité pro taktiku)
  998.         if board.is_check('w'):
  999.             score -= 0.3  # Penalty for white in check
  1000.         if board.is_check('b'):
  1001.             score += 0.3  # Bonus if black in check
  1002.        
  1003.         return score
  1004.    
  1005.     def analyze_position_static_only(self, max_evaluations=1000):
  1006.         """Analýza pouze se statickým ohodnocením"""
  1007.         board = ChessBoard(self.start_fen)
  1008.        
  1009.         print("=== STATICKÁ ANALÝZA (bez rekurze) ===")
  1010.         self.print_position_info(board, "Výchozí pozice")
  1011.        
  1012.         # Ohodnotit výchozí pozici
  1013.         base_score = self.evaluate_position_static(board)
  1014.         print(f"Ohodnocení výchozí pozice: {base_score:.2f}")
  1015.        
  1016.         # Získat všechny legální tahy
  1017.         legal_moves = self.generate_legal_moves(board)
  1018.         print(f"Legálních tahů: {len(legal_moves)}")
  1019.        
  1020.         if not legal_moves:
  1021.             print("Žádné legální tahy")
  1022.             return None
  1023.        
  1024.         # Ohodnotit každý tah
  1025.         print(f"\nOhodnocování tahů:")
  1026.         move_evaluations = []
  1027.        
  1028.         for i, move in enumerate(legal_moves, 1):
  1029.             temp_board = board.copy()
  1030.             temp_board.make_move(move[0], move[1])
  1031.            
  1032.             # Statické ohodnocení
  1033.             move_score = self.evaluate_position_static(temp_board)
  1034.             algebraic = move_to_algebraic(board, move[0], move[1])
  1035.            
  1036.             move_evaluations.append((move, move_score, algebraic))
  1037.             print(f"  {i:2d}. {algebraic}: {move_score:+.2f}")
  1038.        
  1039.         # Najít nejlepší tah
  1040.         stronger_side = self.determine_stronger_side(board)
  1041.         current_color = 'w' if board.turn else 'b'
  1042.        
  1043.         if stronger_side == current_color:
  1044.             # Silnější strana - maximalizuj
  1045.             best_move_data = max(move_evaluations, key=lambda x: x[1])
  1046.             strategy = "AGRESIVNÍ (maximalizace)"
  1047.         elif stronger_side is not None:
  1048.             # Slabší strana - minimalizuj (hledej nejmenší ztrátu)
  1049.             best_move_data = min(move_evaluations, key=lambda x: x[1])
  1050.             strategy = "DEFENZIVNÍ (minimalizace)"
  1051.         else:
  1052.             # Vyrovnaná pozice
  1053.             if board.turn:  # White maximizes
  1054.                 best_move_data = max(move_evaluations, key=lambda x: x[1])
  1055.             else:  # Black minimizes
  1056.                 best_move_data = min(move_evaluations, key=lambda x: x[1])
  1057.             strategy = "VYVÁŽENÁ"
  1058.        
  1059.         best_move, best_score, best_algebraic = best_move_data
  1060.        
  1061.         print(f"\nStrategie: {strategy}")
  1062.         print(f"Nejlepší tah: {best_algebraic}")
  1063.         print(f"Ohodnocení: {best_score:+.2f}")
  1064.        
  1065.         # Ukázat pozici po nejlepším tahu
  1066.         final_board = board.copy()
  1067.         final_board.make_move(best_move[0], best_move[1])
  1068.         self.print_position_info(final_board, f"Po tahu {best_algebraic}")
  1069.        
  1070.         return best_move, best_score
  1071.    
  1072.     def find_best_move_recursive(self, board, depth=6):
  1073.         """Find best move using recursive minimax - FIXED logic for fairy pieces"""
  1074.         depth_start_time = time.time()
  1075.        
  1076.         print(f"\nREKURZIVNÍ ANALÝZA (hloubka {depth})")
  1077.         print("Optimalizováno pro pohádkové figury")
  1078.        
  1079.         nodes_before = self.nodes_evaluated
  1080.         self.current_search_depth = depth
  1081.        
  1082.         legal_moves = self.generate_legal_moves(board)
  1083.        
  1084.         if not legal_moves:
  1085.             print("Žádné legální tahy")
  1086.             return None
  1087.        
  1088.         print(f"Analyzuji {len(legal_moves)} tahů...")
  1089.        
  1090.         # FIXED: Determine strategy based on material advantage
  1091.         stronger_side = self.determine_stronger_side(board)
  1092.         current_color = 'w' if board.turn else 'b'
  1093.        
  1094.         # CRITICAL FIX: Stronger side should ALWAYS maximize their advantage
  1095.         if stronger_side == current_color:
  1096.             strategy = "AGRESIVNÍ (hledáme mat)"
  1097.             # Stronger side wants to MAXIMIZE evaluation (find highest value)
  1098.             best_value = float('-inf')
  1099.             is_maximizing_search = True
  1100.         elif stronger_side is not None:
  1101.             strategy = "DEFENZIVNÍ (zdržujeme)"
  1102.             # Weaker side wants to MINIMIZE opponent's advantage (find lowest value)
  1103.             best_value = float('inf')
  1104.             is_maximizing_search = False
  1105.         else:
  1106.             strategy = "VYVÁŽENÁ"
  1107.             # Standard minimax: white maximizes, black minimizes
  1108.             if board.turn:  # White
  1109.                 best_value = float('-inf')
  1110.                 is_maximizing_search = True
  1111.             else:  # Black
  1112.                 best_value = float('inf')
  1113.                 is_maximizing_search = False
  1114.        
  1115.         print(f"Strategie: {strategy}")
  1116.        
  1117.         best_move = None
  1118.        
  1119.         # FIXED: Consistent move evaluation logic
  1120.         for move in legal_moves:
  1121.             temp_board = board.copy()
  1122.             temp_board.make_move(move[0], move[1])
  1123.            
  1124.             # Always call minimax from opponent's perspective
  1125.             move_value = self.minimax_with_fairy_optimization(
  1126.                 temp_board, depth - 1, float('-inf'), float('inf'), not board.turn)
  1127.            
  1128.             # FIXED: Select best move based on consistent strategy
  1129.             move_is_better = False
  1130.            
  1131.             if is_maximizing_search:
  1132.                 # Want higher values (better for current player)
  1133.                 if move_value > best_value:
  1134.                     move_is_better = True
  1135.             else:
  1136.                 # Want lower values (less bad for current player)
  1137.                 if move_value < best_value:
  1138.                     move_is_better = True
  1139.            
  1140.             if move_is_better:
  1141.                 best_value = move_value
  1142.                 best_move = move
  1143.                 algebraic = move_to_algebraic(board, move[0], move[1])
  1144.                 print(f"Nový nejlepší: {algebraic} ({move_value:.1f})")
  1145.        
  1146.         # Calculate timing for this depth
  1147.         depth_duration = time.time() - depth_start_time
  1148.         nodes_for_depth = self.nodes_evaluated - nodes_before
  1149.         self.depth_times[depth] = depth_duration
  1150.        
  1151.         print(f"Dokončeno za {depth_duration:.1f}s")
  1152.        
  1153.         # FIXED: Avoid division by zero
  1154.         if depth_duration > 0:
  1155.             nodes_per_sec = nodes_for_depth / depth_duration
  1156.             print(f"Evaluováno {nodes_for_depth} uzlů ({nodes_per_sec:.0f}/s)")
  1157.         else:
  1158.             print(f"Evaluováno {nodes_for_depth} uzlů (příliš rychlé pro měření)")
  1159.            
  1160.         print(f"Cache obsahuje {len(self.transposition_table)} pozic")
  1161.        
  1162.         # Print intermediate total time
  1163.         self.print_intermediate_time(f"Hloubka {depth} dokončena")
  1164.        
  1165.         if best_move:
  1166.             best_algebraic = move_to_algebraic(board, best_move[0], best_move[1])
  1167.             print(f"Nejlepší tah: {best_algebraic}")
  1168.             print(f"Ohodnocení: {best_value:.1f}")
  1169.            
  1170.             # FIXED: Correct mate interpretation with proper move counting
  1171.             if abs(best_value) > 9000:
  1172.                 mate_in = int(10000 - abs(best_value))
  1173.                 # Add 1 because we count the move we're about to make
  1174.                 actual_mate_in = mate_in + 1
  1175.                 if best_value > 0:
  1176.                     print(f"🎯 MAT za {actual_mate_in} tah{'ů' if actual_mate_in > 1 else ''}!")
  1177.                 else:
  1178.                     print(f"🛡️  Obrana {actual_mate_in} tah{'ů' if actual_mate_in > 1 else ''}")
  1179.             elif abs(best_value) < 0.5:
  1180.                 print("⚖️  Vyrovnaná pozice")
  1181.             elif best_value > 2:
  1182.                 print("💪 Velká výhoda")
  1183.             elif best_value > 0:
  1184.                 print(f"👍 Mírná výhoda (+{best_value:.1f})")
  1185.             elif best_value < -2:
  1186.                 print("😰 Velká nevýhoda")
  1187.             else:
  1188.                 print(f"👎 Mírná nevýhoda ({best_value:.1f})")
  1189.        
  1190.         return best_move, best_value
  1191.    
  1192.     def analyze_position_recursive(self, max_depth=6):
  1193.         """Complete recursive analysis with FIXED evaluation logic"""
  1194.         recursive_start_time = time.time()
  1195.        
  1196.         board = ChessBoard(self.start_fen)
  1197.        
  1198.         print("=== REKURZIVNÍ ANALÝZA POHÁDKOVÉ POZICE ===")
  1199.         self.print_position_info(board, "Analyzovaná pozice")
  1200.        
  1201.         # Material analysis
  1202.         material_diff = self.evaluate_material(board)
  1203.         stronger_side = self.determine_stronger_side(board)
  1204.         print(f"Materiál: {material_diff:+.1f} (silnější: {stronger_side or 'vyrovnané'})")
  1205.        
  1206.         # Check if already terminal
  1207.         terminal_result = self.is_terminal_position(board)
  1208.         if terminal_result:
  1209.             result_type, moves_to_end = terminal_result
  1210.             print(f"🏁 Terminální pozice: {result_type}")
  1211.             return None
  1212.        
  1213.         # Count fairy pieces for complexity estimate
  1214.         fairy_count = 0
  1215.         for rank in range(8):
  1216.             for file in range(8):
  1217.                 piece = board.board[rank][file]
  1218.                 if piece and piece[1] in ['A', 'C', 'E']:
  1219.                     fairy_count += 1
  1220.        
  1221.         if fairy_count > 0:
  1222.             print(f"🧚 Pohádkových figur: {fairy_count} (složitost: vysoká)")
  1223.        
  1224.         # FIXED: Store current search depth for mate distance calculation
  1225.         self.current_search_depth = 0
  1226.        
  1227.         # Reset timing for this analysis
  1228.         total_nodes_start = self.nodes_evaluated
  1229.        
  1230.         # Iterative deepening search
  1231.         best_result = None
  1232.        
  1233.         for depth in range(1, max_depth + 1):
  1234.             depth_start_time = time.time()
  1235.            
  1236.             print(f"\n📊 HLOUBKA {depth}")
  1237.             print("-" * 20)
  1238.            
  1239.             try:
  1240.                 # FIXED: Set current search depth before each iteration
  1241.                 self.current_search_depth = depth
  1242.                
  1243.                 result = self.find_best_move_recursive(board, depth)
  1244.                 if result:
  1245.                     best_move, best_value = result
  1246.                     best_result = result
  1247.                    
  1248.                     # Track depth completion time
  1249.                     depth_duration = time.time() - depth_start_time
  1250.                     self.print_intermediate_time(f"Kompletní hloubka {depth} ({depth_duration:.1f}s)")
  1251.                    
  1252.                     # FIXED: Early termination for forced mates with correct calculation
  1253.                     if abs(best_value) > 9000:
  1254.                         mate_in = int(10000 - abs(best_value)) + 1  # +1 for the move we make
  1255.                         print(f"\n🚀 NUCENÝ MAT za {mate_in} tah{'ů' if mate_in > 1 else ''}! (hloubka {depth})")
  1256.                        
  1257.                         # Show the matting move position
  1258.                         temp_board = board.copy()
  1259.                         temp_board.make_move(best_move[0], best_move[1])
  1260.                         algebraic = move_to_algebraic(board, best_move[0], best_move[1])
  1261.                         self.print_position_info(temp_board, f"Po maticím tahu {algebraic}")
  1262.                        
  1263.                         # FIXED: Don't stop too early, let's see if there are quicker mates
  1264.                         if depth >= 3 and mate_in <= 2:  # Found mate in 1-2, can stop
  1265.                             break
  1266.                    
  1267.                     # Show position after best move for deeper searches
  1268.                     elif depth >= 3:
  1269.                         temp_board = board.copy()
  1270.                         temp_board.make_move(best_move[0], best_move[1])
  1271.                         algebraic = move_to_algebraic(board, best_move[0], best_move[1])
  1272.                         self.print_position_info(temp_board, f"Po tahu {algebraic}")
  1273.                        
  1274.             except KeyboardInterrupt:
  1275.                 print("⏹️  Analýza přerušena uživatelem")
  1276.                 break
  1277.             except Exception as e:
  1278.                 print(f"❌ Chyba na hloubce {depth}: {e}")
  1279.                 import traceback
  1280.                 traceback.print_exc()
  1281.                 break
  1282.        
  1283.         # Calculate total recursive analysis time
  1284.         recursive_duration = time.time() - recursive_start_time
  1285.         total_nodes_analyzed = self.nodes_evaluated - total_nodes_start
  1286.        
  1287.         print(f"\n🎯 FINÁLNÍ VÝSLEDEK")
  1288.         print("=" * 40)
  1289.        
  1290.         # Print timing summary for recursive analysis
  1291.         print(f"⏱️  ČASOVÝ PŘEHLED REKURZIVNÍ ANALÝZY:")
  1292.         print(f"   Celkový čas: {recursive_duration:.1f}s")
  1293.         print(f"   Uzlů celkem: {total_nodes_analyzed:,}")
  1294.        
  1295.         # FIXED: Avoid division by zero
  1296.         if recursive_duration > 0:
  1297.             print(f"   Rychlost: {total_nodes_analyzed/recursive_duration:.0f} uzlů/s")
  1298.         else:
  1299.             print(f"   Rychlost: >1000000 uzlů/s (příliš rychlé pro měření)")
  1300.        
  1301.         if self.depth_times:
  1302.             print(f"   Časy podle hloubky:")
  1303.             for depth, duration in self.depth_times.items():
  1304.                 print(f"     Hloubka {depth}: {duration:.1f}s")
  1305.        
  1306.         if best_result:
  1307.             best_move, best_value = best_result
  1308.             algebraic = move_to_algebraic(board, best_move[0], best_move[1])
  1309.            
  1310.             print(f"Doporučený tah: {algebraic}")
  1311.             print(f"Konečné ohodnocení: {best_value:.1f}")
  1312.            
  1313.             # Show final position
  1314.             final_board = board.copy()
  1315.             final_board.make_move(best_move[0], best_move[1])
  1316.             self.print_position_info(final_board, f"Výsledná pozice")
  1317.            
  1318.             return best_result
  1319.         else:
  1320.             print("❌ Analýza nebyla úspěšná")
  1321.             return None
  1322.    
  1323.     def analyze_position_with_mate_sequence(self, max_depth=6):
  1324.         """Analyze position and if mate is found, show complete sequence - FIXED VERSION"""
  1325.         # Start total timing
  1326.         self.start_timing("Kompletní analýza pozice")
  1327.        
  1328.         print("🔍 Spouštím základní analýzu pozice...")
  1329.        
  1330.         # First do regular analysis
  1331.         result = self.analyze_position_recursive(max_depth)
  1332.        
  1333.         sequence = None
  1334.         if result:
  1335.             best_move, best_value = result
  1336.            
  1337.             print(f"\n📊 VÝSLEDEK ZÁKLADNÍ ANALÝZY:")
  1338.             print(f"   Nejlepší tah: {move_to_algebraic(ChessBoard(self.start_fen), best_move[0], best_move[1])}")
  1339.             print(f"   Ohodnocení: {best_value:.1f}")
  1340.             print(f"   Je to mat?: {abs(best_value) > 9000}")
  1341.            
  1342.             # FIXED: Always analyze mate sequence if evaluation suggests mate OR if we want to verify
  1343.             if abs(best_value) > 9000:
  1344.                 mate_in = int(10000 - abs(best_value)) + 1
  1345.                 print(f"\n🔍 NALEZEN MAT ZA {mate_in} TAH{'ů' if mate_in > 1 else ''}!")
  1346.                 print("🎯 ANALYZUJI KOMPLETNÍ MATOVOU SEKVENCI...")
  1347.                 self.print_intermediate_time("Začátek analýzy matové sekvence")
  1348.                
  1349.                 # FIXED: Use larger depth to ensure we see the complete sequence
  1350.                 sequence_depth = max(10, mate_in * 3)
  1351.                 print(f"🔧 Použije hloubku {sequence_depth} pro matovou sekvenci")
  1352.                
  1353.                 # Analyze complete mate sequence
  1354.                 sequence = self.analyze_mate_sequence(max_depth=sequence_depth)
  1355.                
  1356.                 if sequence:
  1357.                     print(f"✅ Matová sekvence nalezena s {len(sequence)} kroky")
  1358.                 else:
  1359.                     print("❌ Matová sekvence se nepodařila analyzovat")
  1360.             else:
  1361.                 print(f"\n📊 Ohodnocení {best_value:.1f} nenaznačuje nucený mat")
  1362.                 print("🤔 Zkusím analyzovat sekvenci alespoň 5 kroků pro ověření...")
  1363.                
  1364.                 # Even if not mate, try to analyze a few moves to see what happens
  1365.                 sequence = self.analyze_mate_sequence(max_depth=5)
  1366.         else:
  1367.             print("❌ Základní analýza nevrátila žádný výsledek")
  1368.        
  1369.         # Stop total timing
  1370.         self.total_analysis_time = self.stop_timing("Kompletní analýza pozice")
  1371.        
  1372.         return result, sequence
  1373.    
  1374.     def analyze_mate_sequence(self, max_depth=10):
  1375.         """ZCELA NOVÁ VERZE - zaručeně vypisuje všechny pozice až do skutečného matu"""
  1376.         mate_sequence_start = time.time()
  1377.        
  1378.         print(f"\n🎯 ZAČÍNÁM ANALÝZU MATOVÉ SEKVENCE (max {max_depth} kroků)")
  1379.         print("="*60)
  1380.         print("🔥 BUDU POKRAČOVAT AŽ DO SKUTEČNÉHO CHECKMATE!")
  1381.        
  1382.         board = ChessBoard(self.start_fen)
  1383.        
  1384.         # KROK 0: Zobraz výchozí pozici
  1385.         print(f"\n📍 KROK 0 - VÝCHOZÍ POZICE")
  1386.         print_ascii_board(board, "Výchozí pozice")
  1387.         print(f"FEN: {board.get_fen()}")
  1388.         print(f"Na tahu: {'Bílý' if board.turn else 'Černý'}")
  1389.        
  1390.         sequence = []
  1391.         current_board = board.copy()
  1392.         step = 0
  1393.        
  1394.         # Hlavní smyčka - pokračuj až do matu
  1395.         while step < max_depth:
  1396.             step += 1
  1397.            
  1398.             print(f"\n{'='*60}")
  1399.             print(f"📊 KROK {step}")
  1400.             print(f"Na tahu: {'🔵 BÍLÝ' if current_board.turn else '🔴 ČERNÝ'}")
  1401.             print("="*60)
  1402.            
  1403.             # 1. ZKONTROLUJ AKTUÁLNÍ STAV
  1404.             current_color = 'w' if current_board.turn else 'b'
  1405.             legal_moves = self.generate_legal_moves(current_board)
  1406.             is_in_check = current_board.is_check(current_color)
  1407.            
  1408.             print(f"🔍 STAV POZICE:")
  1409.             print(f"   Hráč na tahu: {current_color.upper()}")
  1410.             print(f"   Počet legálních tahů: {len(legal_moves)}")
  1411.             print(f"   Je v šachu: {is_in_check}")
  1412.            
  1413.             # 2. KONTROLA KONCE HRY
  1414.             if len(legal_moves) == 0:
  1415.                 if is_in_check:
  1416.                     print(f"\n🎉 CHECKMATE! {current_color.upper()} nemá legální tahy a je v šachu!")
  1417.                     print(f"🏁 MATOVÁ SEKVENCE DOKONČENA po {step-1} krocích")
  1418.                     break
  1419.                 else:
  1420.                     print(f"\n🤝 PAT! {current_color.upper()} nemá legální tahy ale není v šachu")
  1421.                     print(f"🏁 Sekvence končí patem po {step-1} krocích")
  1422.                     break
  1423.            
  1424.             # 3. ZOBRAZ DOSTUPNÉ TAHY
  1425.             print(f"\n📋 DOSTUPNÉ TAHY PRO {current_color.upper()}:")
  1426.             for i, move in enumerate(legal_moves[:8], 1):  # Show first 8 moves
  1427.                 move_alg = move_to_algebraic(current_board, move[0], move[1])
  1428.                 print(f"   {i}. {move_alg}", end="")
  1429.                 if i % 4 == 0:
  1430.                     print()
  1431.                 else:
  1432.                     print("", end="  ")
  1433.             if len(legal_moves) > 8:
  1434.                 print(f"   ... a dalších {len(legal_moves) - 8} tahů")
  1435.             elif len(legal_moves) % 4 != 0:
  1436.                 print()
  1437.            
  1438.             # 4. NAJDI NEJLEPŠÍ TAH
  1439.             print(f"\n🎯 HLEDÁM NEJLEPŠÍ TAH...")
  1440.            
  1441.             # Use simple search for mate sequence
  1442.             self.current_search_depth = 3  # Keep it simple for sequence
  1443.            
  1444.             # Reset nodes for this step
  1445.             nodes_before = self.nodes_evaluated
  1446.             step_start = time.time()
  1447.            
  1448.             result = self.find_best_move_recursive(current_board, depth=3)
  1449.            
  1450.             step_time = time.time() - step_start
  1451.             nodes_this_step = self.nodes_evaluated - nodes_before
  1452.            
  1453.             if not result:
  1454.                 print("❌ NEPODAŘILO SE NAJÍT TAH - končím analýzu")
  1455.                 break
  1456.                
  1457.             best_move, best_value = result
  1458.             algebraic = move_to_algebraic(current_board, best_move[0], best_move[1])
  1459.            
  1460.             print(f"✅ NEJLEPŠÍ TAH: {algebraic}")
  1461.             print(f"📊 Ohodnocení: {best_value:.1f}")
  1462.            
  1463.             # FIXED: Avoid division by zero in step timing
  1464.             if step_time > 0:
  1465.                 print(f"⏱️  Čas: {step_time:.1f}s, Uzlů: {nodes_this_step} ({nodes_this_step/step_time:.0f}/s)")
  1466.             else:
  1467.                 print(f"⏱️  Čas: {step_time:.1f}s, Uzlů: {nodes_this_step} (příliš rychlé)")
  1468.  
  1469.            
  1470.             # 5. PROVEĎ TAH A ULOŽ INFORMACE
  1471.             move_info = {
  1472.                 'step': step,
  1473.                 'move': algebraic,
  1474.                 'from_pos': best_move[0],
  1475.                 'to_pos': best_move[1],
  1476.                 'evaluation': best_value,
  1477.                 'color': 'Bílý' if current_board.turn else 'Černý',
  1478.                 'fen_before': current_board.get_fen(),
  1479.                 'legal_moves_before': len(legal_moves)
  1480.             }
  1481.            
  1482.             print(f"\n🎯 PROVÁDÍM TAH: {algebraic}")
  1483.             current_board.make_move(best_move[0], best_move[1])
  1484.             move_info['fen_after'] = current_board.get_fen()
  1485.             sequence.append(move_info)
  1486.            
  1487.             # 6. ZOBRAZ POZICI PO TAHU
  1488.             print(f"\n📍 POZICE PO TAHU {algebraic}:")
  1489.             print_ascii_board(current_board, f"Po tahu {step}. {algebraic}")
  1490.             print(f"FEN: {current_board.get_fen()}")
  1491.            
  1492.             # 7. ZKONTROLUJ STAV PO TAHU
  1493.             next_color = 'w' if current_board.turn else 'b'
  1494.             next_legal_moves = self.generate_legal_moves(current_board)
  1495.             next_in_check = current_board.is_check(next_color)
  1496.            
  1497.             print(f"\n🔍 STAV PO TAHU:")
  1498.             print(f"   Nyní na tahu: {next_color.upper()}")
  1499.             print(f"   Legální tahy: {len(next_legal_moves)}")
  1500.             print(f"   Je v šachu: {next_in_check}")
  1501.            
  1502.             if len(next_legal_moves) == 0:
  1503.                 if next_in_check:
  1504.                     print(f"\n🎉 TO JE MAT! {next_color.upper()} nemá kam táhnout a je v šachu!")
  1505.                     print(f"🏁 CHECKMATE po tahu {algebraic}!")
  1506.                     break
  1507.                 else:
  1508.                     print(f"\n🤝 TO JE PAT! {next_color.upper()} nemá kam táhnout ale není v šachu")
  1509.                     break
  1510.             else:
  1511.                 print(f"✅ Hra pokračuje - {next_color.upper()} má {len(next_legal_moves)} možností")
  1512.            
  1513.             self.print_intermediate_time(f"Krok {step} hotov")
  1514.            
  1515.             # Safety break
  1516.             if step >= 15:
  1517.                 print("⚠️ Dosažen bezpečnostní limit - ukončuji analýzu")
  1518.                 break
  1519.        
  1520.         # VÝSLEDKY
  1521.         self.mate_sequence_time = time.time() - mate_sequence_start
  1522.        
  1523.         print(f"\n{'='*60}")
  1524.         print("📋 SHRNUTÍ MATOVÉ SEKVENCE")
  1525.         print("="*60)
  1526.        
  1527.         if sequence:
  1528.             print(f"🎯 ANALYZOVÁNO {len(sequence)} KROKŮ:")
  1529.             for i, move_data in enumerate(sequence, 1):
  1530.                 print(f"   {i}. {move_data['color']}: {move_data['move']} ({move_data['evaluation']:+.1f})")
  1531.            
  1532.             print(f"\n📊 DETAILY:")
  1533.             for move_data in sequence:
  1534.                 print(f"\nKrok {move_data['step']}: {move_data['move']}")
  1535.                 print(f"   FEN před: {move_data['fen_before']}")
  1536.                 print(f"   FEN po:   {move_data['fen_after']}")
  1537.         else:
  1538.             print("❌ Žádná sekvence nebyla zaznamenána")
  1539.        
  1540.         print(f"\n🏆 STATISTIKY:")
  1541.         print(f"📊 Kroků celkem: {len(sequence)}")
  1542.         print(f"⏱️  Celkový čas: {self.mate_sequence_time:.1f}s")
  1543.        
  1544.         return sequence
  1545.    
  1546.     def analyze_position(self, max_depth=6):
  1547.         """Main analysis method - uses recursive search"""
  1548.         return self.analyze_position_recursive(max_depth)
  1549.    
  1550.     def analyze_position(self, max_depth=6):
  1551.         """Analyze the starting position with minimal output"""
  1552.         board = ChessBoard(self.start_fen)
  1553.        
  1554.         print("=== ANALÝZA POZICE ===")
  1555.         self.print_position_info(board, "Výchozí pozice")
  1556.        
  1557.         # Check if position is already terminal
  1558.         terminal_result = self.is_terminal_position(board)
  1559.         if terminal_result:
  1560.             result_type, moves_to_end = terminal_result
  1561.             print(f"Terminální pozice: {result_type}")
  1562.             return None
  1563.        
  1564.         # Progressive depth search
  1565.         best_result = None
  1566.         for depth in range(1, max_depth + 1):
  1567.             print(f"\n--- HLOUBKA {depth} ---")
  1568.            
  1569.             try:
  1570.                 result = self.find_best_move(board, depth)
  1571.                 if result:
  1572.                     best_move, best_value = result
  1573.                     best_result = result
  1574.                    
  1575.                     # If we found a forced mate, we can stop
  1576.                     if abs(best_value) > 9000:
  1577.                         mate_in = int((10000 - abs(best_value)))
  1578.                         print(f"NUCENÝ MAT za {mate_in} tahů!")
  1579.                         if depth >= 4:
  1580.                             break
  1581.                 else:
  1582.                     print(f"Žádný výsledek pro hloubku {depth}")
  1583.                    
  1584.             except Exception as e:
  1585.                 print(f"Chyba na hloubce {depth}: {e}")
  1586.                 break
  1587.        
  1588.         print(f"\n=== FINÁLNÍ VÝSLEDEK ===")
  1589.        
  1590.         if best_result:
  1591.             best_move, best_value = best_result
  1592.             algebraic = move_to_algebraic(board, best_move[0], best_move[1])
  1593.            
  1594.             print(f"Doporučený tah: {algebraic}")
  1595.             print(f"Ohodnocení: {best_value}")
  1596.            
  1597.             # Show final position
  1598.             final_board = board.copy()
  1599.             final_board.make_move(best_move[0], best_move[1])
  1600.             self.print_position_info(final_board, f"Po tahu {algebraic}")
  1601.            
  1602.             # Interpret the evaluation
  1603.             if abs(best_value) > 9000:
  1604.                 mate_in = int((10000 - abs(best_value)))
  1605.                 if best_value > 0:
  1606.                     print(f"Mat za {mate_in} tahů")
  1607.                 else:
  1608.                     print(f"Obrana {mate_in} tahů")
  1609.             elif abs(best_value) < 0.1:
  1610.                 print("Vyrovnaná pozice")
  1611.             elif best_value > 0:
  1612.                 print(f"Výhoda (+{best_value:.1f})")
  1613.             else:
  1614.                 print(f"Nevýhoda ({best_value:.1f})")
  1615.            
  1616.             return best_result
  1617.         else:
  1618.             print("Analýza selhala")
  1619.             return None
  1620.  
  1621.  
  1622. # Test the enhanced analyzer with minimal output
  1623. if __name__ == "__main__":
  1624.     # Test positions
  1625.     test_positions = {
  1626.         1: ("Jednoduchý mat - Věž + Dáma", "5K1k/8/5R2/8/2Q5/8/8/8 w - - 0 1"),
  1627.         2: ("Amazonka vs malé figury", "8/8/8/8/A7/4c1k1/8/6K1 w - - 0 1"),
  1628.         3: ("Složitý endgame", "8/6K1/3b4/4n1k1/8/8/8/8 w - - 0 1"),
  1629.         4: ("Slabá Amazonka", "8/6k1/1A6/8/3K4/8/8/8 w - - 0 1"),
  1630.         5: ("Cyril vs Král", "8/8/8/3k4/8/3C4/8/3K4 w - - 0 1"),
  1631.         6: ("Eve + Pěšec", "8/1P6/8/3k4/8/3E4/8/3K4 w - - 0 1")
  1632.     }
  1633.    
  1634.     print("POHÁDKOVÝ ŠACHOVÝ ENGINE")
  1635.     print("Pohádkové figury: A=Amazonka(Q+N), C=Cyril(R+N), E=Eve(B+N)")
  1636.     print("="*50)
  1637.    
  1638.     print("\nTestovací pozice:")
  1639.     for num, (name, fen) in test_positions.items():
  1640.         print(f"{num}. {name}")
  1641.        
  1642.         # Simple board display with coordinates
  1643.         rows = fen.split()[0].split("/")
  1644.         for i, row in enumerate(rows):
  1645.             line = ""
  1646.             for char in row:
  1647.                 if char.isdigit():
  1648.                     line += "." * int(char)
  1649.                 else:
  1650.                     line += char
  1651.             print(f"   {8-i} {line}")
  1652.         print(f"     abcdefgh")
  1653.         print()
  1654.    
  1655.     # Select test position
  1656.     selected = 2  # Amazon vs small pieces
  1657.     name, fen = test_positions[selected]
  1658.    
  1659.     print(f"Analyzuji pozici {selected}: {name}")
  1660.     print(f"FEN: {fen}")
  1661.     print("="*50)
  1662.    
  1663. def verify_mate_in_one(fen, expected_move):
  1664.     """Verify that expected move is indeed mate in one"""
  1665.     board = ChessBoard(fen)
  1666.    
  1667.     # Parse expected move (e.g., "Aa1")
  1668.     if len(expected_move) >= 3:
  1669.         piece_type = expected_move[0].upper()
  1670.         to_square = expected_move[1:]
  1671.        
  1672.         # Convert to coordinates
  1673.         to_file = ord(to_square[0]) - ord('a')
  1674.         to_rank = int(to_square[1]) - 1
  1675.         to_pos = (to_rank, to_file)
  1676.        
  1677.         # Find piece that can make this move
  1678.         for rank in range(8):
  1679.             for file in range(8):
  1680.                 piece = board.board[rank][file]
  1681.                 if piece and piece[1] == piece_type and piece[0] == ('w' if board.turn else 'b'):
  1682.                     from_pos = (rank, file)
  1683.                    
  1684.                     # Check if this move is legal
  1685.                     analyzer = EnhancedFairyChessAnalyzer(fen)
  1686.                     if analyzer.is_move_legal(board, from_pos, to_pos):
  1687.                         # Make the move
  1688.                         temp_board = board.copy()
  1689.                         temp_board.make_move(from_pos, to_pos)
  1690.                        
  1691.                         # Check if opponent is in checkmate
  1692.                         opponent_color = 'b' if board.turn else 'w'
  1693.                         if temp_board.is_check(opponent_color):
  1694.                             # Check if opponent has any legal moves
  1695.                             opponent_moves = analyzer.generate_legal_moves(temp_board)
  1696.                             if not opponent_moves:
  1697.                                 print(f"✅ OVĚŘENO: {expected_move} je skutečně mat v 1 tahu")
  1698.                                 return True
  1699.                             else:
  1700.                                 print(f"❌ {expected_move} dává šach, ale není to mat")
  1701.                                 return False
  1702.                         else:
  1703.                             print(f"❌ {expected_move} nedává ani šach")
  1704.                             return False
  1705.    
  1706.     print(f"❌ Tah {expected_move} není možný v této pozici")
  1707.     return False
  1708.  
  1709.  
  1710. # Enhanced fairy chess engine with recursive search focus
  1711. if __name__ == "__main__":
  1712.     # Test positions optimized for fairy piece analysis
  1713.     test_positions = {
  1714.         1: ("Mat s Věží + Dámou", "5K1k/8/5R2/8/2Q5/8/8/8 w - - 0 1"),
  1715.         2: ("Amazonka vs Král+Střelec", "8/8/8/8/A7/4c1k1/8/6K1 w - - 0 1"),
  1716.         3: ("Složitý endgame", "8/6K1/3b4/4n1k1/8/8/8/8 w - - 0 1"),
  1717.         4: ("Amazonka vs Král", "8/6k1/1A6/8/3K4/8/8/8 w - - 0 1"),
  1718.         5: ("Cyril matuje", "8/8/8/3k4/8/3C4/8/3K4 w - - 0 1"),
  1719.         6: ("Eve + Pěšec endgame", "8/1P6/8/3k4/8/3E4/8/3K4 w - - 0 1"),
  1720.         7: ("Všechny pohádkové figury", "r1bqkb1r/pppp1ppp/2n2n2/1B2p3/1A2P3/5N2/PPPP1PcP/RNBQK2R w KQkq - 0 1"),
  1721.         8: ("Amazonka vs Cyril", "8/8/8/3A4/8/3c4/8/3K1k2 w - - 0 1")
  1722.     }
  1723.    
  1724.     print("🧚 REKURZIVNÍ POHÁDKOVÝ ŠACHOVÝ ENGINE")
  1725.     print("Optimalizováno pro hluboké prohledávání")
  1726.     print("Pohádkové figury: A=Amazonka(Q+N), C=Cyril(R+N), E=Eve(B+N)")
  1727.     print("="*60)
  1728.    
  1729.     print("\nTestovací pozice:")
  1730.     for num, (name, fen) in test_positions.items():
  1731.         print(f"{num}. {name}")
  1732.        
  1733.         # Show board with coordinates
  1734.         rows = fen.split()[0].split("/")
  1735.         for i, row in enumerate(rows):
  1736.             line = ""
  1737.             for char in row:
  1738.                 if char.isdigit():
  1739.                     line += "." * int(char)
  1740.                 else:
  1741.                     line += char
  1742.             print(f"   {8-i} {line}")
  1743.         print(f"     abcdefgh")
  1744.         print()
  1745.    
  1746.     # Select position for deep analysis
  1747.     selected = 2  # Amazonka vs small pieces - complex tactics
  1748.     name, fen = test_positions[selected]
  1749.    
  1750.     print(f"🎯 ANALÝZA POZICE {selected}: {name}")
  1751.     print(f"FEN: {fen}")
  1752.     print("="*60)
  1753.    
  1754.     # TESTING: Quick verification of expected result
  1755.     print("🧪 OVĚŘENÍ OČEKÁVANÉHO VÝSLEDKU:")
  1756.     print("Očekávaný nejlepší tah: Aa1 (mat v 1 tahu)")
  1757.     verify_mate_in_one(fen, "Aa1")
  1758.     print("="*60)
  1759.    
  1760.     # Create analyzer instance
  1761.     analyzer = EnhancedFairyChessAnalyzer(fen)
  1762.    
  1763.     # Run recursive analysis with mate sequence tracking
  1764.     print("Spouštím rekurzivní analýzu s matovou sekvencí...")
  1765.     print("Tip: Přerušte Ctrl+C pro rychlejší výsledek")
  1766.    
  1767.     # Start total timing from the very beginning
  1768.     total_start_time = time.time()
  1769.     analyzer.print_time("🚀 ZAČÁTEK KOMPLETNÍ ANALÝZY")
  1770.    
  1771.     # Use the enhanced analysis that shows complete mate sequence
  1772.     analysis_result = analyzer.analyze_position_with_mate_sequence(max_depth=5)
  1773.    
  1774.     if isinstance(analysis_result, tuple):
  1775.         result, mate_sequence = analysis_result
  1776.     else:
  1777.         result = analysis_result
  1778.         mate_sequence = None
  1779.    
  1780.     # Calculate total time including everything
  1781.     total_time = time.time() - total_start_time
  1782.     analyzer.print_time(f"⏹️  KONEC KOMPLETNÍ ANALÝZY (celkem {total_time:.1f}s)")
  1783.    
  1784.     print(f"\n🏆 ZÁVĚREČNÉ SHRNUTÍ")
  1785.     print("="*60)
  1786.    
  1787.     if result:
  1788.         move, evaluation = result
  1789.         from_pos, to_pos = move
  1790.         algebraic = move_to_algebraic(ChessBoard(fen), from_pos, to_pos)
  1791.        
  1792.         print(f"📍 Testovaná pozice: {name}")
  1793.         print(f"🎯 Doporučený tah: {algebraic}")
  1794.         print(f"📊 Finální ohodnocení: {evaluation:.1f}")
  1795.         print(f"🔍 Analyzovaných uzlů: {analyzer.nodes_evaluated:,}")
  1796.         print(f"💾 Pozic v cache: {len(analyzer.transposition_table):,}")
  1797.        
  1798.         # TESTING: Verification of expected result
  1799.         if algebraic == "Aa1":
  1800.             print("✅ SPRÁVNĚ! Engine našel očekávaný tah Aa1")
  1801.         else:
  1802.             print(f"❌ CHYBA! Očekával jsem Aa1, ale engine doporučuje {algebraic}")
  1803.        
  1804.         # Show mate sequence summary if available
  1805.         if mate_sequence:
  1806.             print(f"\n🎯 MATOVÁ SEKVENCE NALEZENA:")
  1807.             print(f"📊 Celkem kroků do matu: {len(mate_sequence)}")
  1808.             print(f"📊 Celkem tahů do matu: {len(mate_sequence)}")
  1809.            
  1810.             print(f"\n📝 SHRNUTÍ MATOVÉ SEKVENCE:")
  1811.             for move_data in mate_sequence:
  1812.                 step = move_data['step']  # FIXED: Use 'step' instead of 'ply'
  1813.                 move = move_data['move']
  1814.                 color = move_data['color']
  1815.                 print(f"  {step}. {color}: {move}")
  1816.        
  1817.         # ENHANCED: Detailed timing statistics
  1818.         print(f"\n⏱️  DETAILNÍ ČASOVÉ STATISTIKY:")
  1819.         print(f"   🕐 Celkový čas analýzy: {total_time:.1f}s")
  1820.         print(f"   🔧 Čas engine operací: {analyzer.total_analysis_time:.1f}s")
  1821.        
  1822.         if hasattr(analyzer, 'mate_sequence_time') and analyzer.mate_sequence_time > 0:
  1823.             print(f"   🎯 Čas matové sekvence: {analyzer.mate_sequence_time:.1f}s")
  1824.             recursive_time = analyzer.total_analysis_time - analyzer.mate_sequence_time
  1825.             print(f"   🔍 Čas rekurzivní analýzy: {recursive_time:.1f}s")
  1826.            
  1827.             # FIXED: Avoid division by zero
  1828.             if analyzer.mate_sequence_time > 0:
  1829.                 ratio = recursive_time / analyzer.mate_sequence_time
  1830.                 print(f"   📊 Poměr času (rekurze/sekvence): {ratio:.1f}:1")
  1831.             else:
  1832.                 print(f"   📊 Matová sekvence byla příliš rychlá pro poměr")
  1833.        
  1834.         if analyzer.depth_times:
  1835.             print(f"   📈 Časy podle hloubky:")
  1836.             total_depth_time = 0
  1837.             for depth in sorted(analyzer.depth_times.keys()):
  1838.                 duration = analyzer.depth_times[depth]
  1839.                 total_depth_time += duration
  1840.                 print(f"      Hloubka {depth}: {duration:.1f}s")
  1841.             print(f"   📊 Celkem všechny hloubky: {total_depth_time:.1f}s")
  1842.        
  1843.         if total_time > 0:
  1844.             print(f"   ⚡ Celková rychlost: {analyzer.nodes_evaluated/total_time:.0f} uzlů/s")
  1845.             efficiency = (analyzer.nodes_evaluated / total_time) / 1000
  1846.             print(f"   🏃 Efektivita: {efficiency:.1f}k uzlů/s")
  1847.         else:
  1848.             print(f"   ⚡ Analýza byla příliš rychlá pro přesné měření rychlosti")
  1849.             print(f"   🏃 Efektivita: >1000k uzlů/s")
  1850.        
  1851.         # Strategic interpretation
  1852.         if abs(evaluation) > 9000:
  1853.             mate_in = int(10000 - abs(evaluation)) + 1  # FIXED: Correct mate counting
  1854.             print(f"🎯 Výsledek: Nucený mat za {mate_in} tah{'ů' if mate_in > 1 else ''}")
  1855.         elif abs(evaluation) > 5:
  1856.             print(f"💪 Výsledek: Rozhodující výhoda")
  1857.         elif abs(evaluation) > 2:
  1858.             print(f"👍 Výsledek: Značná výhoda")
  1859.         elif abs(evaluation) > 0.5:
  1860.             print(f"🤏 Výsledek: Mírná výhoda")
  1861.         else:
  1862.             print(f"⚖️  Výsledek: Vyrovnaná pozice")
  1863.            
  1864.     else:
  1865.         print("❌ Rekurzivní analýza nebyla úspěšná")
  1866.         print("Možné příčiny:")
  1867.         print("- Terminální pozice (mat/pat)")
  1868.         print("- Příliš složitá pozice pro danou hloubku")
  1869.         print("- Chyba v implementaci")
  1870.        
  1871.         # Show timing even for failed analysis
  1872.         if total_time > 0:
  1873.             print(f"\n⏱️  Celkový čas neúspěšné analýzy: {total_time:.1f}s")
  1874.             if analyzer.total_analysis_time > 0:
  1875.                 print(f"   🔧 Čas engine operací: {analyzer.total_analysis_time:.1f}s")
  1876.                
  1877.                 # FIXED: Avoid division by zero for failed analysis
  1878.                 if total_time > 0:
  1879.                     print(f"   ⚡ Rychlost: {analyzer.nodes_evaluated/total_time:.0f} uzlů/s")
  1880.         else:
  1881.             print(f"\n⏱️  Analýza byla příliš rychlá pro měření času")
  1882.             print(f"   🔧 Evaluováno uzlů: {analyzer.nodes_evaluated}")
  1883.    
  1884.     print("="*60)
  1885.     print("✅ OPRAVENÝ ENGINE - správná logika pro silnější/slabší stranu")
  1886.     print("✅ OPRAVENÉ POČÍTÁNÍ - správné tahy do matu")
  1887.     print("✅ MATOVÁ SEKVENCE - kompletní analýza až do matu")
  1888.     print("✅ ČASOVÉ STATISTIKY - detailní tracking všech operací")
  1889.     print("✅ OPTIMALIZACE - rekurzivní prohledávání pro pohádkové figury")
Advertisement
Add Comment
Please, Sign In to add comment