From 54f57abe8bc6753da1c6b1663f1efcd178e33a75 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Sat, 13 Jun 2020 14:38:28 -0700 Subject: [PATCH] Accept votes to advance game at /end-answers and /end-judging endpoints The previous logic was far too strict, where the game would advance only after every registered player had submitted. That made it possible for the game to become totally stuck with just a single player that left the game, (or even that accidentally reloaded the game in a way that lost their previous session). Now there are endpoints for players to vote that they would like to advance past either the "answers" or "judging" phases of the game, and the game will advance as soon as a majority of the registered players have voted. This does still make it possible for the game to get stuck if a sufficient number of players stop playing, but it's at least less likely to happen. And we've got plans to improve this situation further soon as well. --- empathy.js | 90 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 12 deletions(-) diff --git a/empathy.js b/empathy.js index cfe0618..eaf12bf 100644 --- a/empathy.js +++ b/empathy.js @@ -9,9 +9,13 @@ class Empathy extends Game { this.state = { prompts: [], active_prompt: null, - players_answered: 0, + players_answered: [], + players_answering: new Set(), + end_answers: new Set(), ambiguities: null, - players_judged: 0, + players_judged: [], + players_judging: new Set(), + end_judging: new Set(), scores: null }; this.answers = []; @@ -45,9 +49,13 @@ class Empathy extends Game { ); this.state.active_prompt = null; - this.state.players_answered = 0; + this.state.players_answered = []; + this.state.players_answering = new Set(); + this.state.end_answers = new Set(); this.state.ambiguities = 0; - this.state.players_judged = 0; + this.state.players_judged = []; + this.state.players_judging = new Set(); + this.state.end_judging = new Set(); this.state.scores = null; this.answers = []; @@ -127,13 +135,32 @@ class Empathy extends Game { answers: answers }); - /* And notify players how many players have answered. */ - this.state.players_answered++; - this.broadcast_event_object('answered', this.state.players_answered); + /* And notify all players that this player has answered. */ + this.state.players_answered.push(player.name); + this.broadcast_event_object('player-answered', player.name); return { valid: true }; } + /* Returns true if vote toggled, false for player or prompt not found */ + toggle_end_answers(prompt_id, session_id) { + const player = this.players_by_session[session_id]; + + const prompt = this.state.prompts.find(p => p.id === prompt_id); + if (! prompt || ! player) + return false; + + if (this.state.end_answers.has(player.name)) { + this.state.end_answers.delete(player.name); + this.broadcast_event_object('unvote-end-answers', player.name); + } else { + this.state.end_answers.add(player.name); + this.broadcast_event_object('vote-end-answers', player.name); + } + + return true; + } + perform_judging() { const word_map = {}; @@ -198,13 +225,32 @@ class Empathy extends Game { } } - /* And notify players how many players have completed judging. */ - this.state.players_judged++; - this.broadcast_event_object('judged', this.state.players_judged); + /* And notify all players this this player has judged. */ + this.state.players_judged.push(player.name); + this.broadcast_event_object('player-judged', player.name); return { valid: true }; } + /* Returns true if vote toggled, false for player or prompt not found */ + toggle_end_judging(prompt_id, session_id) { + const player = this.players_by_session[session_id]; + + const prompt = this.state.prompts.find(p => p.id === prompt_id); + if (! prompt || ! player) + return false; + + if (this.state.end_judging.has(player.name)) { + this.state.end_judging.delete(player.name); + this.broadcast_event_object('unvote-end-judging', player.name); + } else { + this.state.end_judging.add(player.name); + this.broadcast_event_object('vote-end-judging', player.name); + } + + return true; + } + canonize(word) { return word.toLowerCase(); } @@ -378,8 +424,18 @@ router.post('/answer/:prompt_id([0-9]+)', (request, response) => { request.session.id, request.body.answers); response.json(result); +}); + +router.post('/end-answers/:prompt_id([0-9]+)', (request, response) => { + const game = request.game; + const prompt_id = parseInt(request.params.prompt_id, 10); + + if (game.toggle_end_answers(prompt_id, request.session.id)) + response.send(''); + else + response.sendStatus(404); - if (game.state.players_answered >= game.players.length) + if (game.state.end_answers.size > (game.state.players_answered.length / 2)) game.perform_judging(); }); @@ -391,8 +447,18 @@ router.post('/judging/:prompt_id([0-9]+)', (request, response) => { request.session.id, request.body.word_groups); response.json(result); +}); + +router.post('/end-judging/:prompt_id([0-9]+)', (request, response) => { + const game = request.game; + const prompt_id = parseInt(request.params.prompt_id, 10); + + if (game.toggle_end_judging(prompt_id, request.session.id)) + response.send(''); + else + response.sendStatus(404); - if (game.state.players_judged >= game.players.length) + if (game.state.end_judging.size > (game.state.players_judged.length / 2)) game.compute_scores(); }); -- 2.43.0