""" 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) }