]> git.cworth.org Git - lmno.games/log
3 years agoAllow word groups and votes to wrap during the judging process.
Carl Worth [Sun, 14 Jun 2020 23:58:05 +0000 (16:58 -0700)]
Allow word groups and votes to wrap during the judging process.

This should keep things from sticking off to the left and right when
there are many words in a group.

3 years agoDon't display the answering "Move On" button until the server reports idle
Carl Worth [Sun, 14 Jun 2020 23:43:49 +0000 (16:43 -0700)]
Don't display the answering "Move On" button until the server reports idle

By waiting until the server reports that things are idle, it's safer
to display this button. (Displaying it early might result in a a user
being considered a majority of just the group of that player alone,
which is not what is desired.)

3 years agoFix to use server-sent state for whether player has answered/judged
Carl Worth [Sun, 14 Jun 2020 22:14:44 +0000 (15:14 -0700)]
Fix to use server-sent state for whether player has answered/judged

Previously we were using a component state Boolean "submitted" for
this information, but that's fundamentally broken since if the client
reloads the page that state is lost, resulting in the user being
presented with the form as to submit a second time (which is not
allowed by the game).

So, now the rendering looks to see whether the current player's name
is in the list of submitted players, and if so, it does not display
the form. This is exactly what we want.

3 years agoCopy several game-state members into client state
Carl Worth [Sun, 14 Jun 2020 22:00:04 +0000 (15:00 -0700)]
Copy several game-state members into client state

The server has been telling us (or trying to at least: see recent bug
fixes with JSON serialization of Set objects) the lists of players who
are in the process of answering or judging within the game-state
object, but the client has been ignoring this.

Without this fix, reloading of a status page could cause names to
disappear from the "still waiting" lists or the "move on" buttons.

3 years agoFix bug preventing a user from being able to "unselect" a word while judging
Carl Worth [Sun, 14 Jun 2020 19:22:54 +0000 (12:22 -0700)]
Fix bug preventing a user from being able to "unselect" a word while judging

Previously, the selection was accidentally "sticky" unless the player
went on to group a word with another. So if the user accidentally
clicked a word there was no way to unselect it without maging a bogus
grouping and then undoing that.

3 years agoAdd (rate-limited) posts to the /answering and /judging endpoints
Carl Worth [Sun, 14 Jun 2020 18:54:42 +0000 (11:54 -0700)]
Add (rate-limited) posts to the /answering and /judging endpoints

This gives all connected clients visibility into people that are
actively filling out information.

3 years agofixup-add-object-entries-map calls
Carl Worth [Sun, 14 Jun 2020 18:54:25 +0000 (11:54 -0700)]
fixup-add-object-entries-map calls

3 years agoDelete some dead (and broken) code.
Carl Worth [Sun, 14 Jun 2020 18:53:02 +0000 (11:53 -0700)]
Delete some dead (and broken) code.

This code would obviously not work, (it wouldn't even compile
cleanly). It also wasn't called anywhere. It's gone now.

3 years agoTweak the error message when submitting results of judging
Carl Worth [Sun, 14 Jun 2020 18:01:18 +0000 (11:01 -0700)]
Tweak the error message when submitting results of judging

I wanted this when debugging a confusing case of this error text
appearing, (and we had the same text in two places). So having unique
text here will help.

In the end, the bug I was dealing with was from my Android browser
having a persistent cache of a stale JavaScript file.

3 years agoFix page title to refer to Empathy, not Empires
Carl Worth [Sun, 14 Jun 2020 18:00:34 +0000 (11:00 -0700)]
Fix page title to refer to Empathy, not Empires

Obviously, this was a leftover copy/paste error from when initially
creating the Empathy game and using Empires as a template.

3 years agoTrack server change renaming "judging" to "judged"
Carl Worth [Sun, 14 Jun 2020 17:21:32 +0000 (10:21 -0700)]
Track server change renaming "judging" to "judged"

There should be no functional change with the server and client just
moving to a new name for this endpoint here.

3 years agoAdd a "Move On" button to the end of both the answering and judging phases
Carl Worth [Sat, 13 Jun 2020 22:02:14 +0000 (15:02 -0700)]
Add a "Move On" button to the end of both the answering and judging phases

These use the same voting style as the prompt voting, and allow the
game to proceed once a majority of players have voted to move on. This
should help avoid the game being locked out just because a single
player has decided not to play anymore, or somehow became disconnected
(which has already happened in practice more than once).

