max2201111

excellent 4 OK very good final

Jul 21st, 2025
203
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 34.23 KB | Science | 0 0
  1. import time
  2. import copy
  3. from typing import List, Tuple, Optional, Dict, Set
  4.  
  5. class ChessEngine:
  6.     def __init__(self):
  7.         # Základní nastavení
  8.         self.board = [['' for _ in range(8)] for _ in range(8)]
  9.         self.white_to_move = True
  10.         self.castling_rights = {'K': True, 'Q': True, 'k': True, 'q': True}
  11.         self.en_passant = None
  12.         self.halfmove_clock = 0
  13.         self.fullmove_number = 1
  14.        
  15.         # Hodnoty figur pro evaluaci
  16.         self.piece_values = {
  17.             'P': 100, 'N': 320, 'B': 330, 'R': 500, 'Q': 900, 'K': 20000,
  18.             'p': -100, 'n': -320, 'b': -330, 'r': -500, 'q': -900, 'k': -20000,
  19.             'A': 1200, 'a': -1200,  # Amazonka (kůň + dáma)
  20.             'C': 800, 'c': -800,    # Cyril (kůň + věž)
  21.             'E': 650, 'e': -650     # Eve (kůň + střelec)
  22.         }
  23.        
  24.         # Historie tahů pro výpis cesty
  25.         self.move_history = []
  26.         self.position_history = []
  27.        
  28.     def load_fen(self, fen: str):
  29.         """Načte pozici z FEN stringu"""
  30.         # Nejdříve vymaž šachovnici
  31.         self.board = [['' for _ in range(8)] for _ in range(8)]
  32.        
  33.         parts = fen.split()
  34.        
  35.         # Parsování pozice
  36.         rows = parts[0].split('/')
  37.         for row_idx, row in enumerate(rows):
  38.             if row_idx >= 8:  # Ochrana proti příliš mnoha řádkům
  39.                 break
  40.             col_idx = 0
  41.             for char in row:
  42.                 if col_idx >= 8:  # Ochrana proti překročení sloupců
  43.                     break
  44.                 if char.isdigit():
  45.                     # Prázdná pole
  46.                     empty_squares = int(char)
  47.                     for _ in range(empty_squares):
  48.                         if col_idx < 8:
  49.                             self.board[row_idx][col_idx] = ''
  50.                             col_idx += 1
  51.                 else:
  52.                     self.board[row_idx][col_idx] = char
  53.                     col_idx += 1
  54.        
  55.         # Na tahu
  56.         self.white_to_move = parts[1] == 'w'
  57.        
  58.         # Rošáda
  59.         castling = parts[2] if len(parts) > 2 else '-'
  60.         self.castling_rights = {
  61.             'K': 'K' in castling,
  62.             'Q': 'Q' in castling,
  63.             'k': 'k' in castling,
  64.             'q': 'q' in castling
  65.         }
  66.        
  67.         # En passant
  68.         self.en_passant = parts[3] if len(parts) > 3 and parts[3] != '-' else None
  69.        
  70.         # Počet tahů
  71.         self.halfmove_clock = int(parts[4]) if len(parts) > 4 else 0
  72.         self.fullmove_number = int(parts[5]) if len(parts) > 5 else 1
  73.        
  74.     def to_fen(self) -> str:
  75.         """Převede aktuální pozici na FEN string"""
  76.         # Pozice
  77.         fen_rows = []
  78.         for row in self.board:
  79.             fen_row = ''
  80.             empty_count = 0
  81.             for cell in row:
  82.                 if cell == '':
  83.                     empty_count += 1
  84.                 else:
  85.                     if empty_count > 0:
  86.                         fen_row += str(empty_count)
  87.                         empty_count = 0
  88.                     fen_row += cell
  89.             if empty_count > 0:
  90.                 fen_row += str(empty_count)
  91.             fen_rows.append(fen_row)
  92.        
  93.         board_fen = '/'.join(fen_rows)
  94.        
  95.         # Na tahu
  96.         active_color = 'w' if self.white_to_move else 'b'
  97.        
  98.         # Rošáda
  99.         castling = ''
  100.         if self.castling_rights['K']: castling += 'K'
  101.         if self.castling_rights['Q']: castling += 'Q'
  102.         if self.castling_rights['k']: castling += 'k'
  103.         if self.castling_rights['q']: castling += 'q'
  104.         if not castling: castling = '-'
  105.        
  106.         # En passant
  107.         en_passant = self.en_passant if self.en_passant else '-'
  108.        
  109.         return f"{board_fen} {active_color} {castling} {en_passant} {self.halfmove_clock} {self.fullmove_number}"
  110.    
  111.     def print_board(self):
  112.         """Vypíše šachovnici v ASCII formátu"""
  113.         print("  a b c d e f g h")
  114.         for i in range(8):
  115.             print(f"{8-i} ", end="")
  116.             for j in range(8):
  117.                 piece = self.board[i][j]
  118.                 if piece == '':
  119.                     piece = '.'
  120.                 print(f"{piece} ", end="")
  121.             print(f"{8-i}")
  122.         print("  a b c d e f g h")
  123.         print()
  124.    
  125.     def is_white_piece(self, piece: str) -> bool:
  126.         """Zjistí, zda je figura bílá"""
  127.         return piece.isupper()
  128.    
  129.     def get_piece_moves(self, row: int, col: int, check_castling: bool = True) -> List[Tuple[int, int]]:
  130.         """Získá všechny možné tahy pro figuru na dané pozici"""
  131.         piece = self.board[row][col]
  132.         if piece == '':
  133.             return []
  134.        
  135.         piece_type = piece.lower()
  136.         is_white = self.is_white_piece(piece)
  137.         moves = []
  138.        
  139.         if piece_type == 'p':
  140.             # Pěšec
  141.             direction = -1 if is_white else 1
  142.             start_row = 6 if is_white else 1
  143.            
  144.             # Tah dopředu
  145.             if 0 <= row + direction < 8 and self.board[row + direction][col] == '':
  146.                 moves.append((row + direction, col))
  147.                 # Dvojitý tah z počáteční pozice
  148.                 if row == start_row and self.board[row + 2 * direction][col] == '':
  149.                     moves.append((row + 2 * direction, col))
  150.            
  151.             # Braní úhlopříčně
  152.             for dc in [-1, 1]:
  153.                 new_row, new_col = row + direction, col + dc
  154.                 if 0 <= new_row < 8 and 0 <= new_col < 8:
  155.                     target = self.board[new_row][new_col]
  156.                     if target != '' and self.is_white_piece(target) != is_white:
  157.                         moves.append((new_row, new_col))
  158.                     # En passant
  159.                     elif self.en_passant and self.en_passant == f"{chr(ord('a') + new_col)}{8 - new_row}":
  160.                         moves.append((new_row, new_col))
  161.        
  162.         elif piece_type == 'r':
  163.             # Věž
  164.             directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
  165.             for dr, dc in directions:
  166.                 for i in range(1, 8):
  167.                     new_row, new_col = row + i * dr, col + i * dc
  168.                     if not (0 <= new_row < 8 and 0 <= new_col < 8):
  169.                         break
  170.                     target = self.board[new_row][new_col]
  171.                     if target == '':
  172.                         moves.append((new_row, new_col))
  173.                     else:
  174.                         if self.is_white_piece(target) != is_white:
  175.                             moves.append((new_row, new_col))
  176.                         break
  177.        
  178.         elif piece_type == 'n':
  179.             # Kůň
  180.             knight_moves = [(2, 1), (2, -1), (-2, 1), (-2, -1), (1, 2), (1, -2), (-1, 2), (-1, -2)]
  181.             for dr, dc in knight_moves:
  182.                 new_row, new_col = row + dr, col + dc
  183.                 if 0 <= new_row < 8 and 0 <= new_col < 8:
  184.                     target = self.board[new_row][new_col]
  185.                     if target == '' or self.is_white_piece(target) != is_white:
  186.                         moves.append((new_row, new_col))
  187.        
  188.         elif piece_type == 'b':
  189.             # Střelec
  190.             directions = [(1, 1), (1, -1), (-1, 1), (-1, -1)]
  191.             for dr, dc in directions:
  192.                 for i in range(1, 8):
  193.                     new_row, new_col = row + i * dr, col + i * dc
  194.                     if not (0 <= new_row < 8 and 0 <= new_col < 8):
  195.                         break
  196.                     target = self.board[new_row][new_col]
  197.                     if target == '':
  198.                         moves.append((new_row, new_col))
  199.                     else:
  200.                         if self.is_white_piece(target) != is_white:
  201.                             moves.append((new_row, new_col))
  202.                         break
  203.        
  204.         elif piece_type == 'q':
  205.             # Dáma
  206.             directions = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]
  207.             for dr, dc in directions:
  208.                 for i in range(1, 8):
  209.                     new_row, new_col = row + i * dr, col + i * dc
  210.                     if not (0 <= new_row < 8 and 0 <= new_col < 8):
  211.                         break
  212.                     target = self.board[new_row][new_col]
  213.                     if target == '':
  214.                         moves.append((new_row, new_col))
  215.                     else:
  216.                         if self.is_white_piece(target) != is_white:
  217.                             moves.append((new_row, new_col))
  218.                         break
  219.        
  220.         elif piece_type == 'k':
  221.             # Král
  222.             king_moves = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]
  223.             for dr, dc in king_moves:
  224.                 new_row, new_col = row + dr, col + dc
  225.                 if 0 <= new_row < 8 and 0 <= new_col < 8:
  226.                     target = self.board[new_row][new_col]
  227.                     if target == '' or self.is_white_piece(target) != is_white:
  228.                         moves.append((new_row, new_col))
  229.            
  230.             # Rošáda - pouze pokud je povoleno kontrolovat (vyhneme se rekurzi)
  231.             if check_castling and not self.is_in_check(is_white):
  232.                 # Krátká rošáda
  233.                 castling_key = 'K' if is_white else 'k'
  234.                 if self.castling_rights[castling_key]:
  235.                     if (self.board[row][col + 1] == '' and self.board[row][col + 2] == '' and
  236.                         not self.is_square_attacked(row, col + 1, not is_white) and
  237.                         not self.is_square_attacked(row, col + 2, not is_white)):
  238.                         moves.append((row, col + 2))
  239.                
  240.                 # Dlouhá rošáda
  241.                 castling_key = 'Q' if is_white else 'q'
  242.                 if self.castling_rights[castling_key]:
  243.                     if (self.board[row][col - 1] == '' and self.board[row][col - 2] == '' and
  244.                         self.board[row][col - 3] == '' and
  245.                         not self.is_square_attacked(row, col - 1, not is_white) and
  246.                         not self.is_square_attacked(row, col - 2, not is_white)):
  247.                         moves.append((row, col - 2))
  248.        
  249.         elif piece_type == 'a':  # Amazonka (kůň + dáma)
  250.             # Tahy dámy
  251.             directions = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]
  252.             for dr, dc in directions:
  253.                 for i in range(1, 8):
  254.                     new_row, new_col = row + i * dr, col + i * dc
  255.                     if not (0 <= new_row < 8 and 0 <= new_col < 8):
  256.                         break
  257.                     target = self.board[new_row][new_col]
  258.                     if target == '':
  259.                         moves.append((new_row, new_col))
  260.                     else:
  261.                         if self.is_white_piece(target) != is_white:
  262.                             moves.append((new_row, new_col))
  263.                         break
  264.             # Tahy koně
  265.             knight_moves = [(2, 1), (2, -1), (-2, 1), (-2, -1), (1, 2), (1, -2), (-1, 2), (-1, -2)]
  266.             for dr, dc in knight_moves:
  267.                 new_row, new_col = row + dr, col + dc
  268.                 if 0 <= new_row < 8 and 0 <= new_col < 8:
  269.                     target = self.board[new_row][new_col]
  270.                     if target == '' or self.is_white_piece(target) != is_white:
  271.                         moves.append((new_row, new_col))
  272.        
  273.         elif piece_type == 'c':  # Cyril (kůň + věž)
  274.             # Tahy věže
  275.             directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
  276.             for dr, dc in directions:
  277.                 for i in range(1, 8):
  278.                     new_row, new_col = row + i * dr, col + i * dc
  279.                     if not (0 <= new_row < 8 and 0 <= new_col < 8):
  280.                         break
  281.                     target = self.board[new_row][new_col]
  282.                     if target == '':
  283.                         moves.append((new_row, new_col))
  284.                     else:
  285.                         if self.is_white_piece(target) != is_white:
  286.                             moves.append((new_row, new_col))
  287.                         break
  288.             # Tahy koně
  289.             knight_moves = [(2, 1), (2, -1), (-2, 1), (-2, -1), (1, 2), (1, -2), (-1, 2), (-1, -2)]
  290.             for dr, dc in knight_moves:
  291.                 new_row, new_col = row + dr, col + dc
  292.                 if 0 <= new_row < 8 and 0 <= new_col < 8:
  293.                     target = self.board[new_row][new_col]
  294.                     if target == '' or self.is_white_piece(target) != is_white:
  295.                         moves.append((new_row, new_col))
  296.        
  297.         elif piece_type == 'e':  # Eve (kůň + střelec)
  298.             # Tahy střelce
  299.             directions = [(1, 1), (1, -1), (-1, 1), (-1, -1)]
  300.             for dr, dc in directions:
  301.                 for i in range(1, 8):
  302.                     new_row, new_col = row + i * dr, col + i * dc
  303.                     if not (0 <= new_row < 8 and 0 <= new_col < 8):
  304.                         break
  305.                     target = self.board[new_row][new_col]
  306.                     if target == '':
  307.                         moves.append((new_row, new_col))
  308.                     else:
  309.                         if self.is_white_piece(target) != is_white:
  310.                             moves.append((new_row, new_col))
  311.                         break
  312.             # Tahy koně
  313.             knight_moves = [(2, 1), (2, -1), (-2, 1), (-2, -1), (1, 2), (1, -2), (-1, 2), (-1, -2)]
  314.             for dr, dc in knight_moves:
  315.                 new_row, new_col = row + dr, col + dc
  316.                 if 0 <= new_row < 8 and 0 <= new_col < 8:
  317.                     target = self.board[new_row][new_col]
  318.                     if target == '' or self.is_white_piece(target) != is_white:
  319.                         moves.append((new_row, new_col))
  320.        
  321.         return moves
  322.    
  323.     def is_square_attacked(self, row: int, col: int, by_white: bool) -> bool:
  324.         """Zjistí, zda je pole napadené danou barvou"""
  325.         for r in range(8):
  326.             for c in range(8):
  327.                 piece = self.board[r][c]
  328.                 if piece != '' and self.is_white_piece(piece) == by_white:
  329.                     # Nekontroluji rošádu při detekci napadení (vyhneme se rekurzi)
  330.                     moves = self.get_piece_moves(r, c, check_castling=False)
  331.                     if (row, col) in moves:
  332.                         return True
  333.         return False
  334.    
  335.     def find_king(self, is_white: bool) -> Tuple[int, int]:
  336.         """Najde krále dané barvy"""
  337.         king = 'K' if is_white else 'k'
  338.         for r in range(8):
  339.             for c in range(8):
  340.                 if self.board[r][c] == king:
  341.                     return (r, c)
  342.         return (-1, -1)  # Král nenalezen
  343.    
  344.     def is_in_check(self, is_white: bool) -> bool:
  345.         """Zjistí, zda je král v šachu"""
  346.         king_pos = self.find_king(is_white)
  347.         if king_pos == (-1, -1):
  348.             return False
  349.         return self.is_square_attacked(king_pos[0], king_pos[1], not is_white)
  350.    
  351.     def make_move(self, from_pos: Tuple[int, int], to_pos: Tuple[int, int]) -> bool:
  352.         """Provede tah a vrátí True, pokud je legální"""
  353.         from_row, from_col = from_pos
  354.         to_row, to_col = to_pos
  355.        
  356.         piece = self.board[from_row][from_col]
  357.         if piece == '':
  358.             return False
  359.        
  360.         is_white = self.is_white_piece(piece)
  361.         if is_white != self.white_to_move:
  362.             return False
  363.        
  364.         # Zkontroluj, zda je tah v seznamu možných tahů
  365.         possible_moves = self.get_piece_moves(from_row, from_col)
  366.         if (to_row, to_col) not in possible_moves:
  367.             return False
  368.        
  369.         # Ulož původní stav
  370.         original_board = copy.deepcopy(self.board)
  371.         original_castling = copy.deepcopy(self.castling_rights)
  372.         original_en_passant = self.en_passant
  373.        
  374.         # Proveď tah
  375.         captured_piece = self.board[to_row][to_col]
  376.         self.board[to_row][to_col] = piece
  377.         self.board[from_row][from_col] = ''
  378.        
  379.         # Speciální tahy
  380.         piece_type = piece.lower()
  381.        
  382.         # En passant
  383.         if piece_type == 'p' and self.en_passant and f"{chr(ord('a') + to_col)}{8 - to_row}" == self.en_passant:
  384.             if is_white:
  385.                 self.board[to_row + 1][to_col] = ''
  386.             else:
  387.                 self.board[to_row - 1][to_col] = ''
  388.        
  389.         # Rošáda
  390.         if piece_type == 'k' and abs(to_col - from_col) == 2:
  391.             if to_col > from_col:  # Krátká rošáda
  392.                 self.board[from_row][7] = ''
  393.                 self.board[from_row][5] = 'R' if is_white else 'r'
  394.             else:  # Dlouhá rošáda
  395.                 self.board[from_row][0] = ''
  396.                 self.board[from_row][3] = 'R' if is_white else 'r'
  397.        
  398.         # Aktualizace en passant
  399.         if piece_type == 'p' and abs(to_row - from_row) == 2:
  400.             self.en_passant = f"{chr(ord('a') + from_col)}{8 - (from_row + to_row) // 2}"
  401.         else:
  402.             self.en_passant = None
  403.        
  404.         # Aktualizace rošádových práv
  405.         if piece_type == 'k':
  406.             if is_white:
  407.                 self.castling_rights['K'] = False
  408.                 self.castling_rights['Q'] = False
  409.             else:
  410.                 self.castling_rights['k'] = False
  411.                 self.castling_rights['q'] = False
  412.         elif piece_type == 'r':
  413.             if from_row == 0 or from_row == 7:
  414.                 if from_col == 0:
  415.                     key = 'Q' if from_row == 7 else 'q'
  416.                     self.castling_rights[key] = False
  417.                 elif from_col == 7:
  418.                     key = 'K' if from_row == 7 else 'k'
  419.                     self.castling_rights[key] = False
  420.        
  421.         # Zkontroluj, zda vlastní král není v šachu
  422.         if self.is_in_check(is_white):
  423.             # Vrať původní stav
  424.             self.board = original_board
  425.             self.castling_rights = original_castling
  426.             self.en_passant = original_en_passant
  427.             return False
  428.        
  429.         # Tah je legální
  430.         self.white_to_move = not self.white_to_move
  431.         if not self.white_to_move:
  432.             self.fullmove_number += 1
  433.        
  434.         if captured_piece or piece_type == 'p':
  435.             self.halfmove_clock = 0
  436.         else:
  437.             self.halfmove_clock += 1
  438.        
  439.         return True
  440.    
  441.     def undo_move(self, from_pos: Tuple[int, int], to_pos: Tuple[int, int],
  442.                   captured_piece: str, old_castling: dict, old_en_passant: str,
  443.                   old_halfmove: int, old_fullmove: int, was_white_to_move: bool):
  444.         """Vrátí tah zpět"""
  445.         from_row, from_col = from_pos
  446.         to_row, to_col = to_pos
  447.        
  448.         piece = self.board[to_row][to_col]
  449.         self.board[from_row][from_col] = piece
  450.         self.board[to_row][to_col] = captured_piece
  451.        
  452.         # Vrácení speciálních tahů
  453.         piece_type = piece.lower()
  454.        
  455.         # Rošáda
  456.         if piece_type == 'k' and abs(to_col - from_col) == 2:
  457.             if to_col > from_col:  # Krátká rošáda
  458.                 self.board[from_row][7] = 'R' if self.is_white_piece(piece) else 'r'
  459.                 self.board[from_row][5] = ''
  460.             else:  # Dlouhá rošáda
  461.                 self.board[from_row][0] = 'R' if self.is_white_piece(piece) else 'r'
  462.                 self.board[from_row][3] = ''
  463.        
  464.         # En passant
  465.         if piece_type == 'p' and old_en_passant and f"{chr(ord('a') + to_col)}{8 - to_row}" == old_en_passant:
  466.             if self.is_white_piece(piece):
  467.                 self.board[to_row + 1][to_col] = 'p'
  468.             else:
  469.                 self.board[to_row - 1][to_col] = 'P'
  470.        
  471.         self.castling_rights = old_castling
  472.         self.en_passant = old_en_passant
  473.         self.halfmove_clock = old_halfmove
  474.         self.fullmove_number = old_fullmove
  475.         self.white_to_move = was_white_to_move
  476.    
  477.     def get_all_legal_moves(self) -> List[Tuple[Tuple[int, int], Tuple[int, int]]]:
  478.         """Získá všechny legální tahy pro aktuálního hráče"""
  479.         legal_moves = []
  480.        
  481.         for row in range(8):
  482.             for col in range(8):
  483.                 piece = self.board[row][col]
  484.                 if piece != '' and self.is_white_piece(piece) == self.white_to_move:
  485.                     moves = self.get_piece_moves(row, col)
  486.                     for to_row, to_col in moves:
  487.                         # Zkopíruj stav
  488.                         original_state = self.save_state()
  489.                        
  490.                         # Zkus tah
  491.                         if self.make_move((row, col), (to_row, to_col)):
  492.                             legal_moves.append(((row, col), (to_row, to_col)))
  493.                        
  494.                         # Vrať stav
  495.                         self.restore_state(original_state)
  496.        
  497.         return legal_moves
  498.    
  499.     def save_state(self):
  500.         """Uloží aktuální stav hry"""
  501.         return {
  502.             'board': copy.deepcopy(self.board),
  503.             'white_to_move': self.white_to_move,
  504.             'castling_rights': copy.deepcopy(self.castling_rights),
  505.             'en_passant': self.en_passant,
  506.             'halfmove_clock': self.halfmove_clock,
  507.             'fullmove_number': self.fullmove_number
  508.         }
  509.    
  510.     def restore_state(self, state):
  511.         """Obnoví uložený stav hry"""
  512.         self.board = state['board']
  513.         self.white_to_move = state['white_to_move']
  514.         self.castling_rights = state['castling_rights']
  515.         self.en_passant = state['en_passant']
  516.         self.halfmove_clock = state['halfmove_clock']
  517.         self.fullmove_number = state['fullmove_number']
  518.    
  519.     def get_material_balance(self) -> int:
  520.         """Spočítá materiální vyváženost (pozitivní = výhoda bílého)"""
  521.         balance = 0
  522.         for row in range(8):
  523.             for col in range(8):
  524.                 piece = self.board[row][col]
  525.                 if piece != '' and piece.lower() != 'k':  # Ignoruj krále
  526.                     balance += self.piece_values.get(piece, 0)
  527.         return balance
  528.    
  529.     def evaluate_position(self) -> int:
  530.         """Ohodnotí pozici s lepším rozlišením koncových pozic"""
  531.         # Rychlá kontrola matu/patu před materiálním hodnocením
  532.         if self.is_checkmate():
  533.             if self.white_to_move:  # Bílý v matu -> černý vyhrál
  534.                 return -999999
  535.             else:  # Černý v matu -> bílý vyhrál
  536.                 return 999999
  537.                
  538.         elif self.is_stalemate():
  539.             # Pat: ve vítězné pozici je to neúspěch
  540.             material_balance = self.get_material_balance()
  541.             if material_balance > 300:  # Bílý má výhodu -> pat je velmi špatný
  542.                 return -10000  
  543.             elif material_balance < -300:  # Černý má výhodu -> pat je velmi dobrý pro bílého
  544.                 return 10000
  545.             else:
  546.                 return 0  # Vyrovnaná pozice
  547.        
  548.         # Materiální hodnocení
  549.         score = self.get_material_balance()
  550.        
  551.         # Bonus pro pokročilé koncovky - motivace k matu
  552.         if abs(score) > 500:  # Významná materiální výhoda
  553.             # Penalty za vzdálenost králů (v koncovce chceme krále blízko)
  554.             white_king = self.find_king(True)
  555.             black_king = self.find_king(False)
  556.            
  557.             if white_king != (-1, -1) and black_king != (-1, -1):
  558.                 king_distance = abs(white_king[0] - black_king[0]) + abs(white_king[1] - black_king[1])
  559.                 if score > 0:  # Bílý vede
  560.                     score -= king_distance * 10  # Penalty za vzdálené krále
  561.                 else:  # Černý vede
  562.                     score += king_distance * 10
  563.        
  564.         return score
  565.    
  566.     def is_checkmate(self) -> bool:
  567.         """Zjistí, zda je mat"""
  568.         if not self.is_in_check(self.white_to_move):
  569.             return False
  570.        
  571.         legal_moves = self.get_all_legal_moves()
  572.         return len(legal_moves) == 0
  573.    
  574.     def is_stalemate(self) -> bool:
  575.         """Zjistí, zda je pat"""
  576.         if self.is_in_check(self.white_to_move):
  577.             return False
  578.        
  579.         legal_moves = self.get_all_legal_moves()
  580.         return len(legal_moves) == 0
  581.    
  582.     def is_game_over(self) -> Tuple[bool, str]:
  583.         """Zjistí, zda je hra u konce"""
  584.         if self.is_checkmate():
  585.             winner = "Černý" if self.white_to_move else "Bílý"
  586.             return True, f"Mat! Vyhrál {winner}."
  587.         elif self.is_stalemate():
  588.             return True, "Pat! Remíza."
  589.         elif self.halfmove_clock >= 100:
  590.             return True, "Remíza podle pravidla 50 tahů."
  591.        
  592.         return False, ""
  593.    
  594.     def minimax(self, depth: int, alpha: int, beta: int, maximizing: bool,
  595.                 path: List[str]) -> Tuple[int, List[str]]:
  596.         """Minimax algoritmus s alfa-beta pruningem - OPRAVENO PRO MAT"""
  597.        
  598.         # Kontrola konce hry
  599.         if self.is_checkmate():
  600.             # Mat: kdo vyhrál?
  601.             if self.white_to_move:  # Bílý je na tahu ale je v matu -> černý vyhrál
  602.                 return (-999999 + len(path), path)
  603.             else:  # Černý je na tahu ale je v matu -> bílý vyhrál  
  604.                 return (999999 - len(path), path)
  605.                
  606.         elif self.is_stalemate():
  607.             # NOVÁ LOGIKA: Pat je vždy remíza, ale ve vítězné pozici je to selhání
  608.             material_balance = self.get_material_balance()
  609.            
  610.             if material_balance > 300:  # Bílý má výraznou výhodu
  611.                 return (-10000, path)  # Pat ve vítězné pozici je velmi špatný pro bílého
  612.             elif material_balance < -300:  # Černý má výraznou výhodu  
  613.                 return (10000, path)   # Pat ve vítězné pozici je velmi špatný pro černého
  614.             else:
  615.                 return (0, path)  # Vyrovnaná pozice -> pat je OK
  616.                
  617.         elif self.halfmove_clock >= 100:
  618.             return (0, path)
  619.        
  620.         if depth == 0:
  621.             return (self.evaluate_position(), path)
  622.        
  623.         legal_moves = self.get_all_legal_moves()
  624.        
  625.         if maximizing:
  626.             max_eval = float('-inf')
  627.             best_path = path
  628.            
  629.             for move in legal_moves:
  630.                 # Ulož stav
  631.                 original_state = self.save_state()
  632.                
  633.                 # Proveď tah
  634.                 self.make_move(move[0], move[1])
  635.                 move_notation = f"{chr(ord('a') + move[0][1])}{8 - move[0][0]}-{chr(ord('a') + move[1][1])}{8 - move[1][0]}"
  636.                 new_path = path + [move_notation]
  637.                
  638.                 eval_score, eval_path = self.minimax(depth - 1, alpha, beta, False, new_path)
  639.                
  640.                 if eval_score > max_eval:
  641.                     max_eval = eval_score
  642.                     best_path = eval_path
  643.                
  644.                 # Vrať stav
  645.                 self.restore_state(original_state)
  646.                
  647.                 alpha = max(alpha, eval_score)
  648.                 if beta <= alpha:
  649.                     break
  650.            
  651.             return (max_eval, best_path)
  652.        
  653.         else:
  654.             min_eval = float('inf')
  655.             best_path = path
  656.            
  657.             for move in legal_moves:
  658.                 # Ulož stav
  659.                 original_state = self.save_state()
  660.                
  661.                 # Proveď tah
  662.                 self.make_move(move[0], move[1])
  663.                 move_notation = f"{chr(ord('a') + move[0][1])}{8 - move[0][0]}-{chr(ord('a') + move[1][1])}{8 - move[1][0]}"
  664.                 new_path = path + [move_notation]
  665.                
  666.                 eval_score, eval_path = self.minimax(depth - 1, alpha, beta, True, new_path)
  667.                
  668.                 if eval_score < min_eval:
  669.                     min_eval = eval_score
  670.                     best_path = eval_path
  671.                
  672.                 # Vrať stav
  673.                 self.restore_state(original_state)
  674.                
  675.                 beta = min(beta, eval_score)
  676.                 if beta <= alpha:
  677.                     break
  678.            
  679.             return (min_eval, best_path)
  680.    
  681.     def find_best_move(self, max_depth: int = 10) -> Tuple[Optional[List[str]], int]:
  682.         """Najde nejlepší tah pomocí iterativního prohloubení"""
  683.         print(f"Hledání nejlepšího tahu (maximální hloubka: {max_depth})...")
  684.         print(f"Na tahu: {'Bílý' if self.white_to_move else 'Černý'}")
  685.        
  686.         # Zkontroluj materiální situaci
  687.         material_balance = self.get_material_balance()
  688.         if material_balance > 300:
  689.             print(f"Bílý má materiální výhodu ({material_balance} bodů) - hledám mat!")
  690.         elif material_balance < -300:
  691.             print(f"Černý má materiální výhodu ({-material_balance} bodů) - bráním se!")
  692.         print()
  693.        
  694.         best_path = None
  695.         best_score = 0
  696.        
  697.         for depth in range(1, max_depth + 1):
  698.             start_time = time.time()
  699.            
  700.             # OPRAVA: maximizing musí odpovídat tomu, kdo je na tahu!
  701.             # Bílý maximalizuje (+), černý minimalizuje (-)
  702.             score, path = self.minimax(depth, float('-inf'), float('inf'), self.white_to_move, [])
  703.            
  704.             end_time = time.time()
  705.             elapsed = end_time - start_time
  706.            
  707.             print(f"Hloubka {depth}: skóre {score}, čas {elapsed:.3f}s")
  708.            
  709.             best_path = path
  710.             best_score = score
  711.            
  712.             # Pokud byl nalezen mat, skonči
  713.             if abs(score) > 900000:
  714.                 print(f"Nalezen mat v {len(path)} tazích!")
  715.                 break
  716.                
  717.             # Pokud je skóre příliš nízké ve vítězné pozici, pokračuj v hledání
  718.             if material_balance > 300 and score < -500:
  719.                 print(f"Skóre {score} je příliš nízké pro vítěznou pozici, pokračujem...")
  720.        
  721.         return best_path, best_score
  722.    
  723.     def play_game(self, initial_fen: str = None, max_depth: int = 6):
  724.         """Spustí hru s automatickým hraním"""
  725.         if initial_fen:
  726.             self.load_fen(initial_fen)
  727.         else:
  728.             # Standardní počáteční pozice
  729.             self.load_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
  730.        
  731.         print("=== ŠACHOVÝ ENGINE S NESTANDARDNÍMI FIGURAMI ===")
  732.         print("Legenda figur:")
  733.         print("A/a = Amazonka (Kůň + Dáma)")
  734.         print("C/c = Cyril (Kůň + Věž)")
  735.         print("E/e = Eve (Kůň + Střelec)")
  736.         print()
  737.        
  738.         print("Počáteční pozice:")
  739.         print(f"FEN: {self.to_fen()}")
  740.         self.print_board()
  741.        
  742.         move_count = 0
  743.        
  744.         while True:
  745.             game_over, result = self.is_game_over()
  746.             if game_over:
  747.                 print(result)
  748.                 break
  749.            
  750.             move_count += 1
  751.             print(f"\n=== TAH {move_count} ===")
  752.            
  753.             best_path, score = self.find_best_move(max_depth)
  754.            
  755.             if not best_path:
  756.                 print("Žádný tah nenalezen!")
  757.                 break
  758.            
  759.             # Simuluj celou cestu
  760.             if abs(score) > 900000:
  761.                 print(f"\nNalezená cesta k matu ({len(best_path)} tahů):")
  762.             elif abs(score) > 5000:
  763.                 print(f"\nNalezená silná cesta ({len(best_path)} tahů):")
  764.             elif abs(score) < -5000:
  765.                 print(f"\nVarování: Možný pat v {len(best_path)} tazích!")
  766.             else:
  767.                 print(f"\nNalezená cesta ({len(best_path)} tahů):")
  768.            
  769.             current_engine = ChessEngine()
  770.             current_engine.restore_state(self.save_state())
  771.            
  772.             # Vypíš počáteční pozici
  773.             print(f"\nPočáteční pozice:")
  774.             print(f"FEN: {current_engine.to_fen()}")
  775.             current_engine.print_board()
  776.            
  777.             for i, move_notation in enumerate(best_path):
  778.                 # Parsuj a proveď tah
  779.                 from_pos = (8 - int(move_notation[1]), ord(move_notation[0]) - ord('a'))
  780.                 to_pos = (8 - int(move_notation[4]), ord(move_notation[3]) - ord('a'))
  781.                
  782.                 if not current_engine.make_move(from_pos, to_pos):
  783.                     print("Chyba při provádění tahu!")
  784.                     break
  785.                
  786.                 # Teď vypíš pozici PO provedení tahu
  787.                 print(f"\nTah {i + 1}: {move_notation}")
  788.                 print(f"FEN: {current_engine.to_fen()}")
  789.                 current_engine.print_board()
  790.                
  791.                 game_over, result = current_engine.is_game_over()
  792.                 if game_over:
  793.                     print(f"{result}")
  794.                     return
  795.            
  796.             # Proveď první tah z nalezené cesty
  797.             if best_path:
  798.                 first_move = best_path[0]
  799.                 from_pos = (8 - int(first_move[1]), ord(first_move[0]) - ord('a'))
  800.                 to_pos = (8 - int(first_move[4]), ord(first_move[3]) - ord('a'))
  801.                
  802.                 if self.make_move(from_pos, to_pos):
  803.                     print(f"\nProveden tah: {first_move}")
  804.                 else:
  805.                     print("Chyba při provádění prvního tahu!")
  806.                     break
  807.             else:
  808.                 break
  809.  
  810. # Spuštění enginu
  811. if __name__ == "__main__":
  812.     engine = ChessEngine()
  813.    
  814.     # Testovací pozice - zajímavější matový problém
  815.     # Černý král v rohu, bílá Amazonka a král pro demonstraci síly Amazonky
  816.     test_fen = "k7/8/2A5/8/8/8/8/K7 w - - 0 1"
  817.     test_fen = "7A/8/8/8/8/8/6k1/1K6 w - - 0 1"
  818.  
  819.     test_fen = "8/8/8/8/8/5BN1/5K1k/8 b - - 0 1"
  820.  
  821.     test_fen = "8/8/8/5N2/8/5B1k/5K2/8 b - - 0 1"
  822.    
  823.     print(f"Používám testovací pozici: {test_fen}")
  824.     print("Pozice: Střelec na f3, Kůň na g3, Bílý král na f2, Černý král na h2")
  825.     engine.play_game(test_fen, max_depth=8)
Advertisement
Add Comment
Please, Sign In to add comment