SHOW:
|
|
- or go back to the newest paste.
| 1 | import chess | |
| 2 | from typing import Iterator, Optional, Dict, Tuple | |
| 3 | from chess import Move, BB_ALL, Bitboard, PieceType, Color | |
| 4 | import time | |
| 5 | from collections import deque | |
| 6 | import threading | |
| 7 | ||
| 8 | # Definice nových figur | |
| 9 | AMAZON = 7 | |
| 10 | CYRIL = 8 | |
| 11 | EVE = 9 | |
| 12 | ||
| 13 | # Rozšíření seznamu PIECE_SYMBOLS | |
| 14 | chess.PIECE_SYMBOLS.append('a')
| |
| 15 | chess.PIECE_SYMBOLS.append('c')
| |
| 16 | chess.PIECE_SYMBOLS.append('e')
| |
| 17 | ||
| 18 | class CustomBoard(chess.Board): | |
| 19 | def __init__(self, fen=None): | |
| 20 | self.amazons_white = chess.BB_EMPTY | |
| 21 | self.amazons_black = chess.BB_EMPTY | |
| 22 | self.cyrils_white = chess.BB_EMPTY | |
| 23 | self.cyrils_black = chess.BB_EMPTY | |
| 24 | self.eves_white = chess.BB_EMPTY | |
| 25 | self.eves_black = chess.BB_EMPTY | |
| 26 | super().__init__(None) | |
| 27 | if fen: | |
| 28 | self.set_custom_fen(fen) | |
| 29 | print("Šachovnice inicializována")
| |
| 30 | self.debug_amazons() | |
| 31 | self.debug_cyrils() | |
| 32 | self.debug_eves() | |
| 33 | ||
| 34 | def clear_square(self, square): | |
| 35 | super()._remove_piece_at(square) | |
| 36 | self.amazons_white &= ~chess.BB_SQUARES[square] | |
| 37 | self.amazons_black &= ~chess.BB_SQUARES[square] | |
| 38 | self.cyrils_white &= ~chess.BB_SQUARES[square] | |
| 39 | self.cyrils_black &= ~chess.BB_SQUARES[square] | |
| 40 | self.eves_white &= ~chess.BB_SQUARES[square] | |
| 41 | self.eves_black &= ~chess.BB_SQUARES[square] | |
| 42 | ||
| 43 | def set_custom_fen(self, fen): | |
| 44 | parts = fen.split() | |
| 45 | board_part = parts[0] | |
| 46 | ||
| 47 | self.clear() | |
| 48 | self.amazons_white = chess.BB_EMPTY | |
| 49 | self.amazons_black = chess.BB_EMPTY | |
| 50 | self.cyrils_white = chess.BB_EMPTY | |
| 51 | self.cyrils_black = chess.BB_EMPTY | |
| 52 | self.eves_white = chess.BB_EMPTY | |
| 53 | self.eves_black = chess.BB_EMPTY | |
| 54 | ||
| 55 | square = 56 | |
| 56 | for c in board_part: | |
| 57 | if c == '/': | |
| 58 | square -= 16 | |
| 59 | elif c.isdigit(): | |
| 60 | square += int(c) | |
| 61 | else: | |
| 62 | color = chess.WHITE if c.isupper() else chess.BLACK | |
| 63 | if c.upper() == 'A': | |
| 64 | if color == chess.WHITE: | |
| 65 | self.amazons_white |= chess.BB_SQUARES[square] | |
| 66 | else: | |
| 67 | self.amazons_black |= chess.BB_SQUARES[square] | |
| 68 | piece_type = AMAZON | |
| 69 | elif c.upper() == 'C': | |
| 70 | if color == chess.WHITE: | |
| 71 | self.cyrils_white |= chess.BB_SQUARES[square] | |
| 72 | else: | |
| 73 | self.cyrils_black |= chess.BB_SQUARES[square] | |
| 74 | piece_type = CYRIL | |
| 75 | elif c.upper() == 'E': | |
| 76 | if color == chess.WHITE: | |
| 77 | self.eves_white |= chess.BB_SQUARES[square] | |
| 78 | else: | |
| 79 | self.eves_black |= chess.BB_SQUARES[square] | |
| 80 | piece_type = EVE | |
| 81 | else: | |
| 82 | piece_type = chess.PIECE_SYMBOLS.index(c.lower()) | |
| 83 | self._set_piece_at(square, piece_type, color) | |
| 84 | square += 1 | |
| 85 | ||
| 86 | self.turn = chess.WHITE if parts[1] == 'w' else chess.BLACK | |
| 87 | self.castling_rights = chess.BB_EMPTY | |
| 88 | if '-' not in parts[2]: | |
| 89 | if 'K' in parts[2]: self.castling_rights |= chess.BB_H1 | |
| 90 | if 'Q' in parts[2]: self.castling_rights |= chess.BB_A1 | |
| 91 | if 'k' in parts[2]: self.castling_rights |= chess.BB_H8 | |
| 92 | if 'q' in parts[2]: self.castling_rights |= chess.BB_A8 | |
| 93 | self.ep_square = chess.parse_square(parts[3]) if parts[3] != '-' else None | |
| 94 | ||
| 95 | def _set_piece_at(self, square: chess.Square, piece_type: PieceType, color: Color) -> None: | |
| 96 | self.clear_square(square) | |
| 97 | super()._set_piece_at(square, piece_type, color) | |
| 98 | if piece_type == AMAZON: | |
| 99 | if color == chess.WHITE: | |
| 100 | self.amazons_white |= chess.BB_SQUARES[square] | |
| 101 | else: | |
| 102 | self.amazons_black |= chess.BB_SQUARES[square] | |
| 103 | elif piece_type == CYRIL: | |
| 104 | if color == chess.WHITE: | |
| 105 | self.cyrils_white |= chess.BB_SQUARES[square] | |
| 106 | else: | |
| 107 | self.cyrils_black |= chess.BB_SQUARES[square] | |
| 108 | elif piece_type == EVE: | |
| 109 | if color == chess.WHITE: | |
| 110 | self.eves_white |= chess.BB_SQUARES[square] | |
| 111 | else: | |
| 112 | self.eves_black |= chess.BB_SQUARES[square] | |
| 113 | ||
| 114 | def piece_at(self, square: chess.Square) -> Optional[chess.Piece]: | |
| 115 | if self.amazons_white & chess.BB_SQUARES[square]: | |
| 116 | return chess.Piece(AMAZON, chess.WHITE) | |
| 117 | elif self.amazons_black & chess.BB_SQUARES[square]: | |
| 118 | return chess.Piece(AMAZON, chess.BLACK) | |
| 119 | elif self.cyrils_white & chess.BB_SQUARES[square]: | |
| 120 | return chess.Piece(CYRIL, chess.WHITE) | |
| 121 | elif self.cyrils_black & chess.BB_SQUARES[square]: | |
| 122 | return chess.Piece(CYRIL, chess.BLACK) | |
| 123 | elif self.eves_white & chess.BB_SQUARES[square]: | |
| 124 | return chess.Piece(EVE, chess.WHITE) | |
| 125 | elif self.eves_black & chess.BB_SQUARES[square]: | |
| 126 | return chess.Piece(EVE, chess.BLACK) | |
| 127 | return super().piece_at(square) | |
| 128 | ||
| 129 | def generate_pseudo_legal_moves(self, from_mask: Bitboard = BB_ALL, to_mask: Bitboard = BB_ALL) -> Iterator[Move]: | |
| 130 | our_pieces = self.occupied_co[self.turn] | |
| 131 | if self.turn == chess.WHITE: | |
| 132 | our_amazons = self.amazons_white | |
| 133 | our_cyrils = self.cyrils_white | |
| 134 | our_eves = self.eves_white | |
| 135 | else: | |
| 136 | our_amazons = self.amazons_black | |
| 137 | our_cyrils = self.cyrils_black | |
| 138 | our_eves = self.eves_black | |
| 139 | ||
| 140 | for from_square in chess.scan_forward(our_amazons & from_mask): | |
| 141 | attacks = self.amazon_attacks(from_square) | |
| 142 | valid_moves = attacks & ~our_pieces & to_mask | |
| 143 | for to_square in chess.scan_forward(valid_moves): | |
| 144 | yield Move(from_square, to_square) | |
| 145 | ||
| 146 | for from_square in chess.scan_forward(our_cyrils & from_mask): | |
| 147 | attacks = self.cyril_attacks(from_square) | |
| 148 | valid_moves = attacks & ~our_pieces & to_mask | |
| 149 | for to_square in chess.scan_forward(valid_moves): | |
| 150 | yield Move(from_square, to_square) | |
| 151 | ||
| 152 | for from_square in chess.scan_forward(our_eves & from_mask): | |
| 153 | attacks = self.eve_attacks(from_square) | |
| 154 | valid_moves = attacks & ~our_pieces & to_mask | |
| 155 | for to_square in chess.scan_forward(valid_moves): | |
| 156 | yield Move(from_square, to_square) | |
| 157 | ||
| 158 | for move in super().generate_pseudo_legal_moves(from_mask, to_mask): | |
| 159 | if self.piece_type_at(move.from_square) not in [AMAZON, CYRIL, EVE]: | |
| 160 | yield move | |
| 161 | ||
| 162 | def queen_attacks(self, square): | |
| 163 | return self.bishop_attacks(square) | self.rook_attacks(square) | |
| 164 | ||
| 165 | def bishop_attacks(self, square): | |
| 166 | return chess.BB_DIAG_ATTACKS[square][self.occupied & chess.BB_DIAG_MASKS[square]] | |
| 167 | ||
| 168 | def rook_attacks(self, square): | |
| 169 | return (chess.BB_RANK_ATTACKS[square][self.occupied & chess.BB_RANK_MASKS[square]] | | |
| 170 | chess.BB_FILE_ATTACKS[square][self.occupied & chess.BB_FILE_MASKS[square]]) | |
| 171 | ||
| 172 | def amazon_attacks(self, square): | |
| 173 | return self.queen_attacks(square) | chess.BB_KNIGHT_ATTACKS[square] | |
| 174 | ||
| 175 | def cyril_attacks(self, square): | |
| 176 | return self.rook_attacks(square) | chess.BB_KNIGHT_ATTACKS[square] | |
| 177 | ||
| 178 | def eve_attacks(self, square): | |
| 179 | return self.bishop_attacks(square) | chess.BB_KNIGHT_ATTACKS[square] | |
| 180 | ||
| 181 | def is_pseudo_legal(self, move): | |
| 182 | from_square = move.from_square | |
| 183 | to_square = move.to_square | |
| 184 | piece = self.piece_at(from_square) | |
| 185 | ||
| 186 | if not piece or piece.color != self.turn: | |
| 187 | return False | |
| 188 | ||
| 189 | if self.occupied_co[self.turn] & chess.BB_SQUARES[to_square]: | |
| 190 | return False | |
| 191 | ||
| 192 | if self.is_castling(move): | |
| 193 | return True | |
| 194 | ||
| 195 | if piece.piece_type == AMAZON: | |
| 196 | return bool(self.amazon_attacks(from_square) & chess.BB_SQUARES[to_square]) | |
| 197 | elif piece.piece_type == CYRIL: | |
| 198 | return bool(self.cyril_attacks(from_square) & chess.BB_SQUARES[to_square]) | |
| 199 | elif piece.piece_type == EVE: | |
| 200 | return bool(self.eve_attacks(from_square) & chess.BB_SQUARES[to_square]) | |
| 201 | else: | |
| 202 | return super().is_pseudo_legal(move) | |
| 203 | ||
| 204 | def is_legal(self, move): | |
| 205 | if not self.is_pseudo_legal(move): | |
| 206 | return False | |
| 207 | ||
| 208 | from_square = move.from_square | |
| 209 | to_square = move.to_square | |
| 210 | piece = self.piece_at(from_square) | |
| 211 | captured_piece = self.piece_at(to_square) | |
| 212 | ||
| 213 | self.clear_square(from_square) | |
| 214 | self.clear_square(to_square) | |
| 215 | self._set_piece_at(to_square, piece.piece_type, piece.color) | |
| 216 | ||
| 217 | king_square = to_square if piece.piece_type == chess.KING else self.king(self.turn) | |
| 218 | is_check, attacker_square = self._is_attacked_by(not self.turn, king_square) | |
| 219 | ||
| 220 | self.clear_square(to_square) | |
| 221 | self._set_piece_at(from_square, piece.piece_type, piece.color) | |
| 222 | if captured_piece: | |
| 223 | self._set_piece_at(to_square, captured_piece.piece_type, captured_piece.color) | |
| 224 | ||
| 225 | return not is_check | |
| 226 | ||
| 227 | def _is_attacked_by(self, color, square): | |
| 228 | attackers = self.attackers(color, square) | |
| 229 | if attackers: | |
| 230 | for attacker_square in chess.scan_forward(attackers): | |
| 231 | return True, attacker_square | |
| 232 | return False, None | |
| 233 | ||
| 234 | def attackers(self, color, square): | |
| 235 | attackers = chess.BB_EMPTY | |
| 236 | ||
| 237 | knights = self.knights & self.occupied_co[color] | |
| 238 | attackers |= knights & chess.BB_KNIGHT_ATTACKS[square] | |
| 239 | ||
| 240 | king = self.kings & self.occupied_co[color] | |
| 241 | attackers |= king & chess.BB_KING_ATTACKS[square] | |
| 242 | ||
| 243 | pawns = self.pawns & self.occupied_co[color] | |
| 244 | if color == chess.WHITE: | |
| 245 | attackers |= pawns & chess.BB_PAWN_ATTACKS[chess.BLACK][square] | |
| 246 | else: | |
| 247 | attackers |= pawns & chess.BB_PAWN_ATTACKS[chess.WHITE][square] | |
| 248 | ||
| 249 | queens = self.queens & self.occupied_co[color] | |
| 250 | bishops = (self.bishops | queens) & self.occupied_co[color] | |
| 251 | rooks = (self.rooks | queens) & self.occupied_co[color] | |
| 252 | ||
| 253 | attackers |= chess.BB_DIAG_ATTACKS[square][self.occupied & chess.BB_DIAG_MASKS[square]] & bishops | |
| 254 | attackers |= (chess.BB_RANK_ATTACKS[square][self.occupied & chess.BB_RANK_MASKS[square]] | | |
| 255 | chess.BB_FILE_ATTACKS[square][self.occupied & chess.BB_FILE_MASKS[square]]) & rooks | |
| 256 | ||
| 257 | amazons = self.amazons_white if color == chess.WHITE else self.amazons_black | |
| 258 | for amazon_square in chess.scan_forward(amazons): | |
| 259 | if self.amazon_attacks(amazon_square) & chess.BB_SQUARES[square]: | |
| 260 | attackers |= chess.BB_SQUARES[amazon_square] | |
| 261 | ||
| 262 | cyrils = self.cyrils_white if color == chess.WHITE else self.cyrils_black | |
| 263 | for cyril_square in chess.scan_forward(cyrils): | |
| 264 | if self.cyril_attacks(cyril_square) & chess.BB_SQUARES[square]: | |
| 265 | attackers |= chess.BB_SQUARES[cyril_square] | |
| 266 | ||
| 267 | eves = self.eves_white if color == chess.WHITE else self.eves_black | |
| 268 | for eve_square in chess.scan_forward(eves): | |
| 269 | if self.eve_attacks(eve_square) & chess.BB_SQUARES[square]: | |
| 270 | attackers |= chess.BB_SQUARES[eve_square] | |
| 271 | ||
| 272 | return attackers | |
| 273 | ||
| 274 | def push(self, move): | |
| 275 | if not self.is_legal(move): | |
| 276 | - | pass |
| 276 | + | raise ValueError(f"Move {move} is not legal in position {self.fen()}")
|
| 277 | - | # raise ValueError(f"Move {move} is not legal in position {self.fen()}")
|
| 277 | + | |
| 278 | piece = self.piece_at(move.from_square) | |
| 279 | captured_piece = self.piece_at(move.to_square) | |
| 280 | ||
| 281 | self.clear_square(move.from_square) | |
| 282 | self.clear_square(move.to_square) | |
| 283 | self._set_piece_at(move.to_square, piece.piece_type, piece.color) | |
| 284 | ||
| 285 | self.turn = not self.turn | |
| 286 | ||
| 287 | self.move_stack.append((move, captured_piece)) | |
| 288 | ||
| 289 | def pop(self): | |
| 290 | if not self.move_stack: | |
| 291 | return None | |
| 292 | ||
| 293 | move, captured_piece = self.move_stack.pop() | |
| 294 | ||
| 295 | piece = self.piece_at(move.to_square) | |
| 296 | ||
| 297 | self.clear_square(move.from_square) | |
| 298 | self.clear_square(move.to_square) | |
| 299 | ||
| 300 | self._set_piece_at(move.from_square, piece.piece_type, piece.color) | |
| 301 | ||
| 302 | if captured_piece: | |
| 303 | self._set_piece_at(move.to_square, captured_piece.piece_type, captured_piece.color) | |
| 304 | ||
| 305 | self.turn = not self.turn | |
| 306 | ||
| 307 | return move | |
| 308 | ||
| 309 | def is_check(self): | |
| 310 | king_square = self.king(self.turn) | |
| 311 | if king_square is None: | |
| 312 | return False | |
| 313 | return self._is_attacked_by(not self.turn, king_square)[0] | |
| 314 | ||
| 315 | def is_checkmate(self): | |
| 316 | if not self.is_check(): | |
| 317 | return False | |
| 318 | return not any(self.generate_legal_moves()) | |
| 319 | ||
| 320 | def is_stalemate(self): | |
| 321 | if self.is_check(): | |
| 322 | return False | |
| 323 | return not any(self.generate_legal_moves()) | |
| 324 | ||
| 325 | def is_insufficient_material(self): | |
| 326 | return (self.pawns | self.rooks | self.queens | self.amazons_white | self.amazons_black | | |
| 327 | self.cyrils_white | self.cyrils_black | self.eves_white | self.eves_black) == 0 and ( | |
| 328 | chess.popcount(self.occupied) <= 3 | |
| 329 | ) | |
| 330 | ||
| 331 | def is_game_over(self): | |
| 332 | return self.is_checkmate() or self.is_stalemate() or self.is_insufficient_material() | |
| 333 | ||
| 334 | def debug_amazons(self): | |
| 335 | print(f"Bitboard bílých amazonek: {format(self.amazons_white, '064b')}")
| |
| 336 | print(f"Bitboard černých amazonek: {format(self.amazons_black, '064b')}")
| |
| 337 | for square in chess.SQUARES: | |
| 338 | if self.amazons_white & chess.BB_SQUARES[square]: | |
| 339 | print(f"Bílá amazonka na {chess.SQUARE_NAMES[square]}")
| |
| 340 | if self.amazons_black & chess.BB_SQUARES[square]: | |
| 341 | print(f"Černá amazonka na {chess.SQUARE_NAMES[square]}")
| |
| 342 | ||
| 343 | def debug_cyrils(self): | |
| 344 | print(f"Bitboard bílých Cyrils: {format(self.cyrils_white, '064b')}")
| |
| 345 | print(f"Bitboard černých Cyrils: {format(self.cyrils_black, '064b')}")
| |
| 346 | for square in chess.SQUARES: | |
| 347 | if self.cyrils_white & chess.BB_SQUARES[square]: | |
| 348 | print(f"Bílý Cyril na {chess.SQUARE_NAMES[square]}")
| |
| 349 | if self.cyrils_black & chess.BB_SQUARES[square]: | |
| 350 | print(f"Černý Cyril na {chess.SQUARE_NAMES[square]}")
| |
| 351 | ||
| 352 | def debug_eves(self): | |
| 353 | print(f"Bitboard bílých Eves: {format(self.eves_white, '064b')}")
| |
| 354 | print(f"Bitboard černých Eves: {format(self.eves_black, '064b')}")
| |
| 355 | for square in chess.SQUARES: | |
| 356 | if self.eves_white & chess.BB_SQUARES[square]: | |
| 357 | print(f"Bílá Eve na {chess.SQUARE_NAMES[square]}")
| |
| 358 | if self.eves_black & chess.BB_SQUARES[square]: | |
| 359 | print(f"Černá Eve na {chess.SQUARE_NAMES[square]}")
| |
| 360 | ||
| 361 | def piece_symbol(self, piece): | |
| 362 | if piece is None: | |
| 363 | return '.' | |
| 364 | if piece.piece_type == AMAZON: | |
| 365 | return 'A' if piece.color == chess.WHITE else 'a' | |
| 366 | if piece.piece_type == CYRIL: | |
| 367 | return 'C' if piece.color == chess.WHITE else 'c' | |
| 368 | if piece.piece_type == EVE: | |
| 369 | return 'E' if piece.color == chess.WHITE else 'e' | |
| 370 | return piece.symbol() | |
| 371 | ||
| 372 | def piece_type_at(self, square): | |
| 373 | if (self.amazons_white | self.amazons_black) & chess.BB_SQUARES[square]: | |
| 374 | return AMAZON | |
| 375 | if (self.cyrils_white | self.cyrils_black) & chess.BB_SQUARES[square]: | |
| 376 | return CYRIL | |
| 377 | if (self.eves_white | self.eves_black) & chess.BB_SQUARES[square]: | |
| 378 | return EVE | |
| 379 | return super().piece_type_at(square) | |
| 380 | ||
| 381 | def color_at(self, square): | |
| 382 | if self.amazons_white & chess.BB_SQUARES[square]: | |
| 383 | return chess.WHITE | |
| 384 | if self.amazons_black & chess.BB_SQUARES[square]: | |
| 385 | return chess.BLACK | |
| 386 | if self.cyrils_white & chess.BB_SQUARES[square]: | |
| 387 | return chess.WHITE | |
| 388 | if self.cyrils_black & chess.BB_SQUARES[square]: | |
| 389 | return chess.BLACK | |
| 390 | if self.eves_white & chess.BB_SQUARES[square]: | |
| 391 | return chess.WHITE | |
| 392 | if self.eves_black & chess.BB_SQUARES[square]: | |
| 393 | return chess.BLACK | |
| 394 | return super().color_at(square) | |
| 395 | ||
| 396 | @property | |
| 397 | def legal_moves(self): | |
| 398 | return [move for move in self.generate_pseudo_legal_moves() if self.is_legal(move)] | |
| 399 | ||
| 400 | def __str__(self): | |
| 401 | builder = [] | |
| 402 | for square in chess.SQUARES_180: | |
| 403 | piece = self.piece_at(square) | |
| 404 | symbol = self.piece_symbol(piece) if piece else '.' | |
| 405 | builder.append(symbol) | |
| 406 | if chess.square_file(square) == 7: | |
| 407 | if square != chess.H1: | |
| 408 | builder.append('\n')
| |
| 409 | return ''.join(builder) | |
| 410 | ||
| 411 | def simplify_fen_string(fen): | |
| 412 | parts = fen.split(' ')
| |
| 413 | return ' '.join(parts[:4]) # Zachováváme pouze informace o pozici, barvě na tahu, rošádách a en passant | |
| 414 | ||
| 415 | def format_time(seconds): | |
| 416 | hours, remainder = divmod(seconds, 3600) | |
| 417 | minutes, seconds = divmod(remainder, 60) | |
| 418 | return f"{int(hours):02d}h {int(minutes):02d}m {int(seconds):02d}s"
| |
| 419 | ||
| 420 | def print_elapsed_time(stop_event): | |
| 421 | start_time = time.time() | |
| 422 | while not stop_event.is_set(): | |
| 423 | elapsed_time = time.time() - start_time | |
| 424 | formatted_time = time.strftime("%H:%M:%S", time.gmtime(elapsed_time))
| |
| 425 | print(f"Uplynulý čas: {formatted_time}", end='\r')
| |
| 426 | time.sleep(1) | |
| 427 | ||
| 428 | def calculate_optimal_moves(start_fen: str) -> Dict[str, int]: | |
| 429 | board = CustomBoard(start_fen) | |
| 430 | AR = {simplify_fen_string(start_fen): 0}
| |
| 431 | queue = deque([(simplify_fen_string(start_fen), 0)]) | |
| 432 | visited = set() | |
| 433 | ||
| 434 | start_time = time.time() | |
| 435 | current_level = 0 | |
| 436 | pozice_na_urovni = 0 | |
| 437 | level_start_time = start_time | |
| 438 | ||
| 439 | stop_event = threading.Event() | |
| 440 | timer_thread = threading.Thread(target=print_elapsed_time, args=(stop_event,)) | |
| 441 | timer_thread.start() | |
| 442 | ||
| 443 | try: | |
| 444 | while queue: | |
| 445 | fen, hloubka = queue.popleft() | |
| 446 | ||
| 447 | if hloubka > current_level: | |
| 448 | level_time = time.time() - level_start_time | |
| 449 | print(f"\nHloubka {current_level}: {pozice_na_urovni} pozic, Čas: {format_time(level_time)}")
| |
| 450 | current_level = hloubka | |
| 451 | pozice_na_urovni = 0 | |
| 452 | level_start_time = time.time() | |
| 453 | ||
| 454 | if fen in visited: | |
| 455 | continue | |
| 456 | ||
| 457 | visited.add(fen) | |
| 458 | pozice_na_urovni += 1 | |
| 459 | board.set_custom_fen(fen) | |
| 460 | ||
| 461 | if board.is_checkmate(): | |
| 462 | AR[fen] = -1000 + hloubka if board.turn == chess.WHITE else 1000 - hloubka | |
| 463 | continue | |
| 464 | elif board.is_stalemate() or board.is_insufficient_material(): | |
| 465 | AR[fen] = 0 | |
| 466 | continue | |
| 467 | ||
| 468 | legal_moves = list(board.legal_moves) | |
| 469 | ||
| 470 | for move in legal_moves: | |
| 471 | board.push(move) | |
| 472 | new_fen = simplify_fen_string(board.fen()) | |
| 473 | if new_fen not in AR: | |
| 474 | AR[new_fen] = 0 | |
| 475 | queue.append((new_fen, hloubka + 1)) | |
| 476 | board.pop() | |
| 477 | ||
| 478 | level_time = time.time() - level_start_time | |
| 479 | print(f"\nHloubka {current_level}: {pozice_na_urovni} pozic, Čas: {format_time(level_time)}")
| |
| 480 | ||
| 481 | # Procházení a aktualizace hodnot | |
| 482 | changed = True | |
| 483 | while changed: | |
| 484 | changed = False | |
| 485 | for fen in AR: | |
| 486 | board.set_custom_fen(fen) | |
| 487 | if board.is_game_over(): | |
| 488 | continue | |
| 489 | ||
| 490 | legal_moves = list(board.legal_moves) | |
| 491 | if board.turn == chess.WHITE: | |
| 492 | best_value = max(AR[simplify_fen_string(board.fen())] for _ in [board.push(move), board.pop()] for move in legal_moves) | |
| 493 | if best_value > AR[fen]: | |
| 494 | AR[fen] = best_value | |
| 495 | changed = True | |
| 496 | else: | |
| 497 | best_value = min(AR[simplify_fen_string(board.fen())] for _ in [board.push(move), board.pop()] for move in legal_moves) | |
| 498 | if best_value < AR[fen]: | |
| 499 | AR[fen] = best_value | |
| 500 | changed = True | |
| 501 | ||
| 502 | celkovy_cas = time.time() - start_time | |
| 503 | print(f"\nVýpočet dokončen za {format_time(celkovy_cas)}")
| |
| 504 | ||
| 505 | finally: | |
| 506 | stop_event.set() | |
| 507 | timer_thread.join() | |
| 508 | ||
| 509 | return AR | |
| 510 | ||
| 511 | if __name__ == "__main__": | |
| 512 | start_fen = "8/3k4/8/8/8/8/A7/6K1 w - - 0 1" | |
| 513 | AR = calculate_optimal_moves(start_fen) | |
| 514 | ||
| 515 | # Výpis výsledků | |
| 516 | for fen, hodnota in AR.items(): | |
| 517 | print(f"FEN: {fen}")
| |
| 518 | print(f"Hodnota: {hodnota}")
| |
| 519 | print() |