With this change, we're also now displaying the actual names of the
players that have already answered/judged (as opposed to just the
count as we were displaying previously). And we've written code to
also display the list of player names who are still in the
answering/judging process but that list is not yet being populated
(we'll need just a little more plumbing to have the client send an
activity ping to the server when typing/tapping/clicking before

3 years agoAdd transform-object-rest-spread to list of Babel plugins
Carl Worth [Sat, 13 Jun 2020 21:44:33 +0000 (14:44 -0700)]
Add transform-object-rest-spread to list of Babel plugins

This allows for using the object spread syntax in the source, such as:

updated_players = {...players, id: {name: "player-name"}}

which babel will transform to something else for us.

3 years agoempathy: Fix judging interface to properly merge two entire groups
Carl Worth [Fri, 12 Jun 2020 00:53:20 +0000 (17:53 -0700)]
empathy: Fix judging interface to properly merge two entire groups

Previously, when selecting an item that was a part of a larger group,
it could get pulled out of that group to be merged with the other
selected item. This was absolutely bewildering to players.

Instead, the right thing is to entirely merge the two groups to which
each of the two selected items belong. That's what we do here, and
using Set objects rather than simply arrays as we had before.

3 years agoAdd clean support for rejecting categories that are too large
Carl Worth [Fri, 12 Jun 2020 00:08:02 +0000 (17:08 -0700)]
Add clean support for rejecting categories that are too large

This is clean in the sense that it prints a message if the server
rejects the submission, but before that it will even do the nice thing
of checking the number on the client side, (and reporting this with
the HTML5 validity API).

3 years agoempathy: Add a comman between player names
Carl Worth [Thu, 11 Jun 2020 23:01:06 +0000 (16:01 -0700)]
empathy: Add a comman between player names

And also simplify the code quite a bit, (using a simple join()
function instead of a map with multiple span and literal {" "}

3 years agoempathy: Track change in the server's implementation of /judging
Carl Worth [Thu, 11 Jun 2020 23:00:23 +0000 (16:00 -0700)]
empathy: Track change in the server's implementation of /judging

This endpoint now requires the data to have a top-level "word_groups"
property, so here it is.

3 years agoAdd support for judging of equivalent answers
Carl Worth [Thu, 11 Jun 2020 14:25:15 +0000 (07:25 -0700)]
Add support for judging of equivalent answers

This involves receiving a list of unique words that were submitted and
then allowing the user to group them into words that should be scored
as if identical. The interface implemented here uses sequential
clicking, but maybe it would be more intuitive to do drag-and-drop
instead? I may have to experiement with that.

3 years agoUse triple-equals instead of double
Carl Worth [Thu, 11 Jun 2020 14:24:39 +0000 (07:24 -0700)]
Use triple-equals instead of double

Following Richard's rule of "only ever use triple-equals, never double".

3 years agoAvoid unnecessary use of fill(null)
Carl Worth [Thu, 11 Jun 2020 01:04:16 +0000 (18:04 -0700)]
Avoid unnecessary use of fill(null)

Where we can just use a spread-syntax array copy for the same effect,
(namely, ensuring an array has actual items (even if undefined) rather
than "empty" so that map() actually does something).

3 years agoEmpathy: Display player scores at the main screen of the game
Carl Worth [Wed, 10 Jun 2020 16:19:14 +0000 (09:19 -0700)]
Empathy: Display player scores at the main screen of the game

Leaving each off entirely if unset or 0.

3 years agoEmpathy: When receiving a game-state event overwrite all prompts
Carl Worth [Wed, 10 Jun 2020 14:57:08 +0000 (07:57 -0700)]
Empathy: When receiving a game-state event overwrite all prompts

Originally this cod was written to add each received prompt, but that
does the wrong thing when the game-state object is trying to set a
subset of the prompts we already have, (for example, to drop the
prompt we just finished playing when starting a new game).

3 years agoAdd display of scores
Carl Worth [Wed, 10 Jun 2020 04:29:45 +0000 (21:29 -0700)]
Add display of scores

And a not-quite-yet-fully-functional "New Game" button.

I don't know if "New Game" is broken on this side or on the server
side, (this was part of a 90-minute flurry of code).

3 years agoDisplay the number of players who have already submitted answers
Carl Worth [Wed, 10 Jun 2020 03:03:02 +0000 (20:03 -0700)]
Display the number of players who have already submitted answers

With a message that could look like this:

2/5 players have responded

And of course, that dynamically updates.

This lets players at least know that something is happening, or
whether they are still waiting for somebody.

3 years agoEmpathy: Add support for submitting answers to a prompy
Carl Worth [Wed, 10 Jun 2020 02:46:28 +0000 (19:46 -0700)]
Empathy: Add support for submitting answers to a prompy

For this we convert ActivePrompt from a function to a class-based
React component. Then we use the "uncontrolled components" technique
again to arrange for an array to hold the form values.

Finally, when answers are submitted successfully we display a simple,
static message. Eventually, we'll want to display some dynamic updates
as other players vote, (but for that, we'll also need the server to
give us that information).

3 years agoAdd a button to advance from prompt voting to playing the actual game
Carl Worth [Tue, 9 Jun 2020 14:59:41 +0000 (07:59 -0700)]
Add a button to advance from prompt voting to playing the actual game

Once a majority of the players have voted a new button appears (for
everyone) that when pressed tells the server that it's time to start
the game.

Then, when the client receives a "start" event from the server with
the prompt the server chose, the client replaces the entire interface
with a form for entering the responses to the prompt.

The submit button for that form is currently inert.

3 years agoDrop an unneeded function
Carl Worth [Tue, 9 Jun 2020 04:34:00 +0000 (21:34 -0700)]
Drop an unneeded function

It was only one line, and only called once, so better just to inline it.

3 years agoEmpathy: Let React now I'm a good boy and I won't mutate state
Carl Worth [Tue, 9 Jun 2020 02:10:52 +0000 (19:10 -0700)]
Empathy: Let React now I'm a good boy and I won't mutate state

By using React.memo() and PureComponent, React can avoid doing any
re-rendering of components that haven't changed at all.

3 years agoAdd display of votes on top of each prompt's vote button
Carl Worth [Mon, 8 Jun 2020 16:15:00 +0000 (09:15 -0700)]
Add display of votes on top of each prompt's vote button

This is a simple bit of feedback so players can see which options are
being voted on by other players. I won't claim that there's anything
inspired about the stlying or color selection here. Maybe Karen will
have some suggestions to improve this later.

3 years agoRestrict :hover styling to when a media query says hover is fully supported
Carl Worth [Mon, 8 Jun 2020 16:13:43 +0000 (09:13 -0700)]
Restrict :hover styling to when a media query says hover is fully supported

Otherwise, on my phone I was seeing "sticky" hover effects, (after I
clicked a button it stayed looking like it was still being pressed
after I let go which was very confusing).

3 years agoAdd a new color --text-fg-on-accent-bright
Carl Worth [Mon, 8 Jun 2020 16:11:03 +0000 (09:11 -0700)]
Add a new color --text-fg-on-accent-bright

For allowing the designer to select what color text should be when on
a background of --accent-color-bright.

Note: The value for this color happens to match the color of
previously-defined values currently, but that's just me throwing
programmer-art colors in place. That's why we don't reference an
existing variable in the value here, even though the color is
currently identical to a previous one, (we wouldn't want a designer to
think they are necessarily linked).

3 years agoEmpathy: Send prompt suggestions to server and display received prompts
Carl Worth [Mon, 8 Jun 2020 13:54:16 +0000 (06:54 -0700)]
Empathy: Send prompt suggestions to server and display received prompts

The received prompts can come in an initial list as part of the
"game-state" event sent when first connecting, and they can also come
in subsequent "prompt" events when a player submits a category
suggestion. These are all displayed as large buttons.

Clicking a button also sends a vote to the server, but received votes
are not yet displayed in any way.

3 years agostyle: Add a new variable: --text-fg-on-accent
Carl Worth [Mon, 8 Jun 2020 13:51:56 +0000 (06:51 -0700)]
style: Add a new variable: --text-fg-on-accent

This removes a hard-coded "white" from the styling of the
button. Instead, the theme designer can now choose an appropriate
color for text that is displayed against a background of

3 years agostyle: Apply "box-sizing: border-box" globally
Carl Worth [Mon, 8 Jun 2020 13:48:56 +0000 (06:48 -0700)]
style: Apply "box-sizing: border-box" globally

This is really the only sane way to work. Without this, the behavior
of padding is really hard to use. For example, if I set an element to
"width: 100%" it fills the space like I want. But then, its child
elements might be right up against the left edge, so I had
"padding-left" of some amount. This moves the children from the edge
like I want, but _also_ makes the element grow so that its now larger
than the 100% of its container like I had specified.

That looks to me entirely like a broken default and is something to
just set once, globally to avoid this class of frustration.

3 years agoTake control over the wording of the validation message for category
Carl Worth [Sun, 7 Jun 2020 22:47:36 +0000 (15:47 -0700)]
Take control over the wording of the validation message for category

The "pattern" attribute on the text field was really handy for
triggering HTML5 validation that the input matched a regular
expression. The only real downside is that it gives a truly generic
error message:

Please match the requested format.

That doesn't actually tell the user waht to fix, (in this case, to add
a number). I really wish there existed another attribute to simply
provide the error message that should be provided. If there is, I
couldn't find one.

I did have the title set here, which is close, but with two problems:

  1. The resulting error message isn't _just_ my text, it is:

Please match the requested format:
<My title text here>

     so I don't quite get as much control as I want.

  2. The title text shows up immediately when hovering over the input
     field, (even before the user has ever typed anything). But this
     is an error message that I only want the user to see if they've
     committed an error.

It took me quite a lot of struggling to come up with a solution for
this minor issue that works the way I want. Here it is:

  1. I remove the pattern attribute, (so I don't get any default
     validation of the input format). This is essential or else the
     "Please match the requested format" text will appear at least

  2. In the subit handler, I validate the input against my regular
     expression and call setCustomValidity on the input field to set
     the text I want to appear.

  3. But _also_ immediately after doing this I _also_ call
     reportVisibility on the form element. Otherwise, the input field
     will still get styled as invalid as I want, but the error message
     won't actually get reported, (unless the user tries submitting
     _again_ while the input is still invalid).

  4. Next I also have to arrange to _clear_ this invalid state. So for
     this I add a new onChange handler (so it will be called for every
     keystroke). For this, a lot of tutorials just call
     setCustomValidity with an empty string here unconditionally. The
     downside of that is that the field will get styled as valid as
     soon as the user makes any change. Instead, I check the regular
     expression here so that the field is only styled as valid once
     the mistake is corrected. (This is consistent with the behavior
     of the default HTML5 validation with the "pattern" attribute.)

