Python Forum
Endgame engine with non-standard figures doesn't behave correctly
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Endgame engine with non-standard figures doesn't behave correctly
#1
I've created a code for chess endgame with non-standard figures Amazon/Eve/Cyril.
Amazon, say, is like Queen and Knight at one piece.
The code is here:

import chess
from typing import Iterator, Optional, Dict, Tuple
from chess import Move, BB_ALL, Bitboard, PieceType, Color
import time
from collections import deque
import threading
 
# Definice nových figur
AMAZON = 7
CYRIL = 8
EVE = 9
 
# Rozšíření seznamu PIECE_SYMBOLS
chess.PIECE_SYMBOLS.append('a')
chess.PIECE_SYMBOLS.append('c')
chess.PIECE_SYMBOLS.append('e')
 
class CustomBoard(chess.Board):
    def __init__(self, fen=None):
        self.amazons_white = chess.BB_EMPTY
        self.amazons_black = chess.BB_EMPTY
        self.cyrils_white = chess.BB_EMPTY
        self.cyrils_black = chess.BB_EMPTY
        self.eves_white = chess.BB_EMPTY
        self.eves_black = chess.BB_EMPTY
        super().__init__(None)
        if fen:
            self.set_custom_fen(fen)
        self.debug_amazons()
        self.debug_cyrils()
        self.debug_eves()
 
    def clear_square(self, square):
        super()._remove_piece_at(square)
        self.amazons_white &= ~chess.BB_SQUARES[square]
        self.amazons_black &= ~chess.BB_SQUARES[square]
        self.cyrils_white &= ~chess.BB_SQUARES[square]
        self.cyrils_black &= ~chess.BB_SQUARES[square]
        self.eves_white &= ~chess.BB_SQUARES[square]
        self.eves_black &= ~chess.BB_SQUARES[square]
 
    def set_custom_fen(self, fen):
        parts = fen.split()
        board_part = parts[0]
    
        self.clear()
        self.amazons_white = chess.BB_EMPTY
        self.amazons_black = chess.BB_EMPTY
        self.cyrils_white = chess.BB_EMPTY
        self.cyrils_black = chess.BB_EMPTY
        self.eves_white = chess.BB_EMPTY
        self.eves_black = chess.BB_EMPTY
    
        square = 56
        for c in board_part:
            if c == '/':
                square -= 16
            elif c.isdigit():
                square += int(c)
            else:
                color = chess.WHITE if c.isupper() else chess.BLACK
                if c.upper() == 'A':
                    if color == chess.WHITE:
                        self.amazons_white |= chess.BB_SQUARES[square]
                    else:
                        self.amazons_black |= chess.BB_SQUARES[square]
                    piece_type = AMAZON
                elif c.upper() == 'C':
                    if color == chess.WHITE:
                        self.cyrils_white |= chess.BB_SQUARES[square]
                    else:
                        self.cyrils_black |= chess.BB_SQUARES[square]
                    piece_type = CYRIL
                elif c.upper() == 'E':
                    if color == chess.WHITE:
                        self.eves_white |= chess.BB_SQUARES[square]
                    else:
                        self.eves_black |= chess.BB_SQUARES[square]
                    piece_type = EVE
                elif c == 'P' and chess.square_rank(square) == 7:
                    piece_type = AMAZON
                    color = chess.WHITE
                elif c == 'p' and chess.square_rank(square) == 0:
                    piece_type = AMAZON
                    color = chess.BLACK
                else:
                    piece_type = chess.PIECE_SYMBOLS.index(c.lower())
                
                self._set_piece_at(square, piece_type, color)
                square += 1
    
        self.turn = chess.WHITE if parts[1] == 'w' else chess.BLACK
        self.castling_rights = chess.BB_EMPTY
        if '-' not in parts[2]:
            if 'K' in parts[2]: self.castling_rights |= chess.BB_H1
            if 'Q' in parts[2]: self.castling_rights |= chess.BB_A1
            if 'k' in parts[2]: self.castling_rights |= chess.BB_H8
            if 'q' in parts[2]: self.castling_rights |= chess.BB_A8
        self.ep_square = chess.parse_square(parts[3]) if parts[3] != '-' else None
            
 
    def _set_piece_at(self, square: chess.Square, piece_type: PieceType, color: Color) -> None:
        self.clear_square(square)
        super()._set_piece_at(square, piece_type, color)
        if piece_type == AMAZON:
            if color == chess.WHITE:
                self.amazons_white |= chess.BB_SQUARES[square]
            else:
                self.amazons_black |= chess.BB_SQUARES[square]
        elif piece_type == CYRIL:
            if color == chess.WHITE:
                self.cyrils_white |= chess.BB_SQUARES[square]
            else:
                self.cyrils_black |= chess.BB_SQUARES[square]
        elif piece_type == EVE:
            if color == chess.WHITE:
                self.eves_white |= chess.BB_SQUARES[square]
            else:
                self.eves_black |= chess.BB_SQUARES[square]
 
    def piece_at(self, square: chess.Square) -> Optional[chess.Piece]:
        if self.amazons_white & chess.BB_SQUARES[square]:
            return chess.Piece(AMAZON, chess.WHITE)
        elif self.amazons_black & chess.BB_SQUARES[square]:
            return chess.Piece(AMAZON, chess.BLACK)
        elif self.cyrils_white & chess.BB_SQUARES[square]:
            return chess.Piece(CYRIL, chess.WHITE)
        elif self.cyrils_black & chess.BB_SQUARES[square]:
            return chess.Piece(CYRIL, chess.BLACK)
        elif self.eves_white & chess.BB_SQUARES[square]:
            return chess.Piece(EVE, chess.WHITE)
        elif self.eves_black & chess.BB_SQUARES[square]:
            return chess.Piece(EVE, chess.BLACK)
        return super().piece_at(square)
 
    def generate_pseudo_legal_moves(self, from_mask: Bitboard = BB_ALL, to_mask: Bitboard = BB_ALL) -> Iterator[Move]:
        our_pieces = self.occupied_co[self.turn]
        if self.turn == chess.WHITE:
            our_amazons = self.amazons_white
            our_cyrils = self.cyrils_white
            our_eves = self.eves_white
        else:
            our_amazons = self.amazons_black
            our_cyrils = self.cyrils_black
            our_eves = self.eves_black
    
        # Generování tahů pro amazonky
        for from_square in chess.scan_forward(our_amazons & from_mask):
            attacks = self.amazon_attacks(from_square)
            valid_moves = attacks & ~our_pieces & to_mask
            for to_square in chess.scan_forward(valid_moves):
                yield Move(from_square, to_square)
    
        # Generování tahů pro Cyrily
        for from_square in chess.scan_forward(our_cyrils & from_mask):
            attacks = self.cyril_attacks(from_square)
            valid_moves = attacks & ~our_pieces & to_mask
            for to_square in chess.scan_forward(valid_moves):
                yield Move(from_square, to_square)
    
        # Generování tahů pro Evy
        for from_square in chess.scan_forward(our_eves & from_mask):
            attacks = self.eve_attacks(from_square)
            valid_moves = attacks & ~our_pieces & to_mask
            for to_square in chess.scan_forward(valid_moves):
                yield Move(from_square, to_square)
    
        # Generování tahů pro standardní figury
        for move in super().generate_pseudo_legal_moves(from_mask, to_mask):
            piece = self.piece_at(move.from_square)
            if piece and piece.piece_type not in [AMAZON, CYRIL, EVE]:
                yield move
 
    def queen_attacks(self, square):
        return self.bishop_attacks(square) | self.rook_attacks(square)
 
    def bishop_attacks(self, square):
        return chess.BB_DIAG_ATTACKS[square][self.occupied & chess.BB_DIAG_MASKS[square]]
 
    def rook_attacks(self, square):
        return (chess.BB_RANK_ATTACKS[square][self.occupied & chess.BB_RANK_MASKS[square]] |
                chess.BB_FILE_ATTACKS[square][self.occupied & chess.BB_FILE_MASKS[square]])
 
    def amazon_attacks(self, square):
        return self.queen_attacks(square) | chess.BB_KNIGHT_ATTACKS[square]
 
    def cyril_attacks(self, square):
        return self.rook_attacks(square) | chess.BB_KNIGHT_ATTACKS[quare]
 
    def eve_attacks(self, square):
        return self.bishop_attacks(square) | chess.BB_KNIGHT_ATTACKS[square]
 
    def is_pseudo_legal(self, move):
        from_square = move.from_square
        to_square = move.to_square
        piece = self.piece_at(from_square)
    
        if not piece or piece.color != self.turn:
            return False
    
        if self.occupied_co[self.turn] & chess.BB_SQUARES[to_square]:
            return False
    
        if self.is_castling(move):
            return True
    
        if piece.piece_type == AMAZON:
            return bool(self.amazon_attacks(from_square) & chess.BB_SQUARES[to_square])
        elif piece.piece_type == CYRIL:
            return bool(self.cyril_attacks(from_square) & chess.BB_SQUARES[to_square])
        elif piece.piece_type == EVE:
            return bool(self.eve_attacks(from_square) & chess.BB_SQUARES[to_square])
        else:
            return super().is_pseudo_legal(move)
 
    def is_legal(self, move):
        if not self.is_pseudo_legal(move):
            return False
    
        from_square = move.from_square
        to_square = move.to_square
        piece = self.piece_at(from_square)
        captured_piece = self.piece_at(to_square)
    
        # Kontrola pro všechny figury: nelze brát figuru stejné barvy
        if captured_piece and captured_piece.color == piece.color:
            return False
    
        # Dočasně provést tah
        self.clear_square(from_square)
        self._set_piece_at(to_square, piece.piece_type, piece.color)
    
        # Najít pozici krále
        king_square = to_square if piece.piece_type == chess.KING else self.king(self.turn)
    
        # Kontrola, zda je král v šachu po tahu
        is_check = self._is_attacked_by(not self.turn, king_square) if king_square is not None else False
    
        # Vrátit pozici do původního stavu
        self.clear_square(to_square)
        self._set_piece_at(from_square, piece.piece_type, piece.color)
        if captured_piece:
            self._set_piece_at(to_square, captured_piece.piece_type, captured_piece.color)
    
        return not is_check
        
 
    def _is_attacked_by(self, color, square):
        attackers = self.attackers(color, square)
        return bool(attackers)
 
    def attackers(self, color: Color, square: chess.Square) -> Bitboard:
        if square is None:
            return chess.BB_EMPTY
    
        attackers = chess.BB_EMPTY
        occupied = self.occupied
        occupied_co = self.occupied_co[color]
    
        # Jezdci
        attackers |= chess.BB_KNIGHT_ATTACKS[square] & self.knights & occupied_co
    
        # Král
        attackers |= chess.BB_KING_ATTACKS[square] & self.kings & occupied_co
    
        # Pěšci
        if color == chess.WHITE:
            attackers |= chess.BB_PAWN_ATTACKS[chess.BLACK][square] & self.pawns & occupied_co
        else:
            attackers |= chess.BB_PAWN_ATTACKS[chess.WHITE][square] & self.pawns & occupied_co
    
        # Střelcové útoky (včetně dam a amazonek)
        bishop_attacks = chess.BB_DIAG_ATTACKS[square][occupied & chess.BB_DIAG_MASKS[square]]
        attackers |= bishop_attacks & ((self.bishops | self.queens) & occupied_co)
    
        # Věžové útoky (včetně dam, amazonek a cyrilů)
        rook_attacks = (
            chess.BB_RANK_ATTACKS[square][occupied & chess.BB_RANK_MASKS[square]] |
            chess.BB_FILE_ATTACKS[square][occupied & chess.BB_FILE_MASKS[square]]
        )
        attackers |= rook_attacks & ((self.rooks | self.queens) & occupied_co)
    
        # Amazonky (Dáma + Jezdec)
        amazons = self.amazons_white if color == chess.WHITE else self.amazons_black
        amazon_attacks = bishop_attacks | rook_attacks | chess.BB_KNIGHT_ATTACKS[square]
        attackers |= amazon_attacks & amazons
    
        # Cyrilové (Věž + Jezdec)
        cyrils = self.cyrils_white if color == chess.WHITE else self.cyrils_black
        cyril_attacks = rook_attacks | chess.BB_KNIGHT_ATTACKS[square]
        attackers |= cyril_attacks & cyrils
    
        # Evy (Střelec + Jezdec)
        eves = self.eves_white if color == chess.WHITE else self.eves_black
        eve_attacks = bishop_attacks | chess.BB_KNIGHT_ATTACKS[square]
        attackers |= eve_attacks & eves
    
        return attackers
        
    def push(self, move):
        if not self.is_legal(move):
            raise ValueError(f"Move {move} is not legal in position {self.fen()}")
 
        piece = self.piece_at(move.from_square)
        captured_piece = self.piece_at(move.to_square)
 
        self.clear_square(move.from_square)
        self.clear_square(move.to_square)
        self._set_piece_at(move.to_square, piece.piece_type, piece.color)
 
        self.turn = not self.turn
 
        self.move_stack.append((move, captured_piece))
 
    def pop(self):
        if not self.move_stack:
            return None
 
        move, captured_piece = self.move_stack.pop()
 
        piece = self.piece_at(move.to_square)
        
        self.clear_square(move.from_square)
        self.clear_square(move.to_square)
 
        self._set_piece_at(move.from_square, piece.piece_type, piece.color)
 
        if captured_piece:
            self._set_piece_at(move.to_square, captured_piece.piece_type, captured_piece.color)
 
        self.turn = not self.turn
 
        return move
 
    def is_check(self):
        king_square = self.king(self.turn)
        if king_square is None:
            return False
        is_check = self._is_attacked_by(not self.turn, king_square)
        return is_check
 
    def is_checkmate(self):
        if not self.is_check():
            return False
        legal_moves = list(self.generate_legal_moves())
        return len(legal_moves) == 0
 
    def is_game_over(self):
        return self.is_checkmate() or self.is_stalemate() or self.is_insufficient_material()
 
    def is_stalemate(self):
        if self.is_check():
            return False
        legal_moves = list(self.generate_legal_moves())
        return len(legal_moves) == 0
    
    def is_insufficient_material(self):
        return (self.pawns | self.rooks | self.queens | self.amazons_white | self.amazons_black |
                self.cyrils_white | self.cyrils_black | self.eves_white | self.eves_black) == 0 and (
            chess.popcount(self.occupied) <= 3
        )
 
    def generate_legal_moves(self, from_mask=chess.BB_ALL, to_mask=chess.BB_ALL):
        for move in self.generate_pseudo_legal_moves(from_mask, to_mask):
            if self.is_legal(move):
                yield move
 
    def debug_amazons(self):
        pass
 
    def debug_cyrils(self):
        pass
 
    def debug_eves(self):
        pass
 
    def piece_symbol(self, piece):
        if piece is None:
            return '.'
        if piece.piece_type == AMAZON:
            return 'A' if piece.color == chess.WHITE else 'a'
        if piece.piece_type == CYRIL:
            return 'C' if piece.color == chess.WHITE else 'c'
        if piece.piece_type == EVE:
            return 'E' if piece.color == chess.WHITE else 'e'
        return piece.symbol()
 
    def piece_type_at(self, square):
        if (self.amazons_white | self.amazons_black) & chess.BB_SQUARES[square]:
            return AMAZON
        if (self.cyrils_white | self.cyrils_black) & chess.BB_SQUARES[square]:
            return CYRIL
        if (self.eves_white | self.eves_black) & chess.BB_SQUARES[square]:
            return EVE
        return super().piece_type_at(square)
 
    def color_at(self, square):
        if self.amazons_white & chess.BB_SQUARES[square]:
            return chess.WHITE
        if self.amazons_black & chess.BB_SQUARES[square]:
            return chess.BLACK
        if self.cyrils_white & chess.BB_SQUARES[square]:
            return chess.WHITE
        if self.cyrils_black & chess.BB_SQUARES[square]:
            return chess.BLACK
        if self.eves_white & chess.BB_SQUARES[square]:
            return chess.WHITE
        if self.eves_black & chess.BB_SQUARES[square]:
            return chess.BLACK
        return super().color_at(square)
 
    @property
    def legal_moves(self):
        return list(self.generate_legal_moves())
 
    def __str__(self):
        builder = []
        for square in chess.SQUARES_180:
            piece = self.piece_at(square)
            symbol = self.piece_symbol(piece) if piece else '.'
            builder.append(symbol)
            if chess.square_file(square) == 7:
                if square != chess.H1:
                    builder.append('\n')
        return ''.join(builder)
 
