X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=empathy.js;h=b12c3e75553f596b7cc2108cc9e1c21f0bd97444;hb=9aa7407eda90493c1004258e705ef0fa4afa6a48;hp=6fc926ff83b56991e22dde9ad4ad5635852601d1;hpb=f2a237f13592e30e93dd056efd09087e57f4ce05;p=empires-server diff --git a/empathy.js b/empathy.js index 6fc926f..b12c3e7 100644 --- a/empathy.js +++ b/empathy.js @@ -5,10 +5,164 @@ class Empathy extends Game { constructor(id) { super(id); this.state = { - prompts: [] + prompts: [], + active_prompt: null, + players_answered: 0, + scores: null }; + this.answers = []; this.next_prompt_id = 1; } + + reset() { + + /* Before closing out the current round, we accumulate that score + * for each player into their runnning total. */ + for (let score of this.state.scores.scores) { + const player = this.players.find(p => p.name === score.player); + if (player.score) + player.score += score.score; + else + player.score = score.score; + + /* And broadcast that new score out. */ + this.broadcast_event('player-update', player.info_json()); + } + + /* Now that we're done with the active prompt, we remove it from + * the list of prompts and also remove any prompts that received + * no votes. This keeps the list of prompts clean. + */ + const active_id = this.state.active_prompt.id; + this.state.prompts = + this.state.prompts.filter( + p => p.id !== active_id && p.votes.length > 0 + ); + + this.state.active_prompt = null; + this.state.players_answered = 0; + this.state.scores = null; + + this.answers = []; + + this.broadcast_event_object('game-state', this.state); + } + + add_prompt(items, prompt_string) { + const prompt = new Prompt(this.next_prompt_id, items, prompt_string); + this.next_prompt_id++; + + this.state.prompts.push(prompt); + + this.broadcast_event_object('prompt', prompt); + + return prompt; + } + + /* Returns true if vote toggled, false for player or prompt not found */ + toggle_vote(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; + + prompt.toggle_vote(player.name); + + this.broadcast_event_object('prompt', prompt); + + return true; + } + + /* Returns true on success, false for prompt not found. */ + start(prompt_id) { + const prompt = this.state.prompts.find(p => p.id === prompt_id); + if (! prompt) + return false; + + /* Ignore any start request that comes in while a prompt is + * already being played. */ + if (this.state.active_prompt) + return false; + + this.state.active_prompt = prompt; + + this.broadcast_event_object('start', prompt); + + return true; + } + + receive_answer(prompt_id, session_id, answers) { + const player = this.players_by_session[session_id]; + if (! player) + return { valid: false, message: "Player not found" }; + + const prompt = this.state.prompts.find(p => p.id === prompt_id); + if (! prompt) + return { valid: false, message: "Prompt not found" }; + + if (prompt !== this.state.active_prompt) + return { valid: false, message: "Prompt no longer active" }; + + /* Save the complete answers for our own use later. */ + this.answers.push({ + player: player, + answers: answers + }); + + /* And notify players how many players have answered. */ + this.state.players_answered++; + this.broadcast_event_object('answered', this.state.players_answered); + + return { valid: true }; + } + + compute_scores() { + const word_submitters = {}; + const scores = []; + + for (let a of this.answers) { + for (let word of a.answers) { + if (word_submitters[word]) + word_submitters[word].push(a.player.name); + else + word_submitters[word] = [a.player.name]; + } + } + + for (let a of this.answers) { + let score = 0; + for (let word of a.answers) { + score += word_submitters[word].length; + } + scores.push({ + player: a.player.name, + score: score + }); + } + + scores.sort((a,b) => { + return b.score - a.score; + }); + + const word_submitters_arr = []; + for (let word in word_submitters) + word_submitters_arr.push({word: word, players: word_submitters[word]}); + + word_submitters_arr.sort((a,b) => { + return b.players.length - a.players.length; + }); + + /* Put this round's scores into the game state object so it will + * be sent to any new clients that join. */ + this.state.scores = { + scores: scores, + words: word_submitters_arr + }; + + /* And broadcast the scores to all connected clients. */ + this.broadcast_event_object('scores', this.state.scores); + } } Empathy.router = express.Router(); @@ -33,32 +187,45 @@ class Prompt { router.post('/prompts', (request, response) => { const game = request.game; - const prompt = new Prompt(game.next_prompt_id, - request.body.items, - request.body.prompt); - game.next_prompt_id++; - - game.state.prompts.push(prompt); - - game.broadcast_event_object('prompt', prompt); + game.add_prompt(request.body.items, request.body.prompt); }); router.post('/vote/:prompt_id([0-9]+)', (request, response) => { + const game = request.game; const prompt_id = parseInt(request.params.prompt_id, 10); + + if (game.toggle_vote(prompt_id, request.session.id)) + response.sendStatus(200); + else + response.sendStatus(404); +}); + +router.post('/start/:prompt_id([0-9]+)', (request, response) => { const game = request.game; - const player = game.players_by_session[request.session.id]; + const prompt_id = parseInt(request.params.prompt_id, 10); - prompt = game.state.prompts.find(p => p.id === prompt_id); - if (! prompt || ! player) { + if (game.start(prompt_id)) + response.sendStatus(200); + else response.sendStatus(404); - return; - } +}); - prompt.toggle_vote(player.name); +router.post('/answer/:prompt_id([0-9]+)', (request, response) => { + const game = request.game; + const prompt_id = parseInt(request.params.prompt_id, 10); - game.broadcast_event_object('prompt', prompt); + const result = game.receive_answer(prompt_id, + request.session.id, + request.body.answers); + response.json(result); - response.sendStatus(200); + if (game.answers.length >= game.players.length) + game.compute_scores(); +}); + +router.post('/reset', (request, response) => { + const game = request.game; + game.reset(); }); Empathy.meta = {