So in the end, this gives the behavior that I want. It's a little
wordy, especially here in my explanation!, but also in the code:
Particularly that two different handlers are required: One to set the
error state and one to clear it. As I implemented things here the
regular expression is even duplicated in those two cases, (but that's
a defect that could be addressed---the pattern could be stashed in a
common place if I cared to do it).

Note that it would be possible to set the error state in an 'else'
clause within my onChange handler, (and that would eliminate the
duplication of the regular expression pattern). The reason I don't do
that here is that it would cause the field to be styled with the
angry-red "invalid" styling as soon as the user started typing, rather
than waiting for form submission before validation happens. So that
could be annoying to users (it would drive me crazy) and it would also
be inconsistent with how HTML5 validation happens with the "pattern"

3 years agoAdd a submit handler function for our form
Carl Worth [Sun, 7 Jun 2020 22:22:28 +0000 (15:22 -0700)]
Add a submit handler function for our form

This is still a stub that doesn't actually _do_ aything yet.

Note that we're using the "uncontrolled components" React pattern for
the input field here as described here:


The alternative, forcing a new call to React's setState on every
keypress seems really silly to me, (I don't care to have React getting
involved on every keypress).

3 years agoConvert CategoryRequest from a function to a class
Carl Worth [Sun, 7 Jun 2020 22:14:10 +0000 (15:14 -0700)]
Convert CategoryRequest from a function to a class

