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() |