Skip to content

About

Real-time multiplayer coding elimination game with live code execution, isolated Docker judging, authentication, leaderboards, and reconnectable matches.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

ย 

History

774 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Code Chamber

A real-time multiplayer coding game: solve, survive, and be the last player standing

React Node.js PostgreSQL Docker Cloudflare

โ–ถ Play Code Chamber


๐Ÿ“– Overview

Code Chamber turns coding challenges into a multiplayer elimination game. Players join a room, solve the same problem against the clock, and submit real code in JavaScript, Python, or C++. Submissions are executed on the server against test cases, scored, and used to determine who survives the round.

Correctness, submission speed, and execution time all contribute to your score. Elimination is randomized and weighted by that score, so better performance improves your chances of survival without guaranteeing safety. Random round events add double eliminations, shorter timers, and narrow escapes. The game continues until one player remains.

The project brings together a browser-based code editor, real-time multiplayer state, containerized code execution, authentication, persistent player statistics, and a self-managed deployment on a laptop server at home.

Inspired by LeetCode-style coding challenges, Code Chamber started with a simple idea: make solving coding problems multiplayer and fun. Timed rounds, live competition, and unpredictable eliminations turn individual practice into a shared survival game.


๐ŸŽฌ Demos & GIFs

Home Page

Code Chamber home page

Touring the home page, with shortcuts to create or browse chambers, live platform statistics, and a preview of the global rankings.



Creating and Joining Chambers

Creating a chamber

Creating a chamber by choosing its name, difficulty, player limit, and public or private visibility, then entering the waiting lobby.



Joining a chamber and starting a match

A guest joins a public chamber, the lobby updates to show both players, and the host starts the match countdown.



Coding Workspace

Switching editor languages

Switching between JavaScript, Python, and C++ to view each language's starter code for the same question.



Submitting code and reviewing test cases

Submitting a solution and inspecting individual failed test cases, including their inputs, actual outputs, and expected outputs.



Language drafts and player submission status

Opening the player list to see who has submitted and who is still working.



Resizing the coding workspace

Resizing the question and editor panels and expanding or collapsing the output panel to adjust the coding workspace.



Profile Page

Player profile and language statistics

Browsing account details, linked sign-in providers, game statistics, and a breakdown of submission performance by language.



Match history and round details

Loading more match history and expanding a match to review its round submissions, language, difficulty, and performance details.


๐ŸŽฎ How to Play

  1. Visit codechamber.dev and play as a guest or sign in.
  2. Browse public rooms, join with a room code, or create a public or private room.
  3. Choose a difficulty and wait for the host to start the match.
  4. Solve each round's problem in JavaScript, Python, or C++ before time runs out.
  5. Submit your solution, review the results, and survive the elimination.
  6. Keep surviving until you are the last player standing.

Standard round durations are 5 minutes for easy, 7.5 minutes for medium, and 10 minutes for hard, with round events able to shorten the timer.


โœจ Features

๐Ÿ† Multiplayer & Gameplay

  • Public and private rooms โ€” create a lobby with a name, player limit, and difficulty, or invite friends using a six-character room code.
  • Live room browser โ€” public lobby additions, player counts, updates, and removals arrive through Socket.IO.
  • Timed coding rounds โ€” shared questions, countdowns, submission status, results, and winner announcements follow a server-managed lifecycle.
  • Score-weighted elimination โ€” test-case success, submission time, and execution time affect survival odds.
  • Random round events โ€” double elimination, faster timers, and a missed bullet that spares a selected player.
  • Automatic submission โ€” when time expires, the server requests unfinished players' current code for judging.
  • Reconnection handling โ€” a brief grace period lets disconnected players rejoin, with the current game phase and submission status restored.