This seems like it will be more convenient for defining additional
methods to get access to from the JSX code (such as a submit handler

3 years agoInitial framework for an Empathy game
Carl Worth [Sun, 7 Jun 2020 18:56:35 +0000 (11:56 -0700)]
Initial framework for an Empathy game

This starts with the generic code, (grabbed from Scribe), for
displaying the game INFO, (with a button for copying the link), and
the list of players that are in the game.

It also provides a form for submitting a category, but that is still
inert for now.

3 years agoDrop unused scribe/game.html
Carl Worth [Sun, 7 Jun 2020 17:23:02 +0000 (10:23 -0700)]
Drop unused scribe/game.html

The server actually has a template file that serves this prupose. So
this static HTML file is entirely unused, (perhaps obviously so since
it has "Tic-Tac-Toe" in its title.

3 years agoScribe: Fix the font size to not depend on page height
Carl Worth [Sun, 7 Jun 2020 00:16:08 +0000 (17:16 -0700)]
Scribe: Fix the font size to not depend on page height

The height of the game board is already fixed based on the viewport
width, (to mtain a square asepct ratio). The use of 'vmin' in the font
size led to a weird result where shrinking the page height left the
board size untouched but the text-based game-play components would
shrink, which was undesirable.

The fix for that here is to simply switch from 'vmin' to 'vw' so the
font size depends only on the page width, not the height.

While exploring the issue described above, I found that making the
page _extremely_ wide also caused the fonts to grow excessively and
make the board spill out over the page margin. To avoid that, we cap
the font size with a calculation based on the maximum page width. This
takes advantage of a variable introduced in the previous commit.

3 years agoParameterize the styling of the page width
Carl Worth [Sun, 7 Jun 2020 00:14:31 +0000 (17:14 -0700)]
Parameterize the styling of the page width

Now that I now we can use CSS variables, I can define some top-level
variables to control the page width and then use those for derived

This makes the styling _much_ more maintainable as it's actually
possible to change a single variable and have several related values
change as appopriate.

3 years agoScribe: Increase font size for game elements
Carl Worth [Sat, 6 Jun 2020 19:49:24 +0000 (12:49 -0700)]
Scribe: Increase font size for game elements

It was just too hard to see things on my phone.

I hadn't used this larger font size earlier because it caused the
squares to stretch tall (no longer as squares) and squashing flat the
mini grids without characters in them.

But here I found I can avoid that problem by setting line height to 0.

3 years agoDon't underline links in headers
Carl Worth [Sat, 6 Jun 2020 19:31:54 +0000 (12:31 -0700)]
Don't underline links in headers

Headers want their own styling and look *terrible* with underlining.

3 years agoAdd a button to copy the game URL for sharing and tighten up text
Carl Worth [Sat, 6 Jun 2020 19:30:23 +0000 (12:30 -0700)]
Add a button to copy the game URL for sharing and tighten up text

The way we are styling <h2> right now makes it far too wasteful of
vertical screen real estate. Instead, use the same font size/weight
but inline with the sentence.

Also, this button for copying the game URL should be handy,
particularly on phones, etc.

3 years agoDelay the "Connection lost" message by a second
Carl Worth [Sat, 6 Jun 2020 19:27:57 +0000 (12:27 -0700)]
Delay the "Connection lost" message by a second

Otherwise, when simply clicking a link to navigate away from the page,
this scary-looking red box can appear. Nobody should complain if it
takes a few seconds for the game to notice a connection is lost.

3 years agoDrop back from fanct UTF to plain ASCII "+" and "o"
Carl Worth [Sat, 6 Jun 2020 18:57:33 +0000 (11:57 -0700)]
Drop back from fanct UTF to plain ASCII "+" and "o"

We can use the fancier glyphs in the future after we arrange for the
client to have the appropriate font glyphs available.

3 years agostyle: Force some padding at the bottom of the page.
Carl Worth [Sat, 6 Jun 2020 18:55:09 +0000 (11:55 -0700)]
style: Force some padding at the bottom of the page.

Otherwise the content can run right into the page bottom which looks
quite terrible.

3 years agoScribe: Style the board so there are clear gaps between the mini grids
Carl Worth [Sat, 6 Jun 2020 18:53:44 +0000 (11:53 -0700)]
Scribe: Style the board so there are clear gaps between the mini grids

Thanks to Richard for helping me figure out how to force the square
aspect ratio at the top-level. Below that, it's just two levels of CSS
"grid" for the boxes and the one of "flex" to get the centered

3 years agoInitial implementation of Scribe
Carl Worth [Sat, 6 Jun 2020 15:55:23 +0000 (08:55 -0700)]
Initial implementation of Scribe

This is not at all sophisticated yet.

Some of the things that are missing:

  * Proper layout of the board (need spacing to separate mini grids
    from each other).

  * Move restrictions: Don't allow a player to move in a super grid
    that doesn't correspond to their last move's mini-grid placement
    (unless the corresponding super-grid is full).

  * Presentation to the user of the scored glyph shapes

  * Scoring of completed mini grids

  * Scoring of the super grids for the final game

And on that last point, there needs to be an option to play either the
"majority" or "super-glyph" variation for the final scoring.

3 years agoRemoving a debugging statement
Carl Worth [Sat, 6 Jun 2020 15:53:44 +0000 (08:53 -0700)]
Removing a debugging statement

I just happened to notice this errant debug message in my browser's

3 years agoRename "opponent" in both the interface and the code
Carl Worth [Sat, 6 Jun 2020 12:02:08 +0000 (05:02 -0700)]
Rename "opponent" in both the interface and the code

The code was incorrect, since what was called "opponent_info" was
really just a list of other players (some of which could be on the
same team rather than an opposing team) so the new name of
"other_players" is more accurate.

In the UI, we also now use "another player" instead of "opponent" to
just be more friendly I suppose.

3 years agoSubtle refinement of the status message.
Carl Worth [Sat, 6 Jun 2020 11:54:39 +0000 (04:54 -0700)]
Subtle refinement of the status message.

This distinguishes the message based on how many opponents are in the
game so there's a different message whether we are waiting for an
opponent to move or else to join in the first place.

Also, we use "either player" if there are two players in the game, or
else "any player" if there are mroe than two players in the game.

3 years agoStyle inline buttons for better appearance
Carl Worth [Sat, 6 Jun 2020 11:28:19 +0000 (04:28 -0700)]
Style inline buttons for better appearance

By shrinking the font size within the button just a bit, the entire
button now fits within a line of text, (rather than the text of the
button being the same size as the surrounding text but the button
sticking way out both above and below).

3 years agoBe more selective about when to display buttons for joining a team
Carl Worth [Sat, 6 Jun 2020 11:17:53 +0000 (04:17 -0700)]
Be more selective about when to display buttons for joining a team

Specifically, before the first move, we never want any buttons,
(instead, the first player will commit to a team by making a move).

After the first move, there are two cases:

1. A player is already on a team:

In this case we want only one button, labeled "Switch" to
change to the other team.

2. A player is just spectating:

This is the only case where we need to display two buttons,
one labeled "Join X" and one labeled "Join O".

3 years agoDisplay all players, not just a single component
Carl Worth [Sat, 6 Jun 2020 03:17:46 +0000 (20:17 -0700)]
Display all players, not just a single component

It's a little trickier to deal with an array (both on the setState
side and when using the map() function to generate React elements) but
it's not too bad.

Thanks for the help, Richard!

3 years agoDisplay the opponent's name/team next to our own name/team
Carl Worth [Sat, 6 Jun 2020 01:13:16 +0000 (18:13 -0700)]
Display the opponent's name/team next to our own name/team

This is mostly functional, but has at least two problems:

1. The trailing comma appears when an opponent hasn't joined yet

2. It will only display a single opponent even if additional players
   join the game

3 years agoTighten up the display of the PlayerInfo block
Carl Worth [Sat, 6 Jun 2020 01:06:45 +0000 (18:06 -0700)]
Tighten up the display of the PlayerInfo block

Drop the display of the ID value, because that's meaningless to a
user, and then also just put the team into parens after the player (or
omit those parens entirely if the player is not on a team).

And use a single prop for all of this information instead of a
separate prop for each property of the player_info object.

3 years agoUse an actual space not an &nbsp; entity.
Carl Worth [Sat, 6 Jun 2020 01:00:20 +0000 (18:00 -0700)]
Use an actual space not an &nbsp; entity.

I didn't really want any non-breaking semantics here. I just wanted a
plain-old space but it wasn't obvious to me how to get it for some
reason. The answer is pretty simple: a string literal inside curly

3 years agoAllow either player to make the first move.
Carl Worth [Fri, 5 Jun 2020 23:06:59 +0000 (16:06 -0700)]
Allow either player to make the first move.

That is, by having the board be active even if we are not assigned to
a team yet. (Obviously, for this to work, this depends on the server
also permitting us to send a move before we've joined a team.)

When we send a first move this way we append an "assert_first_move"
property which tells the server to reject our move if someone else
beat us to it.

Finally, this commit rewords the message above the game to take into
account the team of the current player.

3 years agostyle: Use a pointer cursor for the button element
Carl Worth [Fri, 5 Jun 2020 18:15:09 +0000 (11:15 -0700)]
style: Use a pointer cursor for the button element

This is just another nice cue to the user that the button is something
that can be clicked on.

3 years agotictactoe: De-activate board when it's not the player's turn
Carl Worth [Fri, 5 Jun 2020 18:08:32 +0000 (11:08 -0700)]
tictactoe: De-activate board when it's not the player's turn

There's no reason to allow the user to select a square and send the
move to the server when the client can already know that the server is
just going to reject the move because it's not our turn anyway.

3 years agoAvoid some repeated references to "this.type"
Carl Worth [Fri, 5 Jun 2020 18:03:08 +0000 (11:03 -0700)]
Avoid some repeated references to "this.type"

Simpler to just cache this is "state" at the beginning of the function
and then use that throughout.

3 years agotictactoe: Improve player-info block for the case of no assigned team
Carl Worth [Fri, 5 Jun 2020 17:50:04 +0000 (10:50 -0700)]
tictactoe: Improve player-info block for the case of no assigned team

An explicit clause of "not on a team" is more clear than the dangling
"on team: ".

3 years agoReturn null from GameInfo and PlayerInfo if they have no populated props
Carl Worth [Fri, 5 Jun 2020 17:26:25 +0000 (10:26 -0700)]
Return null from GameInfo and PlayerInfo if they have no populated props

These info objects get filled in with data that is streamed from the
server "/events" API. While the page is still loading, we don't want
to brifly see the skeleton of these objects drawn with no real data
inside them.

It's much cleaner to return null instead. This gives a clean result
where these sections of the page only appear when fully formed.

3 years agoAdd two buttons to allow the player to choose a team to join
Carl Worth [Fri, 5 Jun 2020 17:18:17 +0000 (10:18 -0700)]
Add two buttons to allow the player to choose a team to join

This demonstrates how a "Join Team" button could actually work.

Of course, the notion of teams and being able to switch from one to
the other is a bit much for tic tac toe, (but could actually be useful
for a case of two people playing on a single computer for example).

What we definitely want here is some implicit team membership. Such as
"Either play can make the first move" and then having that assign the
player that moves to Team X.

If we did that, then we could also simplify by having just a single
"Swith Teams" button instead of having one button for each team.

3 years agoAdd a new fetch_put_json
Carl Worth [Fri, 5 Jun 2020 17:17:16 +0000 (10:17 -0700)]
Add a new fetch_put_json

This is very similar to fetch_post_json but with a different request
method. In fact, we share the implementation with a new
fetch_method_json that accepts which method to use.

3 years agoAdd key properties to GameInfo and PlayerInfo blocks
Carl Worth [Fri, 5 Jun 2020 17:15:59 +0000 (10:15 -0700)]
Add key properties to GameInfo and PlayerInfo blocks

This silences the warning that React gives:

    Warning: Each child in a list should have a unique "key" prop

Which I seem to get every time I add a new list of elements.

3 years agoMakefile: Fix downloading of React javascript files
Carl Worth [Fri, 5 Jun 2020 17:09:52 +0000 (10:09 -0700)]
Makefile: Fix downloading of React javascript files

This has not worke since commit b5bcbc45f19ee068478edb73b48bc7194e582da8

There were two things broken in that commit:

  1. It was inserting a "deps/" into the URL for downloading, (which
     doesn't exist---we only have "deps/" in the local filesystem.

  2. It wasn't distinguishing "react-dom@16" from "react@16" in the
     URL, (half of the files we download need one, and half the

This commit fixes both. The first by using a "substitution reference"
with the $@ variable to remove the "deps/" from its value when
constructing the URL. And the second by splitting the existing rule
into two rules.

Whle here, we also replace the use of the patsubt function in the
SHA512 recipe with the simpler substitution reference exactly as we
are now using it in the line before.

3 years agoAdd a simple player-info div
Carl Worth [Fri, 5 Jun 2020 14:48:31 +0000 (07:48 -0700)]
Add a simple player-info div

This is populated by the player-info event that is streamed to us when
we first conenct to /events and should also be updated by any
subsequent player-update events for our specific player.

3 years agotictactoe: Add a simple game-info div
Carl Worth [Fri, 5 Jun 2020 01:19:41 +0000 (18:19 -0700)]
tictactoe: Add a simple game-info div

This is populated dynamically by the server sending the game-info
event and contains both the game ID as well as the URL.

We're not yet doing any interesting styling here, (it should get
tucked up into the upper-left corner as just a button with the game
ID, and when clicked on it will expand to show the URL to share).

3 years agoRename reset_state() to reset_board()
Carl Worth [Fri, 5 Jun 2020 00:36:23 +0000 (17:36 -0700)]
Rename reset_state() to reset_board()

It's not resetting _all_ state, just the board.

In the past, these two notions were basically the same, (since the
board was the only state we hadd), but soon we'll be adding players
and other information outside the board, so this new naming is more

3 years agoRename several internal names from ICantReadThis to much_better_thanks
Carl Worth [Thu, 4 Jun 2020 23:40:30 +0000 (16:40 -0700)]
Rename several internal names from ICantReadThis to much_better_thanks

I'm not entirely sure this is a good idea with the number of library
functions that we're calling that still use camel case, (such as
addEventListener, and perhaps most significantly, onClick), but the
code was even more mixed before, so it's maybe at least more
consistent in its inconsistency now, or something?

3 years agoRename stepNumber to step_number
Carl Worth [Thu, 4 Jun 2020 23:19:11 +0000 (16:19 -0700)]
Rename stepNumber to step_number

And drop the dead-code jumpTo while we're at it.

I'm gradually rewriting the original tutorial code into my own style.

3 years agoAdd an enum (or an enum-like object) for Team values
Carl Worth [Thu, 4 Jun 2020 23:15:42 +0000 (16:15 -0700)]
Add an enum (or an enum-like object) for Team values

We replace the existing xIsNext Boolean in the state with a new
next_to_play property takign a value from this enum.

And we will soon also be using this enum to track the team from whose
point of view the game is being shown.

3 years agotictactoe: Don't let the user send an illegal move
Carl Worth [Thu, 4 Jun 2020 00:37:59 +0000 (17:37 -0700)]
tictactoe: Don't let the user send an illegal move

The client already knows which squares are occupied, and when the game
is won, so it's pointless to ever send a move we know is going to be
rejected. And in fact, we shouldn't even give the user a hover
indication as if they could move there.

That's all implemented in this commit. The hover highlight and the
pointer cursor are both disabled for squares that are already
occupied, and for all squares once the game is over.

3 years agoExpect defailed error message from the server when rejecting a move
Carl Worth [Wed, 3 Jun 2020 22:21:36 +0000 (15:21 -0700)]
Expect defailed error message from the server when rejecting a move

The server was recently augmented to not simply say 'false' for an
illegal move, but to instead say something like:

{"legal": false, "message": "Square already occupied"}

So we plumb the server-provided message out to the user in the case of
any illegal move.

3 years agoRename identifier in the "move" handler from 'square' to 'move'
Carl Worth [Mon, 1 Jun 2020 18:37:10 +0000 (11:37 -0700)]
Rename identifier in the "move" handler from 'square' to 'move'

This is not a functional change, but makes sense given the functional
rename from the previous commit.

3 years agotictactoe: Track API change that /move event now has data named "move"
Carl Worth [Mon, 1 Jun 2020 18:31:45 +0000 (11:31 -0700)]
tictactoe: Track API change that /move event now has data named "move"

And no longer named "square" as we had it before.

3 years agotictactoe: Adapt to new server event type: game-state
Carl Worth [Mon, 1 Jun 2020 17:52:19 +0000 (10:52 -0700)]
tictactoe: Adapt to new server event type: game-state

Previously, when a client joined a game in progress the server would
send all previous moves as "move" events (just the same as if a player
were making those moves live).

The server was recently changed to instead a single "game-state" event
in this case, (which also does contain the entire move history). So
when we receive that, we reset the game state, then replay the moves
from that history.

3 years agoempires: Rename "state" to "phase" for game phase transitions
Carl Worth [Mon, 1 Jun 2020 05:46:21 +0000 (22:46 -0700)]
empires: Rename "state" to "phase" for game phase transitions

We're freeing up the term "state" for a more generic, and more
complete description of game state.

3 years agotictactoe: Increase the size of the board a bit
Carl Worth [Wed, 27 May 2020 05:24:52 +0000 (22:24 -0700)]
tictactoe: Increase the size of the board a bit

This is a fixed size, not yet dynamic (and also not yet centered) but
it's something at least.

3 years agoChange styling to not put game info to the right of the board
Carl Worth [Wed, 27 May 2020 04:27:41 +0000 (21:27 -0700)]
Change styling to not put game info to the right of the board

Now that we don't have that huge list of buttons, it seems silly to
have the short status message off to the side.

3 years agoDrop the game history interface.
Carl Worth [Wed, 27 May 2020 04:20:22 +0000 (21:20 -0700)]
Drop the game history interface.

Not that it's bad to let the user go back and forth to see what
happened, but the interface here was particularly clunky, (both for
being rendered as a list of buttons and also for allowing the user to
fire off new moves wen viewing old history state).

This commit simply guts the rendering of the "moves" list. It doesn't
yet remove the jumpTo code that's now dead.

3 years agotictactoe: Implement a minimally-functional multi-player game
Carl Worth [Wed, 27 May 2020 04:13:49 +0000 (21:13 -0700)]
tictactoe: Implement a minimally-functional multi-player game

Now that there's a server implemented at lmno.games/tictactoe/LMNO/
it's a simple matter to break the call chain at handleClick() to
not do any state updates, but instead hit the /move API, then wait
for data to come back from the /events API and only when the server
returns with that, _then_ to update the state.

So, with multiple clients connected, each client will now seem the
game state updated with each move.

As far as the gameplay of Tic Tac Toe, the only major feature missing
is that players are not yet restricted to play as either X or O but
can instead send events for either player. Obviously, that won't be
hard to fix.

Then, as far as implementation, this code copies the add_message()
function from lmno.js, so we'll want to find a better way to do
that. And there may be some refactoring to be done for event handling
as well, (to reduce code duplication between game implementations).

But this code does use the fetch() API which does seem easier to use
than XMLHttpRequest so that's something we will probably want to
switch to in existing code.

3 years agoMakefile: Don't remove write permission from .js build artifacts
Carl Worth [Wed, 27 May 2020 04:05:03 +0000 (21:05 -0700)]
Makefile: Don't remove write permission from .js build artifacts

The intent behind this was to act as a clue to the developer that they
shouldn't edit the .js file, but it caused a problem that subsequent
build would fail because the output files were read-only. So we give
up on this idea.

3 years agotictactoe: Put in place the standard top-level page
Carl Worth [Tue, 26 May 2020 03:45:58 +0000 (20:45 -0700)]
tictactoe: Put in place the standard top-level page

Specifically, one which allows for hosting a new game, (using the
generic lmno_new function). Meanwhile, the game-specific page is moved
to tictactoe/game.html.

3 years agotictactoe: Integrate the standard LMNO styling
Carl Worth [Tue, 26 May 2020 03:02:12 +0000 (20:02 -0700)]
tictactoe: Integrate the standard LMNO styling

Include the LMNO CSS files and add a header. The LMNO button styling
looks better here than I expected. Just required a couple of padding
tweaks to get things looking correct.

3 years agoMakefile: Change permissions on generated .js files to be read-only
Carl Worth [Tue, 26 May 2020 00:50:54 +0000 (17:50 -0700)]
Makefile: Change permissions on generated .js files to be read-only

This is a hint to the developer that they shouldn't be eidting these
files, (but instead, should be editing the corresponding .jsx file).

3 years agoCorrect various meta viewport tags
Carl Worth [Tue, 26 May 2020 00:13:11 +0000 (17:13 -0700)]
Correct various meta viewport tags

I don't know where this cargo cult started, but the semicolon
separator was just wrong, (should be a comma), and the
maximum-scale=1.0 and user-scalable=0 were really just rude, (if a
user needs to/wants to zoom in on a page for accessibility purposes,
who are we to say they can't or shouldn't?).

3 years agoProvide any downloaded deps/*.js files to git clone during deployment
Carl Worth [Mon, 25 May 2020 23:55:52 +0000 (16:55 -0700)]
Provide any downloaded deps/*.js files to git clone during deployment

This is simply so that the deploy process doesn't need to download
anything that we might already have downloaded. We do explicitly call
"make deps" still to force verification of the checksums of the .js
files (even though we didn't just download them). This ensures that
these resource (which aren't otherwise tracked in git) haven't been

3 years agoTeach git to ignore tictactoe.js
Carl Worth [Mon, 25 May 2020 23:53:43 +0000 (16:53 -0700)]
Teach git to ignore tictactoe.js

We only want to commit source files to git, not the results of the

3 years agoRework Makefile to force sha512 verification of downloaded files
Carl Worth [Mon, 25 May 2020 21:20:38 +0000 (14:20 -0700)]
Rework Makefile to force sha512 verification of downloaded files

We had sha512 checksums here, but no automation was happening for the
verification, (instead there was only a "make checksums" file that
would have to be called manually).

We rework things here so that the checksum is verified on every file
that is downloaded. The rework simplifies the recipe for
download/verification to a single recipe for all dependencies (rather
than 4 recipes with a lot of duplicated logic).

The "make checksums" target is also renamed to "make deps" since it
can be used to force the downloading of all dependencies, (and it is
given the .PHONY treatment so that it always performs checksum
verification even if there is nothing new to download).

3 years agoAdd a simple tictactoe game, implemented with React
Carl Worth [Mon, 25 May 2020 20:37:10 +0000 (13:37 -0700)]
Add a simple tictactoe game, implemented with React

This isn't a proper LMNO game, (it's not networked at all), but it's a
starting point for seeing how we might structure a React-based client
(and we can develop this into a proper LMNO game).

In fact, the source code here came directly from the React tutorial


Note that I've not pulled in the 1000+ npm modules that would have
come from using create-react-app as recommended in that tutorial. As
can be seen here, by example, none of them are needed. The only build
tool requireed is something to compile JSX and we've got that working
via the Debian-provided babel packages (as seen in the most recent
commits here).

3 years agoMake the build quieter by default
Carl Worth [Mon, 25 May 2020 20:27:28 +0000 (13:27 -0700)]
Make the build quieter by default

Just a simple change to keep the output of make very tidy.

If the user wants to see the complete command output they can use
"make V=1" for that, (and this support is documented in the default

3 years agoMakefile: Add support to use babel to compile React code using JSX
Carl Worth [Mon, 25 May 2020 19:18:42 +0000 (12:18 -0700)]
Makefile: Add support to use babel to compile React code using JSX

This is in preparation for starting to use React to implement LMNO
game clients.

In this commit, the previous "make dev" target is now simply "make",
and the previous "make prod" target is now "make LMNO_BUILD=production".
This latter command is definitely annoying to remember, but should
almost never need to be executed manually; instead the developer will
likely invoke "make deploy" which knows how to do a production build.

3 years agoExtend Makefile with "deps", "dev", and "prod" targets
Carl Worth [Mon, 25 May 2020 10:46:08 +0000 (03:46 -0700)]
Extend Makefile with "deps", "dev", and "prod" targets

The "make deps" target downloads 3rd-party JavaScript resources that
are used by the site, (currently React and React-Dom). The "make dev"
installs the development versions locally while "made prod" installs
the production versions.

All three targets verify the integrity of the downloaded files via
SHA512 sums that are added in this commit.

And all three targets are documented in the README file added in this

3 years agoClose out li and ul tags
Carl Worth [Sun, 24 May 2020 17:57:11 +0000 (10:57 -0700)]
Close out li and ul tags

Apparently I never quite finished typing out this page. It's amazing
to me that broswers are as forgiving as they are when fed total

3 years agoFix padding calculations for intermediate widths
Carl Worth [Sun, 24 May 2020 15:43:13 +0000 (08:43 -0700)]
Fix padding calculations for intermediate widths

I just noticed that at some intermediate browser widths the page
padding was entirely missing. Fortunately, "git bisect" was very
useful and pointed me to the exact problematic commit:


In that commit we were trying to move the range of media block from
620:720 to instead be 720:820 (to account for the change in the
box-sizing parameter now including 100 units of padding).

But that commit was botched in a couple of ways, (applying from
620:820 and also miscalculating everything within that range).

This commit corrects things and is verified to act as desired when
applied to the broken commit mentioned above and when applied at the
current point in the code history.

3 years agoAdd handling for a spectators list in addition to the players list
Carl Worth [Sun, 24 May 2020 15:27:09 +0000 (08:27 -0700)]
Add handling for a spectators list in addition to the players list

The model is that when people initially join the game, (providing a
name for themselves), they are a spectator. They then move from the
spectator list to the player list when then they choose a character

The server isn't very clever about this. It has distinct endpoints for
adding/removing players and adding/removing spectators. So in this
code we have to explicitly remove ourselves as a spectator when we add
ourselves as a player.

3 years agoempires: Construct reliable paths for all game API endpoints
Carl Worth [Sun, 24 May 2020 15:06:11 +0000 (08:06 -0700)]
empires: Construct reliable paths for all game API endpoints

By appending to window.location we can ensure that we're always
hitting an endpoint one level below the game ID, (and not replacing
the game ID), regardless of whether the current path ends in a
trailing slash or not.