"""Load sampled gameplay positions from a SQLite or PostgreSQL gameplay DB.""" import asyncio from urllib.parse import urlparse def is_postgresql_source(source:str) -> bool: return urlparse(source).scheme.lower() in {"postgres", "postgresql"} def replay_turn_to_state(game:dict, turn:dict) -> tuple[dict, dict]|None: board = turn.get("board") or {} you = turn.get("you") or {} if not you or not board.get("snakes"): return None return board, { "you": you, "game_id": game["game_id"], "source": game.get("source") or "custom", "map": game.get("map") or "standard", "ruleset": { "name": game.get("ruleset_name") or "standard", "version": game.get("ruleset_version") or "v1.0.0", "settings": {}, }, "turn": int(turn["turn"]), } async def sample_states(backend, samples:int, stride:int) -> list[tuple[dict, dict]]: """Every ``stride``-th stored turn, newest games first.""" states = [] seen = 0 for game_id in reversed(await backend.list_game_ids()): replay = await backend.get_game_replay(game_id) if replay is None: continue for turn in reversed(replay["turns"]): if seen % stride == 0: state = replay_turn_to_state(replay["game"], turn) if state is not None: states.append(state) if len(states) >= samples: return states seen += 1 return states async def _load_states(source:str, samples:int, stride:int) -> list[tuple[dict, dict]]: if is_postgresql_source(source): from server.database.backend.PostgresqlGameplayBackend import PostgresqlGameplayBackend # noqa: PLC0415 backend = PostgresqlGameplayBackend(source) else: from server.database.backend.SqliteGameplayBackend import SqliteGameplayBackend # noqa: PLC0415 backend = SqliteGameplayBackend(source, read_only=True) try: return await sample_states(backend, samples, stride) finally: await backend.close() def load_states(source:str, samples:int, stride:int) -> list[tuple[dict, dict]]: return asyncio.run(_load_states(source, max(1, samples), max(1, stride)))