You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A real-time competitive multiplayer Sudoku platform. Players race to solve the same puzzle simultaneously — first to fill all blank cells wins, or the player with the most correct cells when time runs out.
Features
Multiplayer matches — any number of players (2-4) solve the same puzzle at the same time
Live opponent progress — see opponents' cell count and mistake count update in real time via WebSocket
Lobby system — create a lobby, share an invite link, configure time and mistake limits, start when ready
Casual & ranked modes — ranked matches update ELO ratings; casual matches do not
ELO rating system — standard ELO (K=32), starting at 1200; updated atomically on match end via round-robin pairwise comparisons for matches with more than two players
Mistake limit — configurable per lobby (default 3, range 0–10); a player is eliminated when their mistake count exceeds the limit; if all players are eliminated the best score still wins
Time limit — configurable per lobby (default 10 min, range 5–25 min); when time runs out the winner is decided by most correct cells, then fewest mistakes
Puzzle generation — server-side backtracking generator; every puzzle is guaranteed to have a unique solution; solution is never sent to clients
Difficulty levels — Easy, Medium, Hard (classified by naked/hidden single analysis of the given cells)
Player profiles — ELO, win/loss record, full paginated match history
Global leaderboard — top players ranked by ELO
Stack
Layer
Technology
Backend
Python 3.11+, FastAPI
Real-time
WebSockets (FastAPI / Starlette)
Database
SQLite (dev) / PostgreSQL 16 (Docker)
ORM / migrations
SQLAlchemy 2 + Alembic
Validation
Pydantic v2
Auth
JWT (python-jose, HS256)
Password hashing
passlib[bcrypt]
Frontend
React 18, TypeScript, Vite
Styling
Plain CSS
Testing
pytest, pytest-asyncio
Deployment
Docker + docker-compose
Quick Start (Docker)
Prerequisite: Docker Desktop running.
# 1. Copy env config — defaults work for local Docker
cp .env.example .env
# 2. Build and start all three services
docker compose up --build
Broadcast to all participants after every accepted move.
player_eliminated
{type, user_id, username}
Broadcast when a player's mistake count exceeds mistake_limit.
match_end
{type, winner_id, reason, elo_deltas}
Broadcast when the match resolves. reason: completed, time_up, or mistake_limit. elo_deltas is a {user_id: delta} map, present only for ranked matches.
error
{type, detail}
Sent to the client when a message is rejected (invalid format, eliminated player, etc.).
Data Model
users
Field
Type
Notes
id
UUID
Primary key
username
text
Unique, 1–32 chars, alphanumeric/_/-
email
text
Unique
password_hash
text
bcrypt
elo_rating
integer
Default 1200
wins
integer
Default 0
losses
integer
Default 0
created_at
timestamp
puzzles
Field
Type
Notes
id
UUID
Primary key
difficulty
enum
easy / medium / hard
givens
JSON
81-element array, 0 = empty cell
solution
JSON
Full solved grid — never sent to clients
created_at
timestamp
matches
Field
Type
Notes
id
UUID
Primary key
puzzle_id
UUID
FK → puzzles
mode
enum
casual / ranked
status
enum
waiting / active / finished
time_limit_s
integer
Default 600 (10 min)
mistake_limit
integer
Default 3; player eliminated when mistakes > mistake_limit
started_at
timestamp
ended_at
timestamp
Null until resolved
winner_id
UUID
FK → users, null on draw
match_participants
Field
Type
Notes
match_id
UUID
FK → matches (composite PK)
user_id
UUID
FK → users (composite PK)
cells_correct
integer
mistakes
integer
board_state
JSON
Player's current 81-element cell array
solve_time_ms
integer
Set only for the match winner
elo_before
integer
Null for casual matches
elo_after
integer
Null for casual matches
lobbies
Field
Type
Notes
id
UUID
Primary key
code
text (8 chars)
Unique invite code
creator_id
UUID
FK → users
mode
enum
casual / ranked
difficulty
enum
easy / medium / hard
status
enum
waiting / active
match_id
UUID
Set after start, FK → matches
time_limit_min
integer
Default 10, range 5–25
mistake_limit
integer
Default 3, range 0–10
lobby_members
Field
Type
Notes
lobby_id
UUID
FK → lobbies (composite PK)
user_id
UUID
FK → users (composite PK)
joined_at
timestamp
About
A real-time competitive multiplayer Sudoku platform. Players race to solve the same puzzle simultaneously — first to fill all blank cells wins, or the player with the most correct cells when time runs out.