]> git.cworth.org Git - empires-server/commitdiff
Two alterations to player scoring: per-round grouping, and round normalization
authorCarl Worth <cworth@cworth.org>
Sun, 28 Jun 2020 00:21:38 +0000 (17:21 -0700)
committerCarl Worth <cworth@cworth.org>
Sun, 28 Jun 2020 00:21:38 +0000 (17:21 -0700)
Previously, we were returning an array of player scores where some
succesive players in the array may have had identical scores. Now,
instead, we have only one entry per score, and instead of just a
single player name, an array of player names in case there is a tie at
any score. This should help clients display per-round scores in a way
that make all the ties obvious.

Second, we were previously accumulating the per-round points directly
into a player's total. This had the defect of weighting some rounds
more than others, (rounds with more items were worth a higher maximum
number of points than rounds with fewer items). Now, instead, we only
accumulate into a player's total the number of players that they beat
out in each round. This gives an equal weight to every round.

The test suite is updated in this commit for the first fix above. But
the test suite does not yet cover the player's overall scores so that
change is not tested here.

empathy.js
test

index fdf62a18d41abb42e1a41741ee2625e313b9faf0..7b27ee40c5d196866b19036455c66e6b5ebe713e 100644 (file)
@@ -50,17 +50,28 @@ class Empathy extends Game {
 
   reset() {
 
-    /* Before closing out the current round, we accumulate the 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());
+    /* Before closing out the current round, we accumulate into each
+     * player's overall score the results from the current round.
+     *
+     * Note: Rather than applying the actual points from each round
+     * into the player's score, we instead accumulate up the number of
+     * players that they bested in each round. This ensures that each
+     * round receives an equal weight in the overall scoring. */
+    let bested = this.state.scores.scores.reduce(
+      (total, score) => total + score.players.length, 0);
+    for (let i = 0; i < this.state.scores.scores.length; i++) {
+      const score = this.state.scores.scores[i];
+      bested -= score.players.length;
+      for (let player_name of score.players) {
+        const player = this.players.find(p => p.name === player_name);
+        if (player.score)
+          player.score += bested;
+        else
+          player.score = bested;
+
+        /* 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
@@ -513,6 +524,18 @@ class Empathy extends Game {
       return b.score - a.score;
     });
 
+    /* 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)
+        list[list.length-1].players.push(next.player);
+      else
+        list.push({players: [next.player], score: next.score});
+      return list;
+    };
+
+    const grouped_scores = scores.reduce(reducer, []);
+
     /* Put the word groups into a form the client can consume.
      */
     const words_submitted = word_groups.map(
@@ -531,7 +554,7 @@ class Empathy extends Game {
     /* 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,
+      scores: grouped_scores,
       words: words_submitted
     };
 
diff --git a/test b/test
index f62d6824315253edd01758f443ca946a393e2947..fcb556c5baa4e11c1ed1ab3eeaf216bb54c3f1da 100755 (executable)
--- a/test
+++ b/test
@@ -690,7 +690,7 @@ TEST_END
 # Usage: empathy_scores_names_numbers <player_name>
 empathy_scores_names_numbers()
 {
-    empathy_get_event $1 game-state | jq '.scores.scores[]|.player,.score'
+    empathy_get_event $1 game-state | jq '.scores.scores[]|.players[],.score'
 }
 
 TEST_SUBSECTION "Scoring"
@@ -890,7 +890,7 @@ TEST_END
 TEST "Verify the match passed the vote"
 # echo here is to strip newlines
 result=$(echo $(empathy_scores_names_numbers alice))
-test "$result" = '"alice" 2 "bob" 2 "charlie" 0 "dale" 0 "eric" 0 "fred" 0'
+test "$result" = '"alice" "bob" 2 "charlie" "dale" "eric" "fred" 0'
 TEST_END
 
 echo ""
@@ -929,7 +929,7 @@ TEST_END
 TEST "Verify scores don't include inactive players"
 # echo here is to strip newlines
 result=$(echo $(empathy_scores_names_numbers alice))
-test "$result" = '"alice" "bob" 1 "charlie" 0'
+test "$result" = '"alice" "bob" 1 "charlie" 0'
 TEST_END
 
 TEST_SUBSECTION "Deactivated players don't block future game phase advances"