"""Reusable compact duel-search integration for Apex-style snakes.""" from __future__ import annotations from snakes.engine.duel_search import BitboardDuelSearch class BitboardDuelMixin: def _new_duel_search( self, food_set: set, hazard_set: set, hazard_count: dict, hazard_damage: int, width: int, height: int, deadline: float | None, ) -> BitboardDuelSearch: if self._duel_search_context is None: self._duel_search_context = BitboardDuelSearch( board=self._get_bb(width, height), food=food_set, hazards=hazard_set, hazard_count=hazard_count, hazard_damage=hazard_damage, deadline=deadline, ) return self._duel_search_context def _minimax_candidate_id( self, my_body: list, enemy_body: list, my_target: tuple[int, int], food_set: set, hazard_set: set, my_health: int, enemy_health: int, hazard_damage: int, hazard_count: dict, width: int, height: int, max_depth: int, alpha: float, beta: float, deadline: float | None, previous_hazard_set: set | None = None, ) -> tuple[float, int]: """Resolve our selected move and every enemy reply simultaneously.""" search = self._new_duel_search( food_set, hazard_set, hazard_count, hazard_damage, width, height, deadline, ) adaptive_depth = max_depth remaining = self._remaining_ms(deadline) if remaining > 250: adaptive_depth = min(7, max_depth + 1) elif remaining < 120: adaptive_depth = min(max_depth, 2) return search.search_candidate( my_body=my_body, enemy_body=enemy_body, my_target=my_target, my_health=my_health, enemy_health=enemy_health, max_depth=adaptive_depth, previous_hazards=previous_hazard_set if previous_hazard_set is not None else hazard_set, ) def _minimax_sim_id( self, my_body: list, enemy_body: list, food_set: set, hazard_set: set, my_health: int, enemy_health: int, hazard_damage: int, hazard_count: dict, width: int, height: int, max_depth: int, alpha: float, beta: float, deadline: float | None, previous_hazard_set: set | None = None, ) -> tuple[float, int]: """Run iterative deepening with one reusable compact search context.""" search = self._new_duel_search( food_set, hazard_set, hazard_count, hazard_damage, width, height, deadline, ) return search.search( my_body=my_body, enemy_body=enemy_body, my_health=my_health, enemy_health=enemy_health, max_depth=max_depth, previous_hazards=previous_hazard_set if previous_hazard_set is not None else hazard_set, ) def _minimax_sim( self, my_body: list, enemy_body: list, food_set: set, hazard_set: set, my_health: int, enemy_health: int, hazard_damage: int, hazard_count: dict, width: int, height: int, depth: int, alpha: float, beta: float, deadline: float | None, previous_hazard_set: set | None = None, ) -> float: """Compatibility entry point for tests and callers requesting one depth.""" search = self._new_duel_search( food_set, hazard_set, hazard_count, hazard_damage, width, height, deadline, ) return search.search_depth( my_body=my_body, enemy_body=enemy_body, my_health=my_health, enemy_health=enemy_health, depth=depth, previous_hazards=previous_hazard_set if previous_hazard_set is not None else hazard_set, )