W-01 ·
How Boro Battle keeps the score on the server
Boro Battle is a New York trivia game for 2 to 8 players in the browser. Play it at boro-battle.yaoban.dev.
How a game goes
One player creates a room and gets a four-letter code. Everyone else joins with that code from another tab or device. In the lobby, players mark themselves ready, and the host starts once at least two players are connected.
A game is 10 rounds of 15 seconds each. Each round asks either which ZIP had more noise complaints or which community board had more rodent complaints in one month, with 2 or 3 choices. When time is up, the right answer shows with the complaint counts behind every choice. Each right answer is worth one point. The winner screen lists the scores, and ties share the win. The host can start a rematch with the same room and a new set of questions.
Where the questions come from
The questions are built ahead of time by a script that reads the NYC 311 Service Requests dataset. Noise complaints are grouped by ZIP and rodent complaints by community board, for the most recent month with enough complaints. The script drops groups with fewer than 20 complaints, skips rounds with a tied answer, and checks 10 questions against a second query before it writes the file. The current file holds 220 questions from October 2026. A game never calls 311 while it runs.
Why the server keeps score
The browser sends only the choice a player picks. It doesn’t get the right answer or the counts until the round is over. The round deadline is a timer on the server, not the player’s clock, so an answer that arrives late scores zero.
Each room is its own Durable Object with its state saved in SQLite, so a room keeps its players, questions and scores while it sleeps between messages. Players connect over WebSockets, and after every move the server sends each player their own view of the room. A refresh keeps the same player, so a player who drops out and comes back keeps their score.
How it’s built
One Cloudflare Worker serves the page and hands each room code to its Durable Object. The front end is plain HTML, CSS and TypeScript. Tests check the scoring and the round rules:
- answers stay hidden until the round is over;
- a late answer scores zero;
- a player who leaves and rejoins keeps their score;
- bad or oversized messages change nothing.