legomaheggo's picture
feat: Add config, database, realtime, and UI layers with full multiplayer gameplay
a9b6601
"""
Devil's Dozen - Lobby Manager
CRUD operations for the `lobbies` table.
"""
import secrets
import string
from supabase import Client
from src.database.models import Lobby
def _generate_code(length: int = 6) -> str:
"""Generate an alphanumeric lobby code, avoiding ambiguous characters."""
alphabet = string.ascii_uppercase.replace("O", "").replace("I", "")
alphabet += string.digits.replace("0", "").replace("1", "")
return "".join(secrets.choice(alphabet) for _ in range(length))
class LobbyManager:
"""Manages lobby lifecycle in Supabase."""
def __init__(self, client: Client) -> None:
self.client = client
self.table = client.table("lobbies")
def create(self, game_mode: str, win_condition: int) -> Lobby:
"""Create a new lobby with a unique code."""
code = _generate_code()
data = (
self.table
.insert({
"code": code,
"game_mode": game_mode,
"win_condition": win_condition,
})
.execute()
)
return Lobby.model_validate(data.data[0])
def get_by_code(self, code: str) -> Lobby | None:
"""Look up a lobby by its join code."""
data = (
self.table
.select("*")
.eq("code", code.upper())
.execute()
)
if data.data:
return Lobby.model_validate(data.data[0])
return None
def get_by_id(self, lobby_id: str) -> Lobby | None:
"""Look up a lobby by its UUID."""
data = (
self.table
.select("*")
.eq("id", lobby_id)
.execute()
)
if data.data:
return Lobby.model_validate(data.data[0])
return None
def update_status(self, lobby_id: str, status: str) -> Lobby:
"""Update lobby status (waiting, playing, finished)."""
data = (
self.table
.update({"status": status})
.eq("id", lobby_id)
.execute()
)
return Lobby.model_validate(data.data[0])
def advance_turn(self, lobby_id: str, next_turn_index: int) -> Lobby:
"""Move to the next player's turn."""
data = (
self.table
.update({"current_turn_index": next_turn_index})
.eq("id", lobby_id)
.execute()
)
return Lobby.model_validate(data.data[0])
def set_winner(self, lobby_id: str, winner_id: str) -> Lobby:
"""Record the winning player and mark lobby as finished."""
data = (
self.table
.update({
"winner_id": winner_id,
"status": "finished",
})
.eq("id", lobby_id)
.execute()
)
return Lobby.model_validate(data.data[0])
def delete(self, lobby_id: str) -> None:
"""Delete a lobby (cascades to players and game_state)."""
self.table.delete().eq("id", lobby_id).execute()