def format_time(seconds):
    hours, remainder = divmod(seconds, 3600)
    minutes, seconds = divmod(remainder, 60)
    return f"{int(hours):02d}h {int(minutes):02d}m {int(seconds):02d}s"
 
def print_elapsed_time(stop_event, start_time):
    while not stop_event.is_set():
        elapsed_time = time.time() - start_time
        print(f"\rUplynulý čas: {format_time(elapsed_time)}", end="", flush=True)
        time.sleep(1)
 
def simplify_fen(fen):
    return ' '.join(fen.split()[:4])
 
def calculate_optimal_moves(start_fen: str) -> Dict[str, Tuple[int, str]]:
    print("Funkce calculate_optimal_moves byla zavolána8")
    print(f"Počáteční FEN: {start_fen}")
    
    board = CustomBoard(start_fen)
    POZ = {1: simplify_fen(start_fen)}
    AR = {simplify_fen(start_fen): {'used': 0, 'to_end': None, 'depth': 0, 'type': 'normal', 'parent': None}}
    N = 1
    M = 0
 
    start_time = time.time()
    current_depth = 0
    positions_at_depth = {0: 0}
    depth_start_time = start_time
 
    stop_event = threading.Event()
    timer_thread = threading.Thread(target=print_elapsed_time, args=(stop_event, start_time))
    timer_thread.start()
 
    try:
        print("Začínám generovat pozice...")
        print("Počáteční pozice:7")
        print_board(start_fen)
        
        depth_1_positions = []  # Seznam pro ukládání pozic v hloubce 1
 
        # Generate all positions
        while M < N:
            M += 1
            current_fen = POZ[M]
            board.set_custom_fen(current_fen)
            simplified_current_fen = simplify_fen(current_fen)
            current_depth = AR[simplified_current_fen]['depth']
 
            if current_depth not in positions_at_depth:
                positions_at_depth[current_depth] = 0
                if current_depth > 0:
                    depth_time = time.time() - depth_start_time
                    total_time = time.time() - start_time
                    print(f"\nHloubka {current_depth - 1}: {positions_at_depth[current_depth - 1]} pozic, "
                          f"Čas hloubky: {format_time(depth_time)} / Celkový čas: {format_time(total_time)}")
                    
                    if current_depth == 1:
                        print("Všechny pozice v hloubce 1:")
                        for pos in depth_1_positions:
                            print_board(pos)
                            print()
                
                depth_start_time = time.time()
 
            positions_at_depth[current_depth] += 1
 
            if current_depth == 1:
                depth_1_positions.append(current_fen)
 
            if AR[simplified_current_fen]['used'] == 0:
                AR[simplified_current_fen]['used'] = 1
                legal_moves = list(board.legal_moves)
                for move in legal_moves:
                    board.push(move)
                    POZ2 = board.fen()
                    simplified_POZ2 = simplify_fen(POZ2)
                    if simplified_POZ2 not in AR:
                        N += 1
                        POZ[N] = simplified_POZ2
                        AR[simplified_POZ2] = {
                            'used': 0, 
                            'to_end': None, 
                            'depth': current_depth + 1, 
                            'type': 'normal',
                            'parent': simplified_current_fen
                        }
                    board.pop()
    
        # Print last depth
        depth_time = time.time() - depth_start_time
        total_time = time.time() - start_time
        print(f"\nHloubka {current_depth}: {positions_at_depth[current_depth]} pozic, "
              f"Čas hloubky: {format_time(depth_time)} / Celkový čas: {format_time(total_time)}")
        print(f"Příklad pozice v hloubce {current_depth}:")
        print_board(current_fen)
 
        print(f"Generování pozic dokončeno. Celkový počet pozic: {N}")
 
        # Initial evaluation
        print("\nZačínám počáteční ohodnocení...")
        F_checkmate = 0
        F_stalemate = 0
        F_drawing = 0
        F_check = 0
        F_normal = 0
        for i in range(1, N + 1):
            current_fen = POZ[i]
            board.set_custom_fen(current_fen)
            simplified_current_fen = simplify_fen(current_fen)
 
            if board.is_checkmate():
                AR[simplified_current_fen]['to_end'] = -1000
                AR[simplified_current_fen]['type'] = 'checkmate'
                F_checkmate += 1
            elif board.is_stalemate():
                AR[simplified_current_fen]['to_end'] = 0
                AR[simplified_current_fen]['type'] = 'stalemate'
                F_stalemate += 1
            elif board.is_insufficient_material():
                AR[simplified_current_fen]['to_end'] = 0
                AR[simplified_current_fen]['type'] = 'drawing'
                F_drawing += 1
            elif board.is_check():
                AR[simplified_current_fen]['to_end'] = None
                AR[simplified_current_fen]['type'] = 'check'
                F_check += 1
            else:
                AR[simplified_current_fen]['to_end'] = None
                AR[simplified_current_fen]['type'] = 'normal'
                F_normal += 1
 
        print(f"Počet pozic v matu je {F_checkmate}")
        print(f"Počet pozic v patu je {F_stalemate}")
        print(f"Počet pozic v remíze je {F_drawing}")
        print(f"Počet pozic v šachu je {F_check}")
        print(f"Počet normálních pozic je {F_normal}")
 
        # Iterative evaluation
        print("\nZačínám iterativní ohodnocení...6")
        uroven = 0
        while True:
            uroven += 1
            level_start_time = time.time()
            print(f"Výpočet v úrovni {uroven}")
            
            changed = False
            current_level_positions = 0
            for i in range(1, N + 1):
                current_fen = POZ[i]
                board.set_custom_fen(current_fen)
                simplified_current_fen = simplify_fen(current_fen)
                if AR[simplified_current_fen]['to_end'] is None or AR[simplified_current_fen]['to_end'] == 0:
                    hod = -2000
                    for move in board.legal_moves:
                        board.push(move)
                        POZ2 = board.fen()
                        simplified_POZ2 = simplify_fen(POZ2)
                        if simplified_POZ2 in AR and AR[simplified_POZ2]['to_end'] is not None:
                            hod2 = -AR[simplified_POZ2]['to_end']
                            if hod2 > hod:
                                hod = hod2
                        board.pop()
                    
                    if hod == 1001 - uroven:
                        new_to_end = 1000 - uroven
                        new_type = 'winning'
                    elif hod == -1001 + uroven:
                        new_to_end = -1000 + uroven
                        new_type = 'losing'
                    elif hod == 0:
                        new_to_end = 0
                        new_type = 'drawing'
                    else:
                        new_to_end = None
                        new_type = None
                    
                    if new_to_end is not None and (AR[simplified_current_fen]['to_end'] != new_to_end or AR[simplified_current_fen]['type'] != new_type):
                        AR[simplified_current_fen]['to_end'] = new_to_end
                        AR[simplified_current_fen]['type'] = new_type
                        changed = True
                        current_level_positions += 1
            
            level_end_time = time.time()
            total_elapsed_time = level_end_time - start_time
            level_elapsed_time = level_end_time - level_start_time
            print(f"Nalezeno {current_level_positions} pozic v úrovni {uroven}")
            print(f"Čas úrovně: {format_time(level_elapsed_time)} / Celkový čas: {format_time(total_elapsed_time)}")
            
            if not changed:
                print("Hodnocení ukončeno - žádné další změny.5")
                break
        
        print(f"Celkem nalezeno {sum(1 for data in AR.values() if data['to_end'] is not None)} ohodnocených pozic")
        print(f"Celkem nalezeno {sum(1 for data in AR.values() if data['to_end'] is None)} neohodnocených pozic")
 
        print("\nVýpočet dokončen.")
        
        # Print optimal moves with parent check
        current_fen = start_fen
        simplified_current_fen = simplify_fen(current_fen)
        optimal_moves = [simplified_current_fen]
        
        while True:
            board = CustomBoard(current_fen)
            if board.is_checkmate():
                print("Mat detekován!4")
                break
            
            if board.is_insufficient_material():
                print("Nedostatečný materiál detekován!")
                break
            
            half_move_clock = current_fen.split()[-2]
            if half_move_clock != '-' and int(half_move_clock) >= 100:
                print("Remíza pravidlem 50 tahů detekována!")
                break
            
            if simplified_current_fen not in AR:
                print(f"Pozice {simplified_current_fen} není v AR.")
                break
            
            current_value = AR[simplified_current_fen]['to_end']
            
            if current_value == 0:
                print("Remíza dosažena!")
                break
            
            hod = -2000 if current_value > 0 else 2000
            best_fen = None
            for move in board.legal_moves:
                board.push(move)
                POZ2 = board.fen()
                simplified_POZ2 = simplify_fen(POZ2)
                if simplified_POZ2 in AR and AR[simplified_POZ2]['parent'] == simplified_current_fen:
                    hod2 = -AR[simplified_POZ2]['to_end']
                    if current_value > 0:  # Silnější hráč
                        if hod2 > hod:
                            hod = hod2
                            best_fen = simplified_POZ2
                    else:  # Slabší hráč
                        if hod2 < hod:
                            hod = hod2
                            best_fen = simplified_POZ2
                board.pop()
            
            if best_fen is None:
                print("Žádný další tah nebyl nalezen.")
                break
            
            optimal_moves.append(best_fen)
            current_fen = best_fen
            simplified_current_fen = simplify_fen(current_fen)
        
        print("\nOptimální tahy3:")
        for fen in optimal_moves:
            print_board(fen)
            hodnota = AR[simplify_fen(fen)]['to_end']
            typ_pozice = AR[simplify_fen(fen)]['type']
            print(f"Hodnota: {hodnota}, Typ: {typ_pozice}")
            print(fen)
            print("\n")
        
        return {fen: (data['to_end'], data['type']) for fen, data in AR.items() if data['to_end'] is not None}
 
    finally:
        stop_event.set()
        timer_thread.join()
 
