| | from typing import List, Dict, Tuple, Set |
| |
|
| | |
| | MAX_HALFMOVES = 128 |
| | MAX_FULLMOVES = 256 |
| |
|
| | |
| | PIECE_TO_IDX: Dict[str, int] = { |
| | 'P': 0, 'N': 1, 'B': 2, 'R': 3, 'Q': 4, 'K': 5, |
| | 'p': 6, 'n': 7, 'b': 8, 'r': 9, 'q': 10, 'k': 11, |
| | '.': 12 |
| | } |
| | IDX_TO_PIECE: Dict[int, str] = {v: k for k, v in PIECE_TO_IDX.items()} |
| | EMPTY_SQ_IDX = PIECE_TO_IDX['.'] |
| | |
| | |
| | SQUARE_TO_IDX: Dict[str, int] = { |
| | f"{file}{rank}": (rank - 1) * 8 + (ord(file) - ord('a')) |
| | for rank in range(1, 9) |
| | for file in 'abcdefgh' |
| | } |
| | IDX_TO_SQUARE: Dict[int, str] = {v: k for k, v in SQUARE_TO_IDX.items()} |
| |
|
| |
|
| |
|
| | |
| |
|
| | |
| | _IDX_TO_COORDS: Dict[int, Tuple[int, int]] = {i: (i // 8, i % 8) for i in range(64)} |
| | _COORDS_TO_IDX: Dict[Tuple[int, int], int] = {v: k for k, v in _IDX_TO_COORDS.items()} |
| | _IDX_TO_ALG: Dict[int, str] = { |
| | i: f"{chr(ord('a') + file)}{rank + 1}" |
| | for i, (rank, file) in _IDX_TO_COORDS.items() |
| | } |
| | _ALG_TO_IDX: Dict[str, int] = {v: k for k, v in _IDX_TO_ALG.items()} |
| |
|
| | def _coords_to_alg(r: int, f: int) -> str: |
| | """Converts 0-indexed (rank, file) to algebraic notation.""" |
| | if 0 <= r < 8 and 0 <= f < 8: |
| | return f"{chr(ord('a') + f)}{r + 1}" |
| | |
| | raise ValueError(f"Invalid coordinates: ({r}, {f})") |
| |
|
| | def generate_structurally_valid_move_map() -> Dict[str, int]: |
| | """ |
| | Generates a dictionary mapping chess moves that are geometrically possible |
| | by *some* standard piece (K, Q, R, B, N, or P) to unique integer indices. |
| | It excludes moves that are structurally impossible for any piece to make |
| | in one turn (e.g., a1->h5 for non-knight). |
| | |
| | Includes standard UCI promotions (e.g., "e7e8q"), replacing the |
| | corresponding simple pawn move to the final rank (e.g., "e7e8"). |
| | This is based purely on piece movement geometry, not the current board state. |
| | |
| | Returns: |
| | Dict[str, int]: A map from the valid UCI move string to a unique |
| | integer index (0 to N-1). The size N is expected |
| | to be around 1800-1900. |
| | """ |
| | valid_moves: Set[str] = set() |
| | |
| | |
| | promo_base_moves_to_exclude: Set[str] = set() |
| |
|
| | |
| | for from_idx in range(64): |
| | from_r, from_f = _IDX_TO_COORDS[from_idx] |
| | from_alg = _IDX_TO_ALG[from_idx] |
| |
|
| | for to_idx in range(64): |
| | if from_idx == to_idx: |
| | continue |
| |
|
| | to_r, to_f = _IDX_TO_COORDS[to_idx] |
| | to_alg = _IDX_TO_ALG[to_idx] |
| | dr, df = to_r - from_r, to_f - from_f |
| | abs_dr, abs_df = abs(dr), abs(df) |
| |
|
| | |
| | |
| | |
| | |
| | is_king_move = max(abs_dr, abs_df) == 1 |
| | is_knight_move = (abs_dr == 2 and abs_df == 1) or (abs_dr == 1 and abs_df == 2) |
| | is_rook_move = dr == 0 or df == 0 |
| | is_bishop_move = abs_dr == abs_df |
| |
|
| | if is_king_move or is_knight_move or is_rook_move or is_bishop_move: |
| | uci_move = f"{from_alg}{to_alg}" |
| | valid_moves.add(uci_move) |
| |
|
| |
|
| | |
| | promo_pieces = ['q', 'r', 'b', 'n'] |
| | for from_f in range(8): |
| | |
| | from_r_w, to_r_w = 6, 7 |
| | if from_r_w != 7: |
| | from_alg_w = _coords_to_alg(from_r_w, from_f) |
| | |
| | for df in [-1, 0, 1]: |
| | to_f_w = from_f + df |
| | if 0 <= to_f_w < 8: |
| | to_alg_w = _coords_to_alg(to_r_w, to_f_w) |
| | base_move = f"{from_alg_w}{to_alg_w}" |
| | |
| | for p in promo_pieces: |
| | valid_moves.add(f"{base_move}{p}") |
| |
|
| | |
| | from_r_b, to_r_b = 1, 0 |
| | if from_r_b != 0: |
| | from_alg_b = _coords_to_alg(from_r_b, from_f) |
| | |
| | for df in [-1, 0, 1]: |
| | to_f_b = from_f + df |
| | if 0 <= to_f_b < 8: |
| | to_alg_b = _coords_to_alg(to_r_b, to_f_b) |
| | base_move = f"{from_alg_b}{to_alg_b}" |
| | |
| | for p in promo_pieces: |
| | valid_moves.add(f"{base_move}{p}") |
| |
|
| | |
| | final_valid_moves = valid_moves - promo_base_moves_to_exclude |
| |
|
| | |
| | final_valid_moves.add("<claim_draw>") |
| |
|
| | |
| | sorted_moves = sorted(list(final_valid_moves)) |
| | move_map = {move: i for i, move in enumerate(sorted_moves)} |
| |
|
| | |
| | |
| |
|
| | return move_map |
| |
|
| |
|
| | UCI_MOVE_TO_IDX = generate_structurally_valid_move_map() |
| | IDX_TO_UCI_MOVE = {v:k for k,v in UCI_MOVE_TO_IDX.items()} |