Carl Worth [Sat, 19 Sep 2020 21:41:45 +0000 (14:41 -0700)]
Add some autofocus attributes to several forms
Just trying to make things a little more friendly, (so that, a page
with a single form that has a single text field loads with that field
having focus already).
Carl Worth [Sat, 19 Sep 2020 20:52:39 +0000 (13:52 -0700)]
Add a README file for the lmno-server repository
It's been a while since I did any LMNO development, and since the last
time I did, I'm now using a new laptop. So I needed a reminder on how
to configure my web server for local development. Here that is now for
my own use, (and for the use of anyone else that might want it).
Carl Worth [Tue, 7 Jul 2020 12:40:03 +0000 (05:40 -0700)]
test: Extend Scribe testing to encompass a complete game
Including the formation of several large-ish glyph shapes.
There's not actually a _lot_ of functional testing here. It would be
much more useful if the server reported whether a move generated a
glyph or not, (and then the test suite could verify that result on
every single move).
For that, we'll also want to aloow sub-tests that don't generate an
entire line of output, but instead just a single letter.
Carl Worth [Tue, 7 Jul 2020 12:36:12 +0000 (05:36 -0700)]
Implement glyph detection on the server side
This seems to work, but it's only been verified via debugging prints,
(that is, the server isn't yet _doing_ anything with the glyph
detection that a client can actually see).
Carl Worth [Mon, 6 Jul 2020 05:35:59 +0000 (22:35 -0700)]
test: Add testing for a move that sends you to a full mini-grid
In this case, it's legal to move anywhere, (the normal constraint of
having to move to a matching mini-square is waived since it's
impossible by definition).
Carl Worth [Mon, 6 Jul 2020 05:16:11 +0000 (22:16 -0700)]
scribe: Reject moves that are illegal by the move constraint
If the player has a previous move, (this isn't their first move of the
game), then the mini-grid being moved to must match the position
within the mini-grid of the previous move, (unless the indicated mini
grid is full).
Carl Worth [Sun, 5 Jul 2020 21:21:31 +0000 (14:21 -0700)]
Stop ignoring the .gitattributes file
Both lmno-todo and nogit have now been reworked to not use
.giattributes, (instead they now use .nogit/info/attributes), so we
don't need to ignore this file anymore.
Carl Worth [Tue, 30 Jun 2020 00:01:29 +0000 (17:01 -0700)]
Fix bug when a player reclaims a previous player object by name
Previously, we were forgetting to update the session ID map, leading
to an experience where the player couldn't submit any words,
etc. (Sorry, David!).
Carl Worth [Mon, 29 Jun 2020 21:23:28 +0000 (14:23 -0700)]
empathy: Don't let any player give kudos to themself
Which would not be very sporting of course, so we don't allow it.
Note that this restriction is applied after the majority-ruled
matching. So a player can't even give kudos to a word they didn't
submit and then hope to get matched into it.
It's also worth noting that the group can decide to split a group
where one player gave kudos. That will mean that both sides of the
split get kudos from the player, which seems to match the kudos-giving
player's intent.
Carl Worth [Mon, 29 Jun 2020 20:53:20 +0000 (13:53 -0700)]
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).
Carl Worth [Mon, 29 Jun 2020 15:11:32 +0000 (08:11 -0700)]
Cut PHASE_IDLE_TIMEOUT in half
The feedback from our playtest session last night was that the one
time we wanted to move on without an idle player, we had to wait too
long before the "Move On" button appeared.
Carl Worth [Sun, 28 Jun 2020 22:04:00 +0000 (15:04 -0700)]
Remove a positive vote for a prompt when adding a negative vote
This is important to do here because the current client interface
doesn't let a player see a prompt again after adding a negative vote,
(so they wouldn't know their positive vote was still there nor could
they remove it themself).
Carl Worth [Sun, 28 Jun 2020 21:54:26 +0000 (14:54 -0700)]
Change prompt-retirement to require more negative than votes to retire
Or, as expressed here, more (or equal) positive votes than negative in
order to preserve a prompt.
However the logic is worded, the point is that the old rule "Retire
any prompt with no votes" had a serious flaw: When someone submitted a
new category _just_ before a round started, nobody would get a chance
to vote for it, and then it would be dropped before anyone would see
it on the next round.
Now, instead, just like most everything else in empathy, the retiring
of an undesired category is now determined by a vote.
Carl Worth [Sun, 28 Jun 2020 00:52:06 +0000 (17:52 -0700)]
Use set difference (ANSWERED - JUDGED) to determine whether to advance
This is a bug fix for the bug described and tested in the previous
commit. Previously we were simply comparing the count of players who
had judged with the count of those who had answered.
Here, instead, we compute an actual set difference and only
auto-advance from the judging phase when every player who answered has
also completed judging.
This fix causes the test added in the previous comit to start passing,
so now the entire test suite is passing once again.
Carl Worth [Sun, 28 Jun 2020 00:49:00 +0000 (17:49 -0700)]
Add new failing test case: Non-player can terminate judging
The code that is intending to check whether all answering players have
completed judging is currently broken. It is only checking whether the
number of players that have judged is as large as the number of
players that have answered.
This is the wrong logic in the case where a player who didn't answer
joins the game late and submits judging results, which is exactly what
we do in the new test case here.
This test case currently fails, so a fix of the bug described above
will cause it to start passing.
Carl Worth [Sun, 28 Jun 2020 00:21:38 +0000 (17:21 -0700)]
Two alterations to player scoring: per-round grouping, and round normalization
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.
Carl Worth [Sat, 27 Jun 2020 21:55:46 +0000 (14:55 -0700)]
Fix JSON stringification of game-state at game reset
The initial stream of game state upon player connection was already
careful to use a subsitute function for correct stringification of
Set objects, but the streaming at game reset was not.
I didn't notice this for a while because the client always reset its
own state data before applying what was streamed from the server. The
application of the server-provided state would fail, (encountering an
empty object instead of an empty array), but since the client state
was already reset anyway, that wasn't noticed, (as long as the failure
only happened after the prompt data, for example).
I uncovered the bug with a recent client fix to not display the
category-input form until the game-state was received, (and the
Boolean to trigger that display happened only after the portions of
the game state that were failing due to the bug described above).
Carl Worth [Sat, 27 Jun 2020 17:36:39 +0000 (10:36 -0700)]
Allow a player to reclaim a disconnected player of the same name
I've seen cases where players close their browser window, and then
re-open it with the URL only to find that they aren't actually in the
same session so they end up with an unwanted "Name01" name instead of
"Name" and lose access to their score.
We make things work the way users want here by letting them claim an
existing player object by simply using the same name.
Of course, this does assume nobody will want to do this
nefariously. I'm perfectly fine with that, (since the whole point of
all of this is to enable friendly games). If, at some point in the
future somebody cared to lock people out from doign this, then we can
imagine a future where:
1. Users could actually log in
2. Users could lock a game to only allow logged-in users
Carl Worth [Sat, 27 Jun 2020 17:26:29 +0000 (10:26 -0700)]
Don't send a re-connecting player a player-enter event for themself
It's rather ugly that we've got these semantics where the client
doesn't want to see a player-enter event for itself. This is causing
too many special cases in the code (such as the current commit).
So we'll want to change that at some point. But for now we make the
case of a player reconnecting match the semantics. Specifically we
move the add_connection call down _after_ the broadcast of the
player-enter event. This fixes the current client so that it doesn't
display its own name twice when reclaiming a pre-existing player.
Carl Worth [Sat, 27 Jun 2020 17:20:25 +0000 (10:20 -0700)]
Fix player-enter events to use complete info_json() method
Previous to this commit, the player-enter event was hardcoded to send
only ID and name properties, which was enough for an actual new
player. But a player-enter event can also happen when a player
re-joins after being disconnected. In this case, we want the score to
be sent as well.
We can get everything we want by using the player's info_json() method
rather than doing a custom call to JSON.stringify with a hard-coded
list of properties.
Carl Worth [Sat, 27 Jun 2020 16:45:22 +0000 (09:45 -0700)]
game: Fix reactivation of an existing player to be fully active
To do this, we have to set the player's active bit to true, then we
increment the server's count of active players, and finally we
broadcast to all active players that this player has entered the game
again.
This commit fixes the bug described in the previous commit, (so that
the entire test suite passes once again).
Carl Worth [Sat, 27 Jun 2020 16:35:59 +0000 (09:35 -0700)]
Add new failing test case for a reactivated player
I noticed that when a player is reactivated, (that is, by starting a
new event stream by means of a cookie associated with a pre-existing
cookie for a player that had been deactivated), the server was not
properly activating the player.
This commit adds a new failing test case that demonstrates the bug. We
reactivate dale for a 4-player game, but then the server advances the
game out of the answering phase when only 3 players have submitted an
answer. This demonstrates that dale isn't being considered active.
Carl Worth [Sat, 27 Jun 2020 16:25:20 +0000 (09:25 -0700)]
empathy: Don't count inactive players to advance from answering phase
This commit implements the desired behavior described in the previous
commit message. The test case that was added in that commit now
passes, (as does the entire test suite).
In the implementation here, we need a count of all player that have
the active property set to true. Instead of looping over the array and
counting this, we have the Game class track this count as players are
added and removed.
Carl Worth [Sat, 27 Jun 2020 16:11:42 +0000 (09:11 -0700)]
Add new failing test case: Inactive players shouldn't impede phase advance
The current implementation is waiting for all registered players to
have submitted answers before auto-advance (prior to a majority vote
to move on without anyone).
That seems like reasonable logic, except for a player that the server
has already noticed is no longer active (event stream connection has
dropped and server has indicated the player is gone from the game). We
don't want such an inactive player impeding the progress of the game.
This commit adds a test case capturing the behavior we actually want,
(so this test is currently failing).
Carl Worth [Sat, 27 Jun 2020 15:59:25 +0000 (08:59 -0700)]
Add clean handling of Control-C to the test suite
Interrupting the test suite will noe run all cleanup necessary, (such
as terminating the child processes that are still actively listening
to empathy event streams), and will give a (partial) test report of
all tests that have been completed.
This is convenient for when a user doesn't want to wait for the slow
tests to complete, but can still get some good information from
sumarizing the results of all of the fast tests that have already been
performed.
Carl Worth [Sat, 27 Jun 2020 15:43:28 +0000 (08:43 -0700)]
test: Maintain a list of activated players for automated cleanup
The list of deactivate calls at the end of the test sutie was getting
rather messy, (since it required awareness of which players had been
activated in specific tests and then also which had _not_ been
deactivated in other tests).
Instead, we now store an array of each activated player, and loop over
that deactivating all players at the end. We also make deactivate
idempotent, safely doing nothing if we ask to deactivate a plyer which
was already deactivated.
Carl Worth [Sat, 27 Jun 2020 15:00:20 +0000 (08:00 -0700)]
Only count players who participated in judging when determining quorum
Players who are inactive, (whether they registered and then never
submitted answers, or submitted answers but then didn't submit any
judging results), should not be able to sway the results of the
judging.
This commit fixes the failing test case of the previous commit so that
the entire test suite is passing once again.
Carl Worth [Sat, 27 Jun 2020 14:55:09 +0000 (07:55 -0700)]
Add failing test case for a major match-voting bug
Specifically, the majority requirement for a word match to be
considered succesful has been counting all registered players rather
than only the players actually in the current game.
In the degenerate case, having more inactive registered players than
active would mean that no matches would ever be judged as valid even
with unanimous voting. Obviously, this is a disastrous bug.
The test case added here currently fails, (where one person voting
should be considered a (non-strict) majority in a 2-person game).
Carl Worth [Sat, 27 Jun 2020 14:39:53 +0000 (07:39 -0700)]
Add failing test for list of judging players when judging phase begins
In the answering phase, the list of answering players (the ones we are
waiting for) initially starts out as empty and then gets populated
only as people start typing (that is, submit a post to the
"/answering" endpoint).
That's appropriate since we don't know who among the players
registered are really actively "playing".
But that's not the right logic for the judging phase. The judging
phase starts immediately after the answering phase has completed, so
at that point we know the precise list of active players and we should
display all of them in the "waiting" list until each has submitted.
This commit adds a failing test case demonstrating that this list is
empty when the judging phase starts, but it should include the names
of each player that submitted an answer, (but not the name of a player
that is registered but did not submit).
Carl Worth [Sat, 27 Jun 2020 14:31:52 +0000 (07:31 -0700)]
Fix bug described in the previous commit
With this fix, we now advance to the scoring phase as soon as the same
number of people have completed judging as submitted answers in the
first place. (That is, don't wait for a registered player that didn't
participate in the answering phase to now participate in the judging
phase.)
With this fix, the failing test added in the previous commit now
passes, so the test suite is now fully passing.
Carl Worth [Sat, 27 Jun 2020 14:27:41 +0000 (07:27 -0700)]
test: Add failing test case for unnecessary delay for end-judging voting
If all of the players that submitted answers have also all completed
judging, then there's nobody left to wait for and it's pointless to
wait for the idle timer to fire and to force everyone to vote to end
judging. Yet, that's what the implementation currently does.
This commit adds a new test case, which fails, showing the point at
which the game should automatically advance to scoring, (once every
player who submitted an answer has also voted).
Carl Worth [Sat, 27 Jun 2020 13:50:00 +0000 (06:50 -0700)]
test: Keep player event streams open
We're about to fix the server to properly notice when a player drops
their connection and then consider them inactive. To prepare for this
in the test suite, here we put the curl calls getting the event stream
into the background so they stick around, and finally kill them at the
end of the test suite.
We use an ugly `eval` based approach so that emapthy_player_activate
with a name like "alice" sets both an $alice_cookie and an $alice_pid
variable. (Sure would be nice if we had real data structures. Oh
well.)
Carl Worth [Fri, 26 Jun 2020 14:45:10 +0000 (07:45 -0700)]
Start the judging_idle timer whenever a judgment is received
Previously, we were starting the judging_idle timer only when a user
reported they were in the process of judging. This caused a bug in the
following scenario:
* No players group any words
* Majority of players submit the word groups unchanged
* Minority of players drop from the game
* The PHASE_IDLE_TIMEOUT passes
At this point, the game is supposed to consider the judging phase as
idle, but it wasn't doing this because the idle timer never got
started, (because no players actually grouped any words).
This bug came up in some (admittedly artificial) manual
testing. There's no chane to the test suite here because the current
test suite isn't yet exercising the timing related aspects of the
game, (the phase idle timeouts, etc.).
Carl Worth [Thu, 25 Jun 2020 03:19:18 +0000 (20:19 -0700)]
Refactor admin page a bit
Using a new filter to map an array to a new array of just a single
property value from each object of the original array.
This lets us avoid using the "for" directive in the template, as well
as use the "join" filter to get commas between each item in the list,
(which is hard to do with the "for" directive in the template).
Carl Worth [Thu, 25 Jun 2020 01:32:54 +0000 (18:32 -0700)]
admin: Fix admin page to correctly show active/idle games and players
A while ago we changed the storage for players. Previously we had a
_players array and a separate clients array for their
connections. Then at some point in the past we changed to an array
named "players" and instead of separate "clients" each player in
"players" now has its own list of connections.
Ever since that change the admin view has been broken since it wasn't
updated to track that change. Here we bring it up to date, (including
the addition of two nunjucks filters, "active" and "idle" to help with
this).
Carl Worth [Thu, 25 Jun 2020 01:29:45 +0000 (18:29 -0700)]
Mark players as active:false when they drop all connections
Prior to this commit, the intent had been to delete players entirely
when they had no remaining connections. But this code was broken for
the same reason as the bug fixed in the previous commit (filter
returns a new array).
But instead of fixing that bug, here we're actually changing the
semantics so that once a player has so remaining connections they are
simply marked as active:false. This is still broadcast out to all
active players as a "player-exit" event but it means the server is
holding onto the data so that a player can reclaim their spot (and
their score) by rejoining later.
Carl Worth [Thu, 18 Jun 2020 16:04:29 +0000 (09:04 -0700)]
Set judging_start_time_ms before anyone actually does any judging
The judging phase is different than answering in that judging is
optional. So we can't rely on clients actually sending a "judging"
notification, (since they might just submit without having clicked on
any of the words). So instead, we set the start time for the judging
phase as soon as we enter that phase.
Carl Worth [Thu, 18 Jun 2020 15:11:00 +0000 (08:11 -0700)]
Fix bug attempting to set "answering_idle" state
So annoying to have no static compiler checks for assigning to a
mistyped property like this.
Anyway, the impact of the bug here would have been fairly minimal: If
a user reloaded during idle, they would not have gotten the "Move On"
button like expected.
Carl Worth [Thu, 18 Jun 2020 14:59:17 +0000 (07:59 -0700)]
Extend PHASE_IDLE_TIMEOUT from 10 seconds to 30 seconds
The 10 second value was always known to be aggressively short. I had
this in there with such a short value because we didn't have the
feature to auto-advance a phase after every single player was in, nor
to auto-idle the phase after the players-waiting list is emptied. So
without those features implemented, players were forced to wait for
the idle timeout in situations where there was nothing to wait for. So
to keep that from being too annoying, I had this parameter dialed
down.
But now that those two missing features were implemented in recent
commits, we take this timeout up to a higher value. With this,
hopefully the Move On button won't appear too soon so that people
inadvertently skip an active player, but instead only appears once
people really are stuck waiting.
Carl Worth [Thu, 18 Jun 2020 14:57:27 +0000 (07:57 -0700)]
Add named parameters for the two idle timer controls
These controls may need some tweaking, so it's better to have some
defined names for them along with some carefully specified semantics.
Also, we plan to extend the current idle detection from the answering
phased to the judging phase as well, so it will be nice to be able to
reuse these parameters there too.
Carl Worth [Thu, 18 Jun 2020 14:49:16 +0000 (07:49 -0700)]
Broadcast "answering-idle" as soon as the waiting list becomes empty
That is, as long as the answering phase has been going on for a "while".
This avoids an awkward pause when all active players are done
answering, everybody wants to move on, but the "Move On" button hasn't
appeared yet, (because clients haven't been told yet that the
answering phase is idle).
Carl Worth [Fri, 26 Jun 2020 14:33:04 +0000 (07:33 -0700)]
Include still-answering players when ruling on end-asnwering majority
The test suite exposed a logical bug here. Imagine a 10-player game
where two players have submitted and 8 are still answering. Those two
players should not have the ability to move on without the answers
from the larger set of players still waiting. But that's what the old
logic would have allowed here.
In this commit we count up all players who have already submitted
answers as well as all players who have at least indicated that they
are answering in order to decide how many we need for a majority.
Note: This does mean that if something happens, (like a major network
outage), that prevents a majority of the players from being able to
submit their answers, the game cannot proceed with the minority who
succesfully submitted. I think I'm OK with that. (If the minority
really wants to proceed in a case as dramatic as that then it would be
reasonable for them to start a new game.)
With this commit the test suite is now fully passing again, (for the
first time since the recent addition of new tests).
Carl Worth [Fri, 26 Jun 2020 14:31:43 +0000 (07:31 -0700)]
Consistently use null value to reset the ambiguities list
The constructor has always been setting ambiguities to null, but on
game reset it was getting set to 0 instead. The test suite noticed
this inconsistency, which we fix here to make a recently-added test
start passing.
Carl Worth [Fri, 26 Jun 2020 14:26:05 +0000 (07:26 -0700)]
Expand test suite to include testing of auto-phase advancement
The previous commit makes it so that when all involved players are
ready to move on, (such as, everyone has submitted their answers), the
game automatically advances to the next phase.
This breaks some existing tests, which had been expecting the game to
wait for everyone to vote to advance (the old, clunky behavior).
In this commit, we fix the test suite to expect the auto advancing in
the first ame (while also adding a check to ensure it doesn't
auto-advance until the last player is ready).
We also add a second game where auto advancing doesn't happen, (one
player is never ready) but a majority of the remaining players vote to
advance without them.
These tests do exhibit a couple of bugs in the current implementation,
(so some failures are expected here). These failures will be fixed in
the immediately following commits.
Carl Worth [Sun, 14 Jun 2020 23:42:33 +0000 (16:42 -0700)]
Implement an idle event for when nobody has been typing for a while
During the answering phase, if no player has been active, (that is, by
submitting an "answering" event), for 30 seconds, then submit an
"answering-idle" event to all players.
Carl Worth [Sun, 14 Jun 2020 21:57:10 +0000 (14:57 -0700)]
Remove player names from answering and judging when they submit
Without this fix, reloading the "still waiting" view would make player
names that had previously submitted erroneously appear in the "still
waiting" list once again.
Carl Worth [Sun, 14 Jun 2020 21:55:12 +0000 (14:55 -0700)]
Fix game-state object to include players judging and answering
Previously, these were always appearing as empty objects in the JSON
results that we streamed from the server in the game-state object
because JSON.stringify doesn't natively know how to serialize a Set
object.
Here, we provide a replacer function that serializes a Set object as
an array.
Carl Worth [Sun, 14 Jun 2020 18:18:18 +0000 (11:18 -0700)]
Add "/answering" and "/judging" endpoints
These are set up so that clients can report when they are doing any
answering or judging. The server then passes this along so that other
clients can be aware of what's going on.
Carl Worth [Sun, 14 Jun 2020 17:18:12 +0000 (10:18 -0700)]
Rename "/judging" endpoint to "/judged"
This is to make room for a new "/judging" endpoint to capture the
notification that a player is in the process of performing judging,
(that they've started clicking on some of the words in the list).
This commit also fixes the test suite to track this change.
Note: "judged" isn't really a perfect name here. By analogy with
"answer" what we want here is a noun, which would imply "judgment" but
that suggests an entirely different meaning to my ears. So, for now,
we're going with the slightly inconsistent "judged".
Carl Worth [Sun, 14 Jun 2020 16:37:27 +0000 (09:37 -0700)]
Tweak game-ID generation toward more frequently used letters
I'd noticed recently that game IDs seemed to have more Qs, Zs, and Js
than it felt like they should. In fact, all letters were being given
an equal probability of appearing, but that doesn't match our
expectation that some letters should be "rare".
In this commit we tweak the selection of letters toward more "common"
letters. This should hopefully give game ID strings that are slightly
more "friendly" looking in general.
The set of available game ID values isn't reduced here (at least
because of the above, but it is reduced because of part of what is
described below), but when many game IDs are allocated it can now take
longer for the random-selection algorithm to find an available one.
We also switch from using 'B' and 'F'/'X' to instead using 'P' and
'S', again favoring letters that English speakers expect to be
"common".
This actually fixes a bug which I hadn't noticed before, in that the
code has always been replacing a '5' in the input with 'S' but doing
that after 'S' was replaced with 'F', so any input with '5' would not
be mapped as intended. Now an input of '5' will work in the place of
'S'.
Carl Worth [Thu, 25 Jun 2020 16:08:53 +0000 (09:08 -0700)]
Adapt test suite to add explicit voting to advance phases
As of the previous commit, it's now required for players to explicit
vote to advance from one phase to the next. That commit broke the test
suite which didn't have this voting added.
In this commit, we fix the test suite by adding that voting (and
ensuring the state game state transitions from before to after the
vote).
Carl Worth [Sat, 13 Jun 2020 21:38:28 +0000 (14:38 -0700)]
Accept votes to advance game at /end-answers and /end-judging endpoints
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.
Carl Worth [Fri, 12 Jun 2020 17:24:41 +0000 (10:24 -0700)]
Force all submitted judging words to lowercase before mapping
This fixes the bug revealed in the previous commit so that the test
suite now passes once again.
The server now doesn't apy attention to the capitalization that a
client happens to use when providing a judging submission, but will
treat things as equivalent regardless of case differences.
Carl Worth [Fri, 12 Jun 2020 17:18:00 +0000 (10:18 -0700)]
test: Stress the implementation a bit with a mixed-case judging report
With this change to the test, we now have a user submitting a judging
report with "grains of sand" in a list after having received "Grains
of Sand" from the server.
The server currently misscores in this case, so this test case now
fails, (revealing a bug in the server).
Carl Worth [Fri, 12 Jun 2020 17:10:06 +0000 (10:10 -0700)]
Fix bug with incorrect scoring based on capitalization
As exposed in the previous commit which extended testing.
After we construct what we call "word maps", (where a group of words
are hased to by each word in the group individually), we collapse them
down to just the array of word groups themselves. This step was being
carried out by looking for the mapping to the word group where the
mapped word matched the first word in the list.
However, if that first word happened to differ in case from the
mapping word (which was already made canonically lowercase) then the
word group wouldn't be included in the final array and all submissions
of words from that group would incorrectly be scored as singletons.
The fix for this is to simply force the word being compared to as in
this commit.
Carl Worth [Fri, 12 Jun 2020 16:56:35 +0000 (09:56 -0700)]
test: Empathy: Extend test to submit judging results with proper capitalization
In commit abea9915939bd7f5b6e70f12d724f19dc6694ec9 we extended the
test suite to cover the case of players submitting words with mixed
capitalization and we ensured that the server didn't send out any
duplicate words for judging, (that it ignored case when determining
which words were unique).
However, in that commit we still had the players returning the results
of their judging in all lowercase. This is not a good test since
actual clients will return words exactly as they received them.
Here we improve the test by submitting judging results with the same
capitalization that the server used when sending out the
ambiguities. And we also expect that same capitalization to appear in
the final word list.
However, this test currently fails in the final word list _and_ also
fails in the scoring. So this test is exposing a bug that currently
exists in the server.
Carl Worth [Fri, 12 Jun 2020 02:49:12 +0000 (19:49 -0700)]
test: Expand empathy test case to include mixed capitalization
When actually playing a live game recently, we noticed it normalized
different capitalization when sending words out to be judged, but
didn't normalize it when scoring. So we add a test case for this.
It currently fails here, (showing the bug). When the bug is fixed this
test should start passing without needing any change to the test
itself.
Carl Worth [Thu, 11 Jun 2020 23:41:31 +0000 (16:41 -0700)]
test: Exercise the situation coded for in the previous commit
Specifically, by changing bob's answer of "surfers" to "sand" he
should now receive one less point than before. That's because
"surfers" was worth one point (since only bob submitted it), but now
"sand" is worth 0. And _that's_ because bob is already getting full
credit of 3 points from "sands" for matching everybody, so he doesn't
deserve any additional credit for putting down an additional answer
that the group decided is equivalent to one he already has.
Carl Worth [Thu, 11 Jun 2020 23:37:43 +0000 (16:37 -0700)]
Empathy: Use word groups to assign scores to players, not their lists
Previously, we were marching through each players list of words and
looking each word up in the word groups to find a score for that
word. This worked in general, but failed in a specific case:
If a player had two different words that were considered by the group
to be equivalent, that player received the score for that word
twice. To avoid giving a palyer in this situation points that the
group clearly didn't consider they deserved, we instead iterative over
the worud groups themselves to assign points out to players.
This means that when a player ends up having two (or more) words that
end up being equivalent, (based on the team consensus when judging),
all but one of those words will be worth nothing.
Carl Worth [Thu, 11 Jun 2020 22:57:24 +0000 (15:57 -0700)]
Empathy: Change /judging endpoint to expect a top-level word_groups property
It's probably wise, (for future-proofing our APIs), if the server
looks for an explicitly-named property rather than just slurping up
the whole request body.
This also keeps the code more consistent with other endpoints, (which
is going to be particularly important as I start refactoring things to
remove some duplicated code).
Carl Worth [Thu, 11 Jun 2020 22:52:28 +0000 (15:52 -0700)]
Empathy: test: Including final score in testing
And expand the answers a bit to eliminate duplicate scores between
alice and bob. This test verifies that the game is properly scored
according to the word groups that the players submitted.
Carl Worth [Thu, 11 Jun 2020 22:26:17 +0000 (15:26 -0700)]
Empathy: Initial implementation of scoring that considers players' judging
I'm slowly learning more about JavaScript, (such as using
Objects.entries instead of open-coding it, using Set(), etc.), which
is helping as I write progressively more complex code.
But I don't feel _really_ confident that I've written this code in the
best form possible.
Carl Worth [Thu, 11 Jun 2020 22:23:32 +0000 (15:23 -0700)]
Don't throw out punctuation when "canonizing" words
This caused a pretty disastrous failure of the game when the team
chose "Programming languages"; people submitted C, C++, and C#; and
the word list they were presented for voting had only C# in it.
Carl Worth [Thu, 11 Jun 2020 19:11:45 +0000 (12:11 -0700)]
test: Add initial testing for the Empathy game
Two general techniques that are introduced here that will be useful
for testing of other games:
* Registration of multiple user and events sent from each (see
multiple cookies and a player-cookie parameter for many empathy_*
functions)
* Fishing events out of the event stream in response to client
requests (see curl_get_event)
This testing gets as far as is currently implemented in the server:
Multiple player join, a category is submitted and voted one, the game
starts, all players submit answers, players receive words to judge,
and players submit word groups to capture the results of their
judging.
What's not yet tested is the next phase that's also not implemented
yet: The server using the submitted word groups to affect the scoring.
Carl Worth [Thu, 11 Jun 2020 14:52:26 +0000 (07:52 -0700)]
empathy: Fix /prompts endpoint to return the ID of the new prompt
It never ceases to amaze me the bugs that can only be found when
writing tests. (My manual client testing missed this bug because they
never looked for this ID, but instead picked up the ID from the
broadcast to all clients when a new prompt is added.)