๐Ÿ’ป Coding Experience

  • Monaco Editor โ€” an embedded editor with syntax highlighting and language-specific starter code.
  • Three supported languages โ€” JavaScript, Python, and C++17, including server-side C++ compilation.
  • Drafts preserved when switching languages โ€” change languages during a round without losing each language's current code.
  • Persistent editor preferences โ€” font size, tab size, language choice, and relative line-number settings saved locally.
  • Detailed submission feedback โ€” test-case inputs, expected and actual outputs, execution timing, debug output, and compilation or runtime errors.
  • Editor error locations โ€” generated wrapper offsets are accounted for when reporting error lines back to the player.
  • Resizable workspace โ€” adjust the split between the question and editor panels.
  • Client-side anti-cheat measures โ€” Game blocks copy, cut, paste, and drag-and-drop, and reverts edits that insert too many characters at once. These checks run locally without additional server requests, discouraging copied solutions while keeping network traffic low.

๐Ÿ‘ค Accounts & Progress

  • Guest play โ€” join games without creating an account; persistent statistics are reserved for registered players.
  • Multiple sign-in options โ€” username and password, Google, GitHub, and Discord through Better Auth.
  • Player profiles โ€” persistent submission and match statistics backed by PostgreSQL.
  • Match history โ€” review previous matches, round submissions, and outcomes.
  • Global leaderboards โ€” rankings across multiple metrics, with language and difficulty filters where applicable.
  • Live platform statistics โ€” server-sent events deliver updates without repeated client polling.
  • Account deletion โ€” account removal includes cleanup of player info in db, without breaking other players' match history that include the deleted account.

๐Ÿง  Technical Highlights

Containerized Code Execution

Running player-written code is central to the game. Each submission uses a Docker container configured with no network access, a read-only root filesystem, restricted writable temporary directories, dropped Linux capabilities, and limits on memory, CPU, and process count.

Language-specific wrappers accept test-case arguments as JSON, call the submitted function, and return structured output and timing information. C++ submissions are compiled against a custom wrapper before execution. The judge compares outputs with expected values and returns individual test-case results to the player.

A pool of ready containers reduces startup work during submissions. Containers are removed after use and replaced in the background. Per-language semaphores and bounded test-case concurrency control execution load, while retry logic and periodic orphan cleanup manage container failures and lifecycle cleanup.

Coordinating a Real-Time Match

A round has to coordinate more than a timer: players submit at different times, code execution finishes asynchronously, and some submissions may still be processing when the deadline arrives.

The server manages countdowns, deadlines, submission eligibility, pending judging work, automatic submissions, scoring, and elimination. Socket.IO delivers phase changes and player status updates to each room, keeping everyone informed as players move from coding to judging to results.

If every player finishes submitting early, the round timer ends early. When time expires, manual submissions close, the server requests unfinished playersโ€™ current code, and pending judging work completes before scores and eliminations are calculated. This prevents results from being finalized while submissions are still being processed

Reconnection Without Losing the Match

A disconnect can happen during the countdown, while a player is coding, while their submission is being judged, or during results. Each phase needs different recovery behavior, making reconnection more involved than simply reopening a socket.

The server briefly preserves the disconnected playerโ€™s place in the match. If they reconnect within the grace period, it attaches their existing player record to the new socket, restores room membership, and sends a snapshot of the current game phase and submission status so the interface can recover.

Round transitions also coordinate with reconnecting players and pending submissions before processing results. If the grace period expires, the player is removed and the match continues. This keeps temporary connection loss from immediately ending a playerโ€™s game while preventing abandoned connections from holding up the match indefinitely.

Separating Live State from Persistent Records

Active rooms and round state live in server memory, while PostgreSQL stores users, sessions, questions, starter code, solutions, test cases, submissions, eliminations, and match outcomes.

This keeps active gameplay state immediately available to the multiplayer systems while retaining records for profiles, leaderboards, and match history. Numbered SQL migrations track schema changes, and a separate seed script loads the question dataset.

Reducing Repeated Work

Public-room broadcasts are batched every 500 ms, combining changes and retaining the latest update for each room. Leaderboard results are precomputed every 60 seconds across language and difficulty combinations, allowing API requests to read cached rankings instead of rerunning all aggregation queries.

Live platform statistics use a separate precomputation process and a server-sent event stream. REST endpoints also apply rate limits, including separate limits for sensitive authentication actions.


๐ŸŒ Self-Hosted Deployment

I deployed Code Chamber myself. The backend and Docker execution environment run on my own laptop server at home, running Ubuntu LTS. The frontend is hosted on Cloudflare, and Neon provides the PostgreSQL database.

