From: Carl Worth Date: Sat, 13 Jun 2020 21:38:28 +0000 (-0700) Subject: Accept votes to advance game at /end-answers and /end-judging endpoints X-Git-Url: https://git.cworth.org/git?p=lmno-server;a=commitdiff_plain;h=54f57abe8bc6753da1c6b1663f1efcd178e33a75;hp=99db5b01aba2ee48a13a7a591efc8812e23d0beb 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. --- 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(); });