Everything lives in shared state
Unlike realtime games, a turn-based game sends almost nothing on the direct channel. The board, the current turn and the round number all live in shared state, validated by the server. Use preset turn_based, and leave peer-to-peer on: the direct channel carries no moves, but it lets the SDK tell the opponent a move was played so the client can call the server only every few seconds while still reacting in milliseconds.
const room = await mp.quickmatch({ mode: 'ranked', max_players: 2 });
room.setnx('round', 0);
// A move = place the piece AND pass the turn, together or not at all.
async function play(cell) {
room.set(`board.r${round}.${cell}`, myMark);
room.cas('turn', mp.account.id, opponentId); // fails if it is not my turn
try { await room.flush({ atomic: true }); }
catch (e) { showError('Not your turn'); }
}
room.state.watch(`board.r${round}.*`, redraw);
room.state.watch('turn', (who) => setMyTurn(who === mp.account.id));Rules that make client checks unnecessary
{
"state": {
"turn": { "write": "any", "type": "string" },
"board.**": { "write": "any", "immutable": true },
"round": { "write": "any", "type": "int", "monotonic": "up" }
}
}immutable means a placed cell can never be overwritten. cas on turn means two simultaneous moves cannot both succeed. atomic means a move never lands without its turn handoff.
Rematch and spectators
Advance the round with room.cas('round', n, n + 1). Remember that cas expecting 0 fails on a key never written — that is why the code sets it with setnx first. Enable max_spectators and friends can watch with mp.watch(code).
Play the tic-tac-toe demo to see this exact pattern, source included.
How do I stop a player from moving twice?
Use compare-and-swap on the turn: room.cas('turn', me, opponent) only succeeds if it is currently your turn. Send it atomically with the move.
Can players reconnect mid-game?
Yes. Shared state survives reconnection and is sent to anyone who joins late, so a reloaded tab resumes the game where it was.
Make your game online today
Free sandbox keys in one call, no account and no card. $19.99/month when you ship, for every game you make.
Free sandbox · $19.99/mo to go live · cancel anytime