Backend traffic passes through Cloudflare Tunnel. The home server establishes an outbound connection to Cloudflare, and clients send API and Socket.IO traffic to the Cloudflare-facing endpoint. This keeps clients from connecting directly to the home server, avoids exposing its origin IP through the application's public endpoint, and adds Cloudflare as a protective layer in front of the backend. See Cloudflare's tunnel documentation for the connection model.

Here's the model described visually:

flowchart LR
    Browser[Player browser] <--> Frontend[Frontend hosted on Cloudflare]
    Browser <-->|API and Socket.IO| Edge[Cloudflare backend endpoint]
    Edge <-->|Cloudflare Tunnel| Server[Home laptop server ยท Ubuntu LTS]
    Server <--> Docker[Docker code execution]
    Server <-->|Persistent data| Neon[Neon PostgreSQL]
Loading

๐Ÿ› ๏ธ Built With

Technology Purpose
React Frontend pages, game interface, and shared application state
Vite Frontend development server and production builds
Tailwind CSS Interface styling
Monaco Editor Browser-based coding workspace
Framer Motion Interface animations
Node.js & Express Backend APIs and game orchestration
Socket.IO Real-time lobbies, gameplay events, and reconnection
Better Auth Sessions, email/password authentication, and social sign-in
PostgreSQL & Neon Persistent accounts, questions, submissions, and match records
node-postgres & Kysely Database queries, connection pooling, and authentication database integration
Docker Isolated language execution environments
JavaScript, Python & C++17 Supported player submission languages
Cloudflare & Cloudflare Tunnel Frontend hosting and proxied access to the home backend
Ubuntu LTS Operating system on the home laptop server
Vitest & React Testing Library Backend unit tests and frontend component and hook tests

๐Ÿ“‚ Project Structure

code-chamber/
โ”œโ”€โ”€ client/
โ”‚   โ”œโ”€โ”€ src/
โ”‚   โ”‚   โ”œโ”€โ”€ components/       # Navigation, route guards, editor, and game UI
โ”‚   โ”‚   โ”œโ”€โ”€ context/          # Session, player, server health, and live stats
โ”‚   โ”‚   โ”œโ”€โ”€ hooks/            # Shared hooks and game event handling
โ”‚   โ”‚   โ”œโ”€โ”€ layouts/          # Main and game layouts
โ”‚   โ”‚   โ”œโ”€โ”€ pages/            # Lobbies, gameplay, accounts, and leaderboards
โ”‚   โ”‚   โ”œโ”€โ”€ test/             # Frontend test setup and shared mocks
โ”‚   โ”‚   โ”œโ”€โ”€ utils/            # Timer and timeout utilities
โ”‚   โ”‚   โ”œโ”€โ”€ App.jsx           # Root application component
โ”‚   โ”‚   โ”œโ”€โ”€ main.jsx          # Frontend entry point
โ”‚   โ”‚   โ”œโ”€โ”€ router.jsx        # Application routes
โ”‚   โ”‚   โ”œโ”€โ”€ authClient.js     # Authentication client
โ”‚   โ”‚   โ”œโ”€โ”€ socket.js         # Socket.IO client and connection handling
โ”‚   โ”‚   โ””โ”€โ”€ index.css         # Global styles
โ”‚   โ”œโ”€โ”€ .env.example          # Frontend environment template
โ”‚   โ”œโ”€โ”€ package.json          # Frontend dependencies and scripts
โ”‚   โ””โ”€โ”€ vite.config.js        # Vite, React, Tailwind, and test configuration
โ”œโ”€โ”€ server/
โ”‚   โ”œโ”€โ”€ broadcast/            # Batched public-room updates
โ”‚   โ”œโ”€โ”€ executor/             # Docker pool, judging, and language configuration
โ”‚   โ”‚   โ””โ”€โ”€ cpp/              # C++ wrapper, helpers, and executor Dockerfile
โ”‚   โ”œโ”€โ”€ game/                 # Match startup, departure, and reconnection
โ”‚   โ”‚   โ””โ”€โ”€ round/            # Round lifecycle, submissions, scoring, and elimination
โ”‚   โ”œโ”€โ”€ leaderboard/          # Precomputed rankings
โ”‚   โ”œโ”€โ”€ liveStats/            # Precomputed platform statistics
โ”‚   โ”œโ”€โ”€ middleware/           # API rate limiting
โ”‚   โ”œโ”€โ”€ migrations/           # Versioned PostgreSQL schema
โ”‚   โ”œโ”€โ”€ room/                 # Lobby creation, membership, and cleanup
โ”‚   โ”œโ”€โ”€ routes/               # REST APIs and live statistics stream
โ”‚   โ”œโ”€โ”€ seed/                 # Question dataset
โ”‚   โ”œโ”€โ”€ socket/               # Socket authentication and event registration
โ”‚   โ”œโ”€โ”€ utils/                # Guest identities, player lists, and timer utilities
โ”‚   โ”œโ”€โ”€ index.js              # Backend startup
โ”‚   โ”œโ”€โ”€ app.js                # Express middleware and API routes
โ”‚   โ”œโ”€โ”€ server.js             # HTTP and Socket.IO server setup
โ”‚   โ”œโ”€โ”€ auth.js               # Authentication configuration
โ”‚   โ”œโ”€โ”€ db.js                 # PostgreSQL connection pool
โ”‚   โ”œโ”€โ”€ globals.js            # Shared in-memory room and player state
โ”‚   โ”œโ”€โ”€ shutdown.js           # Server shutdown handling
โ”‚   โ”œโ”€โ”€ migrate.js            # Database migration runner
โ”‚   โ”œโ”€โ”€ seed.js               # Question dataset loader
โ”‚   โ”œโ”€โ”€ .env.example          # Backend environment template
โ”‚   โ”œโ”€โ”€ package.json          # Backend dependencies and scripts
โ”‚   โ””โ”€โ”€ vitest.config.js      # Backend test configuration
โ”œโ”€โ”€ package.json              # Root dependencies
โ”œโ”€โ”€ README.md
โ””โ”€โ”€ LICENSE