# Helper function to print the board
def print_board(fen):
    board = CustomBoard(fen)
    print(board)
 
# Najděte nejmenší kladnou hodnotu to_end ve všech FEN záznamech v AR
def find_min_positive_value(AR):
    min_positive_value = float('inf')
    min_fen = None
    
    for fen, (value, type_pozice) in AR.items():
        if value is not None and value > 0 and value < min_positive_value:
            min_positive_value = value
            min_fen = fen
    
    if min_positive_value == float('inf'):
        print("Žádná kladná hodnota nebyla nalezena.")
    else:
        print(f"Nejmenší kladná hodnota: {min_positive_value}, FEN: {min_fen}")
 
# # Main execution
# # Main execution
# if __name__ == "__main__":
#     start_fen = "7K/8/k1P5/7p/8/8/8/8 w - - 0 1"
 
#     start_fen = "7K/8/8/8/8/k7/8/7A w - - 0 1"
 
#  #   start_fen = "7K/8/8/2a5/8/1k6/8/7A w - - 0 1"
 
#     start_fen = "7K/8/k1P5/7p/8/8/8/8 w - - 0 1"
 
#     start_fen = "6K1/3E4/8/8/8/k7/8/8 w - - 0 1"
 
#     start_fen = "8/5A2/8/8/2K5/8/ka6/8 w - - 0 1"
 
