From 6d7b857216c136426067e9575fc692e09a778d8d Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Mon, 29 Jun 2020 13:53:20 -0700 Subject: [PATCH] Add scoring of kudos along with word groups The kudos act as a tiebreaker when regular points are otherwise identical. The test suite is updated here to pass the new information expected by the server when receiving a word list during judging, (now wants an object with two properties: 1. words, a list of words, 2. kudos, a Boolean). With this the test suite is still fully passing. --- empathy.js | 81 +++++++++++++++++++++++++++++++++++++++++++----------- test | 8 +++--- 2 files changed, 69 insertions(+), 20 deletions(-) diff --git a/empathy.js b/empathy.js index c1d150f..01836df 100644 --- a/empathy.js +++ b/empathy.js @@ -46,6 +46,7 @@ class Empathy extends Game { this.judging_start_time_ms = 0; this.next_prompt_id = 1; this.equivalencies = {}; + this.kudos = {}; } reset() { @@ -110,6 +111,7 @@ class Empathy extends Game { this.judging_idle_timer = 0; this.judging_start_time_ms = 0; this.equivalencies = {}; + this.kudos = {}; this.broadcast_event('game-state', this.game_state_json()); } @@ -345,15 +347,19 @@ class Empathy extends Game { */ for (let group of word_groups) { - for (let i = 0; i < group.length - 1; i++) { - for (let j = i + 1; j < group.length; j++) { - let eq = [group[i], group[j]]; + const words = group.words; + if (group.kudos) + this.kudos[player.name] = [...words]; + + for (let i = 0; i < words.length - 1; i++) { + for (let j = i + 1; j < words.length; j++) { + let eq = [words[i], words[j]]; /* Put the two words into a reliable order so that we don't * miss a pair of equivalent equivalencies just because they * happen to be in the opposite order. */ if (eq[0].localeCompare(eq[1]) > 0) { - eq = [group[j], group[i]]; + eq = [words[j], words[i]]; } const key=`${this.canonize(eq[0])}:${this.canonize(eq[1])}`; @@ -480,7 +486,11 @@ class Empathy extends Game { if (! group) group = word_maps[word1_canon]; if (! group) - group = { words: [], players: new Set()}; + group = { + words: [], + players: new Set(), + kudos: new Set() + }; if (! word_maps[word0_canon]) { word_maps[word0_canon] = group; @@ -502,13 +512,29 @@ class Empathy extends Game { if (word_maps[word_canon]) { word_maps[word_canon].players.add(a.player); } else { - const group = { words: [word], players: new Set() }; + const group = { + words: [word], + players: new Set(), + kudos: new Set() + }; group.players.add(a.player); word_maps[word_canon] = group; } } } + /* Apply kudos from each player to the word maps, (using a set so + * that no word_map can get multiple kudos from a single + * player). */ + for (let player of Object.keys(this.kudos)) { + for (let word of this.kudos[player]) { + const word_canon = this.canonize(word); + if (! word_maps[word_canon]) + continue; + word_maps[word_canon].kudos.add(player); + } + } + /* Now that we've assigned the players to these word maps, we now * want to collapse the groups down to a single array of * word_groups. @@ -527,33 +553,52 @@ class Empathy extends Game { * * Note: We do this by going through the word groups, (as opposed * to the list of words from the players again), specifically to - * avoid giving a player points for a wrod group twice (in the + * avoid giving a player points for a word group twice (in the * case where a player submits two different words that the group * ends up judging as equivalent). */ - this.players.forEach(p => p.round_score = 0); + this.players.forEach(p => { + p.round_score = 0; + p.round_kudos = 0; + }); for (let group of word_groups) { - group.players.forEach(p => p.round_score += group.players.size); + group.players.forEach(p => { + p.round_score += group.players.size; + p.round_kudos += group.kudos.size; + }); } const scores = this.players.filter(p => p.active).map(p => { return { player: p.name, - score: p.round_score + score: p.round_score, + kudos: p.round_kudos }; }); scores.sort((a,b) => { - return b.score - a.score; + const delta = b.score - a.score; + if (delta) + return delta; + return b.kudos - a.kudos; }); /* After sorting individual players by score, group players * together who have the same score. */ const reducer = (list, next) => { - if (list.length && list[list.length-1].score == next.score) + if (list.length + && list[list.length-1].score == next.score + && list[list.length-1].kudos == next.kudos + ) + { list[list.length-1].players.push(next.player); - else - list.push({players: [next.player], score: next.score}); + } else { + list.push({ + players: [next.player], + score: next.score, + kudos: next.kudos, + }); + } return list; }; @@ -565,13 +610,17 @@ class Empathy extends Game { group => { return { word: group.words.join('/'), - players: Array.from(group.players).map(p => p.name) + players: Array.from(group.players).map(p => p.name), + kudos: Array.from(group.kudos) }; } ); words_submitted.sort((a,b) => { - return b.players.length - a.players.length; + const delta = b.players.length - a.players.length; + if (delta !== 0) + return delta; + return b.kudos.length - a.kudos.length; }); /* Put this round's scores into the game state object so it will diff --git a/test b/test index 646cdca..c6c8750 100755 --- a/test +++ b/test @@ -655,12 +655,12 @@ empathy_judged() } TEST "Submit word groups from alice" -result=$(empathy_judged alice $prompt_id '[["sun","SunLight","SunShine"],["sand","sands","Grains of Sand"],["water","wafer"]]') +result=$(empathy_judged alice $prompt_id '[{"words":["sun","SunLight","SunShine"],"kudos":false},{"words":["sand","sands","Grains of Sand"],"kudos":false},{"words":["water","wafer"],"kudos":false}]') test "$result" = '{"valid":true}' TEST_END TEST "Submit word groups from bob" -result=$(empathy_judged bob $prompt_id '[["sands","grains of sand"],["water","wafer"]]') +result=$(empathy_judged bob $prompt_id '[{"words":["sands","grains of sand"],"kudos":false},{"words":["water","wafer"],"kudos":false}]') test "$result" = '{"valid":true}' TEST_END @@ -676,7 +676,7 @@ test "$result" = "null" TEST_END TEST "Submit word groups from charlie" -result=$(empathy_judged charlie $prompt_id '[["SunLight","SunShine"],["sand","Grains of Sand"]]') +result=$(empathy_judged charlie $prompt_id '[{"words":["SunLight","SunShine"],"kudos":false},{"words":["sand","Grains of Sand"],"kudos":false}]') test "$result" = '{"valid":true}' TEST_END @@ -892,7 +892,7 @@ test "$?" = "0" TEST_END TEST "1 player votes for a match" -empathy_judged alice $prompt_id '[["truth","true"]]' >/dev/null +empathy_judged alice $prompt_id '[{"words":["truth","true"],"kudos":false}]' >/dev/null result=$(empathy_judged bob $prompt_id '[]') test "$result" = '{"valid":true}' TEST_END -- 2.43.0