feat(snake): optimize duels and persist customizations
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:
2026-08-01 17:19:35 +02:00
parent 65c97b219b
commit 4f022d3d01
7 changed files with 449 additions and 11 deletions
@@ -76,6 +76,7 @@ CREATE TABLE IF NOT EXISTS game_snakes (
snake_id TEXT NOT NULL,
snake_name TEXT,
is_you BOOLEAN NOT NULL DEFAULT FALSE,
customizations JSONB NOT NULL DEFAULT '{}'::jsonb,
PRIMARY KEY (game_id, snake_id)
);
@@ -114,6 +115,7 @@ ALTER TABLE games ADD COLUMN IF NOT EXISTS quality_tier TEXT;
ALTER TABLE games ADD COLUMN IF NOT EXISTS quality_reasons JSONB;
ALTER TABLE turns ADD COLUMN IF NOT EXISTS my_thinking JSONB;
ALTER TABLE snake_turns ADD COLUMN IF NOT EXISTS latency TEXT;
ALTER TABLE game_snakes ADD COLUMN IF NOT EXISTS customizations JSONB NOT NULL DEFAULT '{}'::jsonb;
"""
# Force TOAST compression on the large JSONB columns so that even
@@ -458,14 +460,22 @@ class PostgresqlGameplayBackend(GameplayBackendTemplate):
async with pool.acquire() as conn:
async with conn.transaction():
await conn.executemany("""
INSERT INTO game_snakes (game_id, snake_id, snake_name, is_you)
VALUES ($1,$2,$3,$4)
INSERT INTO game_snakes (
game_id, snake_id, snake_name, is_you, customizations
) VALUES ($1,$2,$3,$4,$5)
ON CONFLICT (game_id, snake_id) DO UPDATE SET
snake_name = EXCLUDED.snake_name,
is_you = EXCLUDED.is_you
is_you = EXCLUDED.is_you,
customizations = EXCLUDED.customizations
""",
[
(game_id, snake.get("id"), snake.get("name"), snake.get("id") == you.get("id"))
(
game_id,
snake.get("id"),
snake.get("name"),
snake.get("id") == you.get("id"),
snake.get("customizations") or {},
)
for snake in snakes if snake.get("id") is not None
],
)
@@ -739,6 +749,7 @@ class PostgresqlGameplayBackend(GameplayBackendTemplate):
COALESCE(gs.snake_name, st.snake_name) AS snake_name,
st.health, st.length, st.head_x, st.head_y, st.body AS body_json,
COALESCE(gs.is_you, st.is_you) AS is_you,
COALESCE(gs.customizations, '{}'::jsonb) AS customizations_json,
st.inferred_move, st.latency
FROM snake_turns AS st
LEFT JOIN game_snakes AS gs