#     start_fen = "8/8/8/2k5/8/8/1K6/3Q4 w - - 0 1"
 
 #    start_fen = "8/7k/7r/8/8/RK6/8/8 w - - 0 1"
 
    
 #    AR = calculate_optimal_moves(start_fen)
 
#     find_min_positive_value(AR)
 
def print_20_successors(AR, start_fen):
    print("\nVýpis 20 následníků počáteční pozice:")
    simplified_start_fen = simplify_fen(start_fen)
    
    if simplified_start_fen not in AR:
        print(f"Počáteční pozice {simplified_start_fen} nebyla nalezena v AR.")
        return
 
    count = 0
    for fen, (hodnota, typ_pozice) in AR.items():
        if count >= 20:
            break
        
        print(f"\nFEN: {fen}")
        print("Hodnoty:")
        print(f"  Hodnota: {hodnota}")
        print(f"  Typ pozice: {typ_pozice}")
        
        print_board(fen)
        count += 1
        
if __name__ == "__main__":
    start_fen = "8/8/8/2k5/8/8/1K6/1Q6 w - - 0 1"
    start_fen = "8/7k/8/8/8/1K6/8/1Q6 w - - 0 1"
    start_fen = "8/7k/8/8/8/1K6/8/1A6 w - - 0 1"
    start_fen = "8/7k/8/8/8/1K6/1A6/8 w - - 0 1"
    start_fen = "8/8/8/5k2/8/1K6/8/4A3 w - - 0 1"
    start_fen = "8/8/8/5k2/8/8/K7/2A5 w - - 0 1"
    
    AR = calculate_optimal_moves(start_fen)
 
    find_min_positive_value(AR)
 
    # Přidáno: Volání nové funkce pro výpis 20 následníků
