fix svg color problem show dead resions when very sure and allow to highlight snakes when clicking into them store timout and calcumate Snake Win Rate Overall, fix to use full page of games-body, get win lloss or unknown

This commit is contained in:
2026-04-05 23:01:27 +02:00
parent 050dd1083c
commit b7c6a0e345
2 changed files with 246 additions and 34 deletions
+47 -9
View File
@@ -88,6 +88,8 @@ class GameplayDatabase:
self._ensure_column_exists(connection, "turns", "my_thinking_json", "TEXT")
self._ensure_column_exists(connection, "games", "your_snake_type", "TEXT")
self._ensure_column_exists(connection, "games", "your_snake_version", "TEXT")
self._ensure_column_exists(connection, "games", "game_type", "TEXT")
self._ensure_column_exists(connection, "snake_turns", "latency", "TEXT")
connection.execute("PRAGMA optimize")
def _ensure_column_exists(self, connection:sqlite3.Connection, table_name:str, column_name:str, column_type:str) -> None:
@@ -133,19 +135,26 @@ class GameplayDatabase:
return "down"
return None
def _derive_game_type(self, board:dict, ruleset:dict) -> str:
initial_snake_count = len(board.get("snakes", []))
if initial_snake_count == 2:
return "duel"
return ruleset.get("name") or "standard"
def _record_game_start_sync(self, game_state:dict, snake_type:str|None=None, snake_version:str|None=None) -> None:
game = game_state.get("game", {})
board = game_state.get("board", {})
you = self._extract_you(game_state)
ruleset = game.get("ruleset", {})
game_type = self._derive_game_type(board, ruleset)
with self._connect() as connection:
connection.execute("""
INSERT INTO games (
game_id, started_at, width, height, source, map_name,
ruleset_name, ruleset_version, your_snake_id, your_snake_name,
your_snake_type, your_snake_version, status
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'running')
your_snake_type, your_snake_version, game_type, status
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'running')
ON CONFLICT(game_id) DO UPDATE SET
width = excluded.width,
height = excluded.height,
@@ -157,6 +166,7 @@ class GameplayDatabase:
your_snake_name = excluded.your_snake_name,
your_snake_type = excluded.your_snake_type,
your_snake_version = excluded.your_snake_version,
game_type = excluded.game_type,
status = 'running'
""",
(
@@ -172,6 +182,7 @@ class GameplayDatabase:
you.get("name"),
snake_type,
snake_version,
game_type,
),
)
connection.execute("PRAGMA wal_checkpoint(PASSIVE)")
@@ -253,8 +264,8 @@ class GameplayDatabase:
connection.execute("""
INSERT INTO snake_turns (
game_id, turn, snake_id, snake_name, health, length,
head_x, head_y, body_json, is_you, inferred_move
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
head_x, head_y, body_json, is_you, inferred_move, latency
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(game_id, turn, snake_id) DO UPDATE SET
snake_name = excluded.snake_name,
health = excluded.health,
@@ -263,7 +274,8 @@ class GameplayDatabase:
head_y = excluded.head_y,
body_json = excluded.body_json,
is_you = excluded.is_you,
inferred_move = excluded.inferred_move
inferred_move = excluded.inferred_move,
latency = excluded.latency
""",
(
game_id,
@@ -277,6 +289,7 @@ class GameplayDatabase:
self._to_json(snake.get("body", [])),
1 if snake_id == you_id else 0,
inferred,
snake.get("latency"),
),
)
@@ -332,8 +345,22 @@ class GameplayDatabase:
"""
).fetchone()
by_type = connection.execute("""
SELECT
COALESCE(game_type, ruleset_name, 'unknown') AS type_label,
COUNT(*) AS total,
SUM(CASE WHEN status = 'finished' AND winner_you = 1 THEN 1 ELSE 0 END) AS wins,
SUM(CASE WHEN status = 'finished' AND winner_you = 0 THEN 1 ELSE 0 END) AS losses
FROM games
WHERE status = 'finished'
GROUP BY type_label
ORDER BY total DESC
"""
).fetchall()
recent = connection.execute("""
SELECT game_id, started_at, ended_at, map_name, your_snake_name, your_snake_type, your_snake_version, winner_you, final_turn, status
SELECT game_id, started_at, ended_at, map_name, ruleset_name, game_type,
your_snake_name, your_snake_type, your_snake_version, winner_you, final_turn, status
FROM games
ORDER BY started_at DESC
LIMIT ?
@@ -349,11 +376,19 @@ class GameplayDatabase:
"wins": int(totals["wins"] or 0),
"losses": int(totals["losses"] or 0),
"avg_turns_finished": round(float(totals["avg_turns"] or 0.0), 2),
"by_game_type": [{
"game_type": row["type_label"],
"total": int(row["total"]),
"wins": int(row["wins"]),
"losses": int(row["losses"]),
} for row in by_type],
"recent_games": [{
"game_id": row["game_id"],
"started_at": row["started_at"],
"ended_at": row["ended_at"],
"map": row["map_name"],
"ruleset": row["ruleset_name"],
"game_type": row["game_type"],
"snake": row["your_snake_name"],
"snake_type": row["your_snake_type"],
"snake_version": row["your_snake_version"],
@@ -366,7 +401,7 @@ class GameplayDatabase:
def _list_games_sync(self, limit:int=50) -> list[dict]:
with self._connect() as connection:
rows = connection.execute("""
SELECT game_id, started_at, ended_at, map_name, source, ruleset_name,
SELECT game_id, started_at, ended_at, map_name, source, ruleset_name, game_type,
your_snake_name, your_snake_type, your_snake_version,
winner_you, winner_names_json, final_turn, status
FROM games
@@ -383,6 +418,7 @@ class GameplayDatabase:
"map": row["map_name"],
"source": row["source"],
"ruleset": row["ruleset_name"],
"game_type": row["game_type"],
"snake": row["your_snake_name"],
"snake_type": row["your_snake_type"],
"snake_version": row["your_snake_version"],
@@ -396,7 +432,7 @@ class GameplayDatabase:
with self._connect() as connection:
game_row = connection.execute("""
SELECT game_id, started_at, ended_at, width, height, source, map_name,
ruleset_name, ruleset_version, your_snake_id, your_snake_name,
ruleset_name, ruleset_version, game_type, your_snake_id, your_snake_name,
your_snake_type, your_snake_version,
winner_names_json, winner_you, final_turn, status
FROM games
@@ -420,7 +456,7 @@ class GameplayDatabase:
snake_rows = connection.execute("""
SELECT turn, snake_id, snake_name, health, length, head_x, head_y,
body_json, is_you, inferred_move
body_json, is_you, inferred_move, latency
FROM snake_turns
WHERE game_id = ?
ORDER BY turn ASC, is_you DESC, snake_name ASC
@@ -440,6 +476,7 @@ class GameplayDatabase:
"body": self._from_json(row["body_json"]) or [],
"is_you": bool(row["is_you"]),
"inferred_move": row["inferred_move"],
"latency": row["latency"],
})
replay_turns = []
@@ -468,6 +505,7 @@ class GameplayDatabase:
"map": game_row["map_name"],
"ruleset_name": game_row["ruleset_name"],
"ruleset_version": game_row["ruleset_version"],
"game_type": game_row["game_type"],
"your_snake_id": game_row["your_snake_id"],
"your_snake_name": game_row["your_snake_name"],
"your_snake_type": game_row["your_snake_type"],