feat: add Prism snake and gameplay database lifecycle
Build and Push Docker Container / build-and-push (push) Successful in 8m3s

- Add bitboard-accelerated Prism and versioned Supreme snake implementations.
- Add database-backed move benchmarks and focused strategy tests.
- Normalize gameplay storage while preserving replay compatibility.
- Add deterministic game quality scoring and replay retention tiers.
- Add backup-first SQLite cleanup, verification, and replacement tooling.
- Add safe compact-plus-delta database merging with conflict detection.
- Extend SQLite and PostgreSQL schemas for replay and quality metadata.
- Add PostgreSQL development service and pytest import configuration.
- Update gameplay documentation and the quart_common submodule revision.
This commit is contained in:
2026-08-01 16:21:02 +02:00
parent 9a7f4de586
commit c704fbc742
21 changed files with 3156 additions and 88 deletions
+5 -25
View File
@@ -2,6 +2,8 @@ import json
from datetime import datetime, timezone
from typing import Any
from server.database.normalized_turn import hydrate_replay_turns
class GameplayBackendTemplate:
"""Abstract base for gameplay database backends.
@@ -164,19 +166,7 @@ class GameplayBackendTemplate:
(SQLite) or already-decoded objects (PostgreSQL). Pass self._from_json for
SQLite; pass (lambda x: x) for PostgreSQL.
"""
snakes_by_turn:dict[int, list[dict]] = {}
for row in snake_rows:
snakes_by_turn.setdefault(int(row["turn"]), []).append({
"snake_id": row["snake_id"],
"snake_name": row["snake_name"],
"health": row["health"],
"length": row["length"],
"head": {"x": row["head_x"], "y": row["head_y"]},
"body": decode_json(row["body_json"]) or [],
"is_you": bool(row["is_you"]),
"inferred_move": row["inferred_move"],
"latency": row["latency"],
})
hydrated_turns = hydrate_replay_turns(game_row, turn_rows, snake_rows, decode_json)
return {
"game": {
@@ -200,18 +190,8 @@ class GameplayBackendTemplate:
"status": game_row["status"],
},
"turns": [
{
"turn": int(row["turn"]),
"observed_at": self._ts_to_str(row["observed_at"]),
"my_move": row["my_move"],
"my_thinking": decode_json(row["my_thinking_json"]),
"board": decode_json(row["board_state_json"]),
"food": decode_json(row["food_json"]) or [],
"hazards": decode_json(row["hazards_json"]) or [],
"you": decode_json(row["you_json"]) or {},
"snakes": snakes_by_turn.get(int(row["turn"]), []),
}
for row in turn_rows
{**turn, "observed_at": self._ts_to_str(turn["observed_at"])}
for turn in hydrated_turns
],
}