feat(snake): optimize duels and persist customizations
Build and Push Docker Container / build-and-push (push) Successful in 7m29s
Build and Push Docker Container / build-and-push (push) Successful in 7m29s
- Add deadline-aware iterative duel search with bitboards and tuple bodies. - Reuse transposition bounds and move-order hints across search depths. - Persist snake colors, heads, and tails in SQLite and PostgreSQL. - Restore customization metadata when hydrating dashboard replays. - Cover duel deadlines, cache reuse, schema storage, and replay output.
This commit is contained in:
@@ -23,6 +23,8 @@ Key speedups:
|
||||
S10: _legal_moves override uses bitboard neighbour mask instead of
|
||||
per-direction Python loop + _in_bounds calls.
|
||||
S11: _future_survival_tree inlines legal-move check with bitboard ops.
|
||||
S12: Duel minimax uses tuple bodies and bitboard move generation.
|
||||
S13: Iterative deepening reuses a transposition table and move-order hints.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -31,6 +33,7 @@ from time import perf_counter
|
||||
|
||||
from snakes.ApexBattleSnake import ApexBattleSnake
|
||||
from snakes.bitboard import BitBoard
|
||||
from snakes.bitboard_duel_search import BitboardDuelSearch
|
||||
from server.GameBoard import GameBoard
|
||||
|
||||
# Direction offsets for coord-dict → tuple conversion
|
||||
@@ -245,6 +248,61 @@ class PrismBattleSnake_GPT_5_6_Sol(ApexBattleSnake):
|
||||
blocked_bits = self._blocked_to_bits(blocked, width, height)
|
||||
return bb.open_neighbor_count(bb.idx(head["x"], head["y"]), blocked_bits)
|
||||
|
||||
# ── S12/S13: compact bitboard duel search ───────────────────────────────
|
||||
|
||||
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:
|
||||
return BitboardDuelSearch(
|
||||
board=self._get_bb(width, height),
|
||||
food=food_set,
|
||||
hazards=hazard_set,
|
||||
hazard_count=hazard_count,
|
||||
hazard_damage=hazard_damage,
|
||||
deadline=deadline,
|
||||
)
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
# ── S9: Optimised survival tree (bitboard-native) ────────────────────────
|
||||
|
||||
def _future_position_score(
|
||||
|
||||
Reference in New Issue
Block a user