#    print_20_successors(AR, start_fen)
 
    # print("\nVýsledky:")
    # for hodnota in range(-996, -1001, -1):  # Generuje hodnoty -996, -997, -998, -999, -1000
    #     for fen, (fen_hodnota, typ_pozice) in AR.items():
    #         if fen_hodnota == hodnota:
    #             print(f"FEN: {fen}")
    #             print(f"Hodnota: {fen_hodnota}")
    #             print(f"Typ pozice: {typ_pozice}")
                
    #             temp_board = CustomBoard(fen)
                
    #             if temp_board.is_checkmate():
    #                 print("Stav: Mat")
    #             elif temp_board.is_stalemate():
    #                 print("Stav: Pat")
    #             elif temp_board.is_insufficient_material():
    #                 print("Stav: Nedostatečný materiál")
    #             elif temp_board.is_check():
    #                 print("Stav: Šach")
    #             else:
    #                 print("Stav: Normální pozice")
     
    #             print_board(fen)
                
    #             print()
 
    # Print optimal moves
# Print optimal moves
    current_fen = start_fen
    simplified_current_fen = simplify_fen(current_fen)
    simplified_current_fen1 = simplified_current_fen
    optimal_moves = [start_fen]
    
    while True:
        board = CustomBoard(current_fen)
        if board.is_checkmate():
            print("Mat detekován!2")
            break
        
        # Opravená část
        half_move_clock = current_fen.split()[-2]
        if board.is_insufficient_material() or (half_move_clock != '-' and int(half_move_clock) >= 100):
            if board.is_insufficient_material():
                print("Nedostatečný materiál detekován!")
            else:
                print("Remíza pravidlem 50 tahů detekována!")
            AR[simplified_current_fen] = (0, 'drawing')  # Aktualizujeme AR pro tuto pozici
            break
        
        if simplified_current_fen not in AR:
            print(f"Pozice {simplified_current_fen} není v AR.")
            break
        
        current_value = AR[simplified_current_fen][0]
        
        if current_value == 0:
            print("Remíza dosažena!")
            break
        
        hod = -2000 if current_value > 0 else 2000
        best_fen = None
        for move in board.legal_moves:
            board.push(move)
            POZ2 = board.fen()
            simplified_POZ2 = simplify_fen(POZ2)
            if simplified_POZ2 in AR:
                hod2 = -AR[simplified_POZ2][0]
                if current_value > 0:  # Silnější hráč
                    if hod2 > hod:
                        hod = hod2
                        best_fen = simplified_POZ2
                else:  # Slabší hráč
                    if hod2 < hod:
                        hod = hod2
                        best_fen = simplified_POZ2
            board.pop()
        
        if best_fen is None:
            print("Žádný další tah nebyl nalezen.")
            break
        optimal_moves.append(best_fen)
        current_fen = best_fen
        simplified_current_fen = simplify_fen(current_fen)
            
    
    print("\nOptimální tahy1:")
    for fen in reversed(optimal_moves):
        print_board(fen)
        hodnota, typ_pozice = AR[simplify_fen(fen)]
        print(f"Hodnota: {hodnota}, Typ: {typ_pozice}")
        print(fen)
        print("\n")
