Carl Worth [Mon, 9 Mar 2026 15:34:02 +0000 (08:34 -0700)]
Implement better support for a queue of claimants
And when sending an event to the clients to end one claim, indicate in
that event the next claimant so that the client can transition from
one to the next cleanly without a tranient "no claim in progress"
state.
Carl Worth [Sun, 8 Mar 2026 23:41:22 +0000 (19:41 -0400)]
lmno: Save session state to disk so clients can reconnect after server restart
In recent commits we added save/restore of all game state, but our
express session objects were only stored in memory. So, after a server
restart, a client reconnecting was getting an entirely new session
rather than being connect to an existing session (and associated with
the current player state in the game object).
To fix this, this commit adds a new FileStore in session-store.js
which saves sessions to a JSON file on disk when sessions are changed,
(basically just user login or nickname change), and loads them at
server start.
Carl Worth [Sun, 8 Mar 2026 23:19:30 +0000 (19:19 -0400)]
empires: Implement sub-class serialize/restore for extra data
This game contains a fair amount of data not in this.state, so
we need this functions to correctly save and restore an in-flight
game in the case of a server shutdown/restart.
Carl Worth [Sun, 8 Mar 2026 23:19:30 +0000 (19:19 -0400)]
empathy: Implement sub-class serialize/restore for extra data
This game contains a fair amount of data not in this.state, so
we need this functions to correctly save and restore an in-flight
game in the case of a server shutdown/restart.
Carl Worth [Sun, 8 Mar 2026 23:13:53 +0000 (19:13 -0400)]
anagrams: Restart any necessary timers when restoring a game
This could give some extra time to the current in-progress claim/vote,
but that's fine, (and better than leaving the timer un-started which
could result in a hung game if a player has been disconnected).
Carl Worth [Sun, 8 Mar 2026 23:01:04 +0000 (19:01 -0400)]
lmno: Add game specific restore() operation to reconsstruct Set objects
The game state save logic serializes any Set objects as arrays, so
we need this extra little bit of code to re-construct Set objects
from arrays at time of restore.
Carl Worth [Sun, 8 Mar 2026 22:57:29 +0000 (18:57 -0400)]
lmno: Implement saving of game state when shutting down the server
State is written to data/lmno-state.json at shutdown and then re-read
at server start. This should let us stop/start the server without
disrupting game play for in-progress games.
Carl Worth [Sun, 8 Mar 2026 22:33:12 +0000 (18:33 -0400)]
anagrams: Implement an idle counter to detect a game-end condition
The idle counter doesn't start until the bag is empty. After that,
any client post resets the counter. Once the counter expires the
servers sends a game-ending event to all clients. If they don't
reply that the user is still looking, then the game will be ended.
Carl Worth [Sun, 8 Mar 2026 15:25:49 +0000 (11:25 -0400)]
anagrams: Have the server auto deal up to 7 tiles to the center
Until there are a few tiles out on the board, it's silly to make the
players press the bag button. Once there are 7 or more it's reasonable
to have the game slow down (no more auto deal) and let players either
find anagrams from what's there, or else grab new tiles from the bag.
Carl Worth [Sun, 8 Mar 2026 15:13:50 +0000 (11:13 -0400)]
letterrip, anagrams: Make game reload smoother
Previously we were requiring each player to do a separate join_game
(even after they were already part of the game). Notably, if the user
ever reloaded their browser, they had to click "Join game" yet again.
Instead, in this commit we add a game.started state. And we only need
one player to start the game, triggering the send of the started game
state to all players.
Now, if a player reloads their browser, they will just see the game
state, and not a "join game" button.
Carl Worth [Sun, 8 Mar 2026 12:23:09 +0000 (08:23 -0400)]
Simplify tile dealing from the bag
No longer require multiple people to request a letter. Instead, any person
can draw a new letter from the bag as long as no letter reveal is currently
in progress.
Carl Worth [Sun, 8 Mar 2026 05:27:05 +0000 (00:27 -0500)]
Fix Anagrams: broadcast claim-end on word acceptance, remove game steal
Broadcast a claim-end event after a word is accepted so clients properly
exit claim mode. Remove the _find_game_steal function (deferred for a
better approach later).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Carl Worth [Sun, 8 Mar 2026 00:06:48 +0000 (19:06 -0500)]
Add Anagrams game server engine
New game with real-time word claiming from a shared letter pool.
Features queued claiming, word stealing, dictionary validation
with player voting for non-TWL words, scaled letter-request
timer, and game-end steal mechanic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Carl Worth [Sun, 8 Mar 2026 00:03:57 +0000 (19:03 -0500)]
Extract shared tile distribution and bag logic into tiles.js
Letter Rip now imports from the shared module instead of defining
its own tile distribution and make_bag(). This prepares for the
Anagrams game which will reuse the same tile bag (without blanks).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Carl Worth [Sat, 7 Mar 2026 16:50:01 +0000 (11:50 -0500)]
Save nickname in local storage
So that when a user creates a new game they don't have to enter their
name again. (Not that that would be a big penalty, but I do want LMNO
to be as smooth to use as possible.)
Carl Worth [Sat, 7 Mar 2026 13:08:04 +0000 (08:08 -0500)]
letterrip: Implement server-side validation of words
Now that we have the dictionary on the server side, (for purpose of
final scoring) we also implement validation of words on every tile
placement on the server side. This lets us drop the dictionary from
the client side so there is no possibility of disagreement between
client and server on which words are valid.
Carl Worth [Sat, 7 Mar 2026 04:06:48 +0000 (23:06 -0500)]
letterrip: Add scoring of all players at the end of the game
This requires the server to have the list of words, which is added
here. When the game is over, the server sends the scores and boards
of all players out.
Carl Worth [Fri, 6 Mar 2026 14:36:01 +0000 (09:36 -0500)]
Add tracking of client placement of tiles
This adds a new /place endpoint to be told where tiles are placed, and
allows the server to send all placed tiles when a player
reconnects. This means that a client refresh no longer clears the
entire board, (which was really annoying).
Carl Worth [Fri, 6 Mar 2026 11:36:46 +0000 (03:36 -0800)]
Add serving of static files from ../lmno.games
This makes development simpler since we don't need an additional
server to serve the static files, (on our production machine, we do
have a separate web server for the static files).
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.