From 4a3ba6a0988fa1eb08c34a96068ed9e9e623136f Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Sun, 8 Mar 2026 08:23:09 -0400 Subject: [PATCH] Simplify tile dealing from the bag No longer require multiple people to request a letter. Instead, any person can draw a new letter from the bag as long as no letter reveal is currently in progress. --- anagrams.js | 83 ++++++++++++++--------------------------------------- 1 file changed, 22 insertions(+), 61 deletions(-) diff --git a/anagrams.js b/anagrams.js index 2f841ae..cdf9e3d 100644 --- a/anagrams.js +++ b/anagrams.js @@ -28,8 +28,6 @@ class Anagrams extends Game { claimed_words: [], /* { owner_session, word_id, word_obj } */ /* Voting state. */ vote_pending: null, - /* Letter request state. */ - letter_requests: new Set(), /* Game state. */ finished: false, done_players: new Set() @@ -37,7 +35,7 @@ class Anagrams extends Game { this._claim_timer = null; this._claim_warning_timer = null; this._vote_timer = null; - this._letter_request_timer = null; + this._revealing = false; this._reveal_timer = null; } @@ -70,15 +68,30 @@ class Anagrams extends Game { *****************************************************/ /* Deal a letter from bag to center with a countdown reveal. */ - deal_letter() { - if (this.state.bag.length === 0) return false; + handle_deal_letter(request, response) { + const session_id = request.session.id; + if (!this.state.player_words[session_id]) { + response.sendStatus(400); + return; + } + + if (this.state.bag.length === 0 || this._revealing) { + response.json({ ok: false }); + return; + } const letter = this.state.bag.pop(); const id = this.state.next_letter_id++; const tile = { id, letter }; this.state.center.push(tile); - this.state.letter_requests = new Set(); + this._revealing = true; + + if (this._reveal_timer) clearTimeout(this._reveal_timer); + this._reveal_timer = setTimeout(() => { + this._revealing = false; + this._reveal_timer = null; + }, REVEAL_COUNTDOWN_MS); this.broadcast_event_object("letter-reveal", { tile, @@ -86,63 +99,11 @@ class Anagrams extends Game { countdown_ms: REVEAL_COUNTDOWN_MS }); - /* Also broadcast updated bag count. */ this.broadcast_event_object("bag-count", { remaining: this.state.bag.length }); - return true; - } - - /* Handle a player requesting a new letter. */ - handle_request_letter(request, response) { - const session_id = request.session.id; - if (!this.state.player_words[session_id]) { - response.sendStatus(400); - return; - } - - if (this.state.bag.length === 0) { - response.json({ remaining: 0 }); - return; - } - - /* Don't allow requests during a reveal countdown. */ - if (this._reveal_timer) { - response.json({ queued: false }); - return; - } - - this.state.letter_requests.add(session_id); - - const joined = this.joined_player_count(); - const votes = this.state.letter_requests.size; - - this.broadcast_event_object("letter-request", { - votes, - needed: joined - }); - - /* Scale timer: all players voting = immediate. - * One player = full 10-second wait. - * Linear interpolation between. */ - if (this._letter_request_timer) { - clearTimeout(this._letter_request_timer); - this._letter_request_timer = null; - } - - if (votes >= joined) { - this.deal_letter(); - } else { - const ratio = votes / joined; - const delay_ms = Math.round(10000 * (1 - ratio)); - this._letter_request_timer = setTimeout(() => { - this._letter_request_timer = null; - this.deal_letter(); - }, delay_ms); - } - - response.json({ queued: true, remaining: this.state.bag.length }); + response.json({ ok: true }); } /***************************************************** @@ -825,8 +786,8 @@ router.post('/cancel-claim', (request, response) => { request.game.handle_cancel_claim(request, response); }); -router.post('/request-letter', (request, response) => { - request.game.handle_request_letter(request, response); +router.post('/deal-letter', (request, response) => { + request.game.handle_deal_letter(request, response); }); router.post('/vote', (request, response) => { -- 2.45.2