๐Ÿงช Development & Testing

The client and server have separate dependency installations and scripts. Development requires a Node.js version compatible with the installed Vite version, a running Docker daemon, PostgreSQL, and the psql command-line client for seeding.

From the repository root:

npm ci
npm ci --prefix client
npm ci --prefix server

cp client/.env.example client/.env
cp server/.env.example server/.env

docker pull node:alpine
docker pull python:alpine
docker build -t cpp-executor:latest -f server/executor/cpp/cpp-executor.Dockerfile .

Configure the environment files before starting:

File Variables
client/.env VITE_APP_URL: backend URL
server/.env PORT, DB_URL, FRONTEND_URL, BETTER_AUTH_URL, BETTER_AUTH_SECRET, and Google/GitHub/Discord OAuth credentials

The current authentication configuration uses secure cross-site cookies. For authenticated development, use HTTPS endpoints and matching OAuth callback URLs, or deliberately adapt the cookie configuration for your local environment.

Apply migrations and load questions from the server directory:

cd server
node migrate.js
node seed.js
npm run dev

In a separate terminal, start the frontend from the repository root:

npm run dev --prefix client

The frontend defaults to port 3000 and the backend to 5000. Keep these aligned with the environment URLs.

Run the test suites or build the frontend from the repository root:

npm run test:ci --prefix server
npm run test:ci --prefix client
npm run build --prefix client

Tests cover room membership, round orchestration, submissions, scoring and elimination, reconnection, execution helpers, frontend pages, game hooks, and UI components.

Note: Executor tests may take a few minutes to complete because they run each solution against its questionโ€™s test cases in every supported language using Docker containers.


๐Ÿ“ฌ Contact

Mayar Al Jawhary

๐Ÿ“ง mayar.aljwh@gmail.com

๐Ÿ’ผ LinkedIn

๐Ÿ™ GitHub


๐Ÿ“„ License

Code Chamber is licensed under the MIT License.

About

Real-time multiplayer coding elimination game with live code execution, isolated Docker judging, authentication, leaderboards, and reconnectable matches.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Contributors

Languages