The output is here:

Output:
Mat detekován!2 Optimální tahy1: ........ .......k .....A.. ........ ........ ........ K....... ........ Hodnota: -1000, Typ: checkmate 8/7k/5A2/8/8/8/K7/8 b - - ........ .......k ........ ....A... ........ ........ K....... ........ Hodnota: 999, Typ: winning 8/7k/8/4A3/8/8/K7/8 w - - ........ ........ ......k. ....A... ........ ........ K....... ........ Hodnota: -998, Typ: losing 8/8/6k1/4A3/8/8/K7/8 b - - ........ ........ ......k. ........ ........ ........ K....... A....... Hodnota: 997, Typ: winning 8/8/6k1/8/8/8/K7/A7 w - - ........ ........ ........ .....k.. ........ ........ K....... A....... Hodnota: -994, Typ: losing 8/8/8/5k2/8/8/K7/A7 b - - ........ ........ ........ .....k.. ........ ........ K....... ..A..... Hodnota: 993, Typ: winning 8/8/8/5k2/8/8/K7/2A5 w - - 0 1
The bad thing is that it outputs numbers like -994 and then it jumps to 997.
The fix amounts to outputting continuous chain of numbers like -994,995,-996,997,-998,999,-1000.
Once fixed I can offer around 100$.
Larz60+ write Dec-08-2024, 07:14 AM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.

