Spaces:
Sleeping
Sleeping
| """ | |
| Move Ordering for Nexus-Nano | |
| Simplified for speed - MVV-LVA + Killer moves only | |
| """ | |
| import chess | |
| from typing import List, Optional, Dict | |
| class MoveOrderer: | |
| """Fast move ordering with minimal overhead""" | |
| PIECE_VALUES = { | |
| chess.PAWN: 100, | |
| chess.KNIGHT: 320, | |
| chess.BISHOP: 330, | |
| chess.ROOK: 500, | |
| chess.QUEEN: 900, | |
| chess.KING: 20000 | |
| } | |
| def __init__(self): | |
| # Only killer moves (no history table for speed) | |
| self.killer_moves: Dict[int, List[Optional[chess.Move]]] = {} | |
| self.max_killers = 2 | |
| self.killer_hits = 0 | |
| def order_moves( | |
| self, | |
| board: chess.Board, | |
| moves: List[chess.Move], | |
| depth: int, | |
| tt_move: Optional[chess.Move] = None | |
| ) -> List[chess.Move]: | |
| """ | |
| Fast move ordering | |
| Priority: TT move > Captures (MVV-LVA) > Killers > Others | |
| """ | |
| scored_moves = [] | |
| for move in moves: | |
| score = 0 | |
| # TT move | |
| if tt_move and move == tt_move: | |
| score += 1000000 | |
| # Captures | |
| elif board.is_capture(move): | |
| score += self._score_capture(board, move) | |
| # Quiet moves | |
| else: | |
| # Killer moves | |
| if self._is_killer(move, depth): | |
| score += 9000 | |
| self.killer_hits += 1 | |
| # Promotions | |
| if move.promotion == chess.QUEEN: | |
| score += 8000 | |
| # Checks | |
| board.push(move) | |
| if board.is_check(): | |
| score += 5000 | |
| board.pop() | |
| # Center control | |
| center = [chess.D4, chess.D5, chess.E4, chess.E5] | |
| if move.to_square in center: | |
| score += 30 | |
| scored_moves.append((score, move)) | |
| scored_moves.sort(key=lambda x: x[0], reverse=True) | |
| return [move for _, move in scored_moves] | |
| def _score_capture(self, board: chess.Board, move: chess.Move) -> int: | |
| """MVV-LVA scoring""" | |
| captured = board.piece_at(move.to_square) | |
| attacker = board.piece_at(move.from_square) | |
| if not captured or not attacker: | |
| return 0 | |
| victim = self.PIECE_VALUES.get(captured.piece_type, 0) | |
| attacker_val = self.PIECE_VALUES.get(attacker.piece_type, 1) | |
| return (victim * 10 - attacker_val) * 100 | |
| def _is_killer(self, move: chess.Move, depth: int) -> bool: | |
| killers = self.killer_moves.get(depth, []) | |
| return move in killers | |
| def update_killer_move(self, move: chess.Move, depth: int): | |
| if depth not in self.killer_moves: | |
| self.killer_moves[depth] = [] | |
| killers = self.killer_moves[depth] | |
| if move not in killers: | |
| killers.insert(0, move) | |
| self.killer_moves[depth] = killers[:self.max_killers] | |
| def clear(self): | |
| self.killer_moves.clear() | |
| self.killer_hits = 0 | |
| def get_stats(self) -> Dict: | |
| return { | |
| 'killer_hits': self.killer_hits, | |
| 'killer_depths': len(self.killer_moves) | |
| } |