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.
this.state = {
prompts: [],
active_prompt: null,
this.state = {
prompts: [],
active_prompt: null,
+ players_answered: [],
+ players_answering: new Set(),
+ end_answers: new Set(),
+ players_judged: [],
+ players_judging: new Set(),
+ end_judging: new Set(),
scores: null
};
this.answers = [];
scores: null
};
this.answers = [];
);
this.state.active_prompt = null;
);
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.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 = [];
this.state.scores = null;
this.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 };
}
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 = {};
perform_judging() {
const word_map = {};
- /* 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 };
}
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();
}
canonize(word) {
return word.toLowerCase();
}
request.session.id,
request.body.answers);
response.json(result);
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();
});
game.perform_judging();
});
request.session.id,
request.body.word_groups);
response.json(result);
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();
});
game.compute_scores();
});