Done for you this time. Please use bbcode tags on future posts.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  How returns behave in a function with multiple returns? khasbay 1 909 May-19-2024, 08:48 AM
Last Post: deanhystad
  a chess endgame problem, almost solved but not quite max22 0 772 Mar-31-2024, 06:14 PM
Last Post: max22
  optimum chess endgame with D=3 pieces doesn't give an exact moves_to_mate variable max22 1 1,047 Mar-21-2024, 09:31 PM
Last Post: max22
  A new endgame problem, almost solved but not quite 2 max22 0 903 Mar-07-2024, 07:12 PM
Last Post: max22
  Python trivial endgame engine is not working as expected max22 0 1,223 Feb-24-2024, 04:41 PM
Last Post: max22
  Search Engine nman52 1 82,923 Dec-16-2020, 11:46 AM
Last Post: Larz60+
  Winsorized Mean and Standard Deviation Wheeliam 0 2,515 Jul-11-2020, 05:27 PM
Last Post: Wheeliam
  standard library modules chpyel 4 4,065 May-10-2020, 02:58 PM
Last Post: snippsat
  Why doesn't my loop work correctly? (problem with a break statement) steckinreinhart619 2 4,098 Jun-11-2019, 10:02 AM
Last Post: steckinreinhart619
  Making an application with a 3d engine in it moo5e 1 2,783 May-27-2019, 03:17 PM
Last Post: heiner55

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020