fix: resolve duel roots and recover legacy snake data
- Resolve selected moves and enemy replies on the same simulated turn. - Add an Apex candidate hook and bump the Prism snake to version 1.1.0. - Rebuild benchmark states from normalized turn data when snapshots are empty. - Synthesize missing game snake identities during legacy database migration. - Add regression coverage for duel timing and partial legacy schemas.
This commit is contained in:
@@ -468,15 +468,11 @@ class ApexBattleSnake(TemplateSnake):
|
||||
if self._time_exceeded(deadline):
|
||||
break
|
||||
pos = safe_moves[m]
|
||||
ate = (pos["x"], pos["y"]) in food_set
|
||||
fb = self._future_body(my_body, pos, ate, False)
|
||||
nmy_h = 100 if ate else my_health - 1
|
||||
if (pos["x"], pos["y"]) in hazard_set and not ate:
|
||||
nmy_h -= hazard_damage * hazard_count.get((pos["x"], pos["y"]), 1)
|
||||
mm_val, depth_done = self._minimax_sim_id(
|
||||
my_body=fb, enemy_body=enemy["body"],
|
||||
mm_val, depth_done = self._minimax_candidate_id(
|
||||
my_body=my_body, enemy_body=enemy["body"],
|
||||
my_target=(pos["x"], pos["y"]),
|
||||
food_set=food_set, hazard_set=hazard_set,
|
||||
my_health=nmy_h, enemy_health=enemy_health,
|
||||
my_health=my_health, enemy_health=enemy_health,
|
||||
hazard_damage=hazard_damage, hazard_count=hazard_count,
|
||||
width=width, height=height,
|
||||
max_depth=self._planning_depth,
|
||||
@@ -893,6 +889,55 @@ class ApexBattleSnake(TemplateSnake):
|
||||
|
||||
# ── A1: Iterative deepening minimax ──────────────────────────────────────────
|
||||
|
||||
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]:
|
||||
"""Evaluate a selected move before continuing the legacy duel search.
|
||||
|
||||
Optimized subclasses can override this hook to resolve our selected move
|
||||
and the opponent's reply simultaneously at the search root.
|
||||
"""
|
||||
pos = {"x": my_target[0], "y": my_target[1]}
|
||||
ate = my_target in food_set
|
||||
future_body = self._future_body(my_body, pos, ate, False)
|
||||
future_health = 100 if ate else my_health - 1
|
||||
effective_previous = previous_hazard_set if previous_hazard_set is not None else hazard_set
|
||||
if my_target in hazard_set and my_target in effective_previous and not ate:
|
||||
future_health -= hazard_damage * hazard_count.get(my_target, 1)
|
||||
return self._minimax_sim_id(
|
||||
my_body=future_body,
|
||||
enemy_body=enemy_body,
|
||||
food_set=food_set,
|
||||
hazard_set=hazard_set,
|
||||
my_health=future_health,
|
||||
enemy_health=enemy_health,
|
||||
hazard_damage=hazard_damage,
|
||||
hazard_count=hazard_count,
|
||||
width=width,
|
||||
height=height,
|
||||
max_depth=max_depth,
|
||||
alpha=alpha,
|
||||
beta=beta,
|
||||
deadline=deadline,
|
||||
previous_hazard_set=previous_hazard_set,
|
||||
)
|
||||
|
||||
def _minimax_sim_id(
|
||||
self,
|
||||
my_body: list,
|
||||
|
||||
Reference in New Issue
Block a user