Overview
I built an online multiplayer adaptation of Cheese Thief, a social-deduction board game. The server manages the tasks normally handled around a physical table: assigning secret roles, coordinating night actions, collecting votes, and resolving the outcome.
The application uses Node.js, Express, Socket.IO, HTML, CSS, and JavaScript, with a minimum of three players.
Browse the source code on GitHub ↗
Game Flow
- Players enter a name and join the shared lobby.
- A player starts the game once enough participants have joined.
- The server assigns roles and dice values, sending each player their private information.
- After role confirmation, night actions proceed through dice slots one to six.
- The thief can steal the cheese; eligible players can inspect another player’s dice information.
- The thief selects an accomplice, followed by discussion and voting.
- The server counts votes, handles ties, and determines the winning side.
Realtime Architecture
Express serves the client interface, while Socket.IO carries bidirectional game events. The server holds the player list, phase, cheese state, votes, and completed-action sets.
Private roles and inspection results are sent to the relevant socket. Lobby updates, phase transitions, and final outcomes are broadcast to the players.
| Event | Server responsibility |
|---|---|
join | Add a player to the lobby and handle duplicate names. |
startGame | Reset the round and assign roles and dice values. |
confirmIdentity | Track readiness before entering the night phase. |
stealCheese / peekPlayer | Process role-specific night actions. |
thiefChooseFollower | Record the accomplice and advance the game. |
submitVote | Collect votes and resolve the outcome. |
Rule Validation
Before accepting an action, the server checks the current phase, the player’s socket, their role and dice value, and whether the action has already been completed. It also checks the cheese state and prevents duplicate inspection, voting, and night-confirmation actions.
Disconnects update the lobby. If a disconnection makes the current game unable to continue, the server ends that round and returns to the waiting state.
This server-authoritative state machine gives connected browsers a common game state while preserving the distinction between public information and each player’s private knowledge.