X-Git-Url: https://git.cworth.org/git?p=empires-server;a=blobdiff_plain;f=empathy.js;h=d6b007b4bc3ef75d32230cde000917cdacdb7fa4;hp=7b1e9a1a7e79815a4d6c581f22562056bbb27f04;hb=HEAD;hpb=fd6875ac5df6262460bcca803aae3b223c18eca4 diff --git a/empathy.js b/empathy.js index 7b1e9a1..d6b007b 100644 --- a/empathy.js +++ b/empathy.js @@ -19,7 +19,7 @@ const PHASE_MINIMUM_TIME = 30; * * Specified in seconds */ -const PHASE_IDLE_TIMEOUT = 30; +const PHASE_IDLE_TIMEOUT = 15; class Empathy extends Game { constructor(id) { @@ -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,16 +111,25 @@ 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()); } add_prompt(items, prompt_string) { - if (items > MAX_PROMPT_ITEMS) + if (items > MAX_PROMPT_ITEMS) { return { valid: false, message: `Maximum number of items is ${MAX_PROMPT_ITEMS}` }; + } + + if (items < 1) { + return { + valid: false, + message: "Category must require at least one item" + }; + } const prompt = new Prompt(this.next_prompt_id, items, prompt_string); this.next_prompt_id++; @@ -337,15 +347,23 @@ 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] = { + player: player, + words: [...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])}`; @@ -472,7 +490,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; @@ -494,13 +516,33 @@ 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 kudos of Object.values(this.kudos)) { + for (let word of kudos.words) { + const word_canon = this.canonize(word); + if (! word_maps[word_canon]) + continue; + /* Don't let any player give kudos to a group where they + * submitted a word themself. That just wouldn't be right. */ + if (! word_maps[word_canon].players.has(kudos.player)) { + word_maps[word_canon].kudos.add(kudos.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. @@ -519,33 +561,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; }; @@ -557,13 +618,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).map(p => p.name) }; } ); 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