max2201111

excellent 4 OK very good final 2

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