Connections strategy

I’ve been thinking a lot about the NY Times Connections game lately, mainly because my family keeps playing it wrong. They’d get mad at me if I told them that, so I’m telling you.

Unplayed Connections game

As I’ve said before, Connections is an obvious rip-off of the Connecting Wall segment of the BBC game show Only Connect. The main differences, apart from the Connecting Wall being much, much harder, are

These rule differences mean game play is different. In the early stages of the Connecting Wall, rapid guesses are a common way to eliminate red herrings. If there are five clues that could fit into a category, you can eliminate the red herring in no more than five quick guesses,1 and that’s a good strategy for figuring out groups. It’s after the first two groups are set that teams tend to take a more methodical approach to conserve wrong guesses.

In Connections, at least the way I think it should be played, the goal is not simply to get all four groups (I’ve never failed to do that) but to get them with no mistakes. Texting a four-row solution to your group of fellow players is the ideal. Just guessing from the start—as some people I know do—is an almost certain way to get less than a perfect score.

Connections score in Messages

So unless I’m in a hurry or have given up, I don’t start submitting guesses until I’m sure of at least three, and ideally all four, of the categories. This strategy means I almost always get a better score than my hasty wife and kids, and the additional need to keep track of all the categories in my head is another weapon in the fight against cognitive decline.2

By the way, if you’re outside the UK and would like to see Only Connect, the wheelsongenius YouTube account uploads episodes shortly after they air. The show is currently in Series 19, and wheelsongenius has playlists for several of the older series.

  1. Combinatorics can work against you. If there are six clues that could fit in a category, it could take as many as 15 guesses to get through all the combinations. Keeping track of which two you’ve kept out of your previous guesses is basically impossible, even for the kind of quizzing champions that appear on Only Connect

  2. I’m skeptical of the claim that doing puzzles and other brainwork can ward off the effects of aging, but it can’t hurt. 

A shell script for blank calendars

Generally speaking, I dislike writing shell scripts. The operators are cryptic (yes, I’ve enjoyed writing Perl), whitespace matters way more than it should (yes, I’ve enjoyed writing Python), and I just always feel I’m one step away from disaster. A lot of my scripts start out as shell scripts but get changed into Perl or Python once they get more than a few lines long. The script we’ll discuss below is an exception.

I wanted a script to help me print out blank monthly calendars. The program I’ve always used for this is pcal, which is pretty easy to use. For example,

pcal -e -S 10 2023 3

will create a three monthly calendars starting with this coming October. The -e option tell pcal to make empty calendars,1 and the -S tells it not to include mini-calendars for the preceding and succeeding months.2 The result looks like this:

Blank October calendar

The thing about pcal is that the p stands for PostScript, a great file format but one that’s been superseded3 by PDF. So to get pcal’s output into a more modern format, I pipe its output to ps2pdf:

pcal -e -S 10 2023 3 | ps2pdf - -

The first hyphen tells ps2pdf to get the PostScript from standard input and the second hyphen tells it to write the resulting PDF to standard output. Of course, I really don’t want the PDF code spewing out into my Terminal, so I use Apple’s very handy open command to pipe it into Preview:

pcal -e -S 10 2023 3 | ps2pdf -  - | open -f -a Preview

The -f option tells open to take what being piped in through standard input and the -a Preview tells it to open that content in the Preview application.

This isn’t the most complicated command pipeline in the world, but I have trouble remembering both the -S option and the order of the month, year, and count arguments. So I decided to whip up a quick little shell script to replace my faulty memory.

You should know first that my main use of this command is to print a few upcoming months for my wife. She’s always preferred paper calendars but decided last December that 2023 would be different, so I didn’t get a 2023 calendar for her for Christmas. Partway through the year, she changed her mind. There’s a lot less selection for calendars in spring, and it would kill her to waste money on a full year when she’d only use eight months, so she asked me to print her a few months at a time.

My first thought was to make a script that takes just two arguments: the starting month and the number of months—I could have the script figure out the year. That thinking led to this simple script, which I called bcal:

1:  #!/usr/bin/env bash
3:  y=$(date +%Y)
4:  pcal -e -S $1 $y $2 | ps2pdf -  - | open -f -a Preview

This worked fine, but you’ve probably already seen the problem. What happens at the end of the year, when it’s December and she wants calendars for the first few months of the following year?

I could use date to get the current month, date +%m, and if it’s 12, add one to $y. But what if I wanted to print out the upcoming January calendar in November? Instead of trying to have the program guess what I wanted, it seemed better for me to tell it what I wanted. That meant adding an option to bcal to let me tell it I wanted next year instead of this year.

At this point, I was tempted to give up on bash and move to Python. I know how to handle options, dates, and external calls in Python, so the switch would have been fairly easy. But I had an itch to learn how to do options in bash. Couldn’t be too hard, could it?

It wasn’t. The key command is getopts, and it’s easy to find examples of its use. And once I had getopts working, I expanded the script to add a help/usage message and one bit of error handling. Here’s the final version of bcal:

 1:  #!/usr/bin/env bash
 3:  # Make PDF file with blank calendar starting on month of first argument
 4:  # and continuing for second argument months
 6:  usage="Usage: bcal [-n] m c
 7:  Arguments:
 8:    m  starting month number (defaults to this year)
 9:    c  count of months to print
10:  Option:
11:    -n  use next year instead of this year"
13:  # Current year
14:  y=$(date +%Y)
16:  # If user asks for next year (-n), add one to the year
17:  while getopts "nh" opt; do
18:    case ${opt} in
19:      n) y=$((y + 1));;
20:      h) echo "$usage"; exit 0;;
21:      ?) echo "$usage"; exit 1;;
22:    esac
23:  done
25:  # Skip over any options to the required arguments
26:  shift $(($OPTIND - 1))
28:  # Exit with usage message if there aren't two arguments
29:  if (($# < 2)); then
30:    echo "Needs two arguments"
31:    echo "$usage"
32:    exit 1
33:  fi
35:  # Make the calendar, convert to PDF, and open in Preview
36:  pcal -e -S $1 $y $2 | ps2pdf -  - | open -f -a Preview

Lines 17–23 handle the options. I decided on -n as the option for “next year” and you can see in the case statement that giving that option adds one to the current year. Any other options lead to the usage message and a halt to the script.

Line 26 uses shift to skip over the options to the required arguments. $OPTIND is the option index, which gets increased by one with each option processed by getopts, so this command makes $1 point to the month and $2 point to the count, just as if there were no options.

The error handling in Lines 29–33 is limited to just making sure there are two required arguments. If the arguments are letters or negative numbers, the script will continue through this section and fail in a clumsy way. I’m not especially worried about that because this is a script for me, and I’m unlikely to invoke it as bcal hello world.

Anyway, now I can get the next three months with

bcal 10 3

and the first two months of next year with

bcal -n 1 2

When Preview opens, it shows me a temporary file.

Calendar in Preview

Usually I just print it out and the temporary file is deleted when I quit Preview. This is the nice thing about piping into open: the script doesn’t create any files that I have to clean up later. But I can save the file if I think there’s a need to.

I should mention that pcal can be installed through Homebrew, and ps2pdf is typically installed as part of the Ghostscript suite, which is also in Homebrew.

Now that I kind of know how to use getopts, I’ll probably extend my shell scripts before bailing out to Perl or Python. I’m not sure that’s a good thing.

  1. By default, pcal looks in your home directory for a file named .calendar and parses it to print entries on the appropriate days. Back when I was a Linux user, this was how I kept track of my calendar. Whenever I added a new entry, I’d print out an updated calendar on the back of a sheet I pulled out of the recycling bin. It worked pretty well in those pre-smartphone days. 

  2. English has more spelling anomalies than there are stars in the sky, but right now the one that’s bothering me the most is that succeeding has a doubled E and preceding doesn’t. 

  3. No doubled E! 

Simple drawings with Mathematica

A couple of days ago, I wrote a post that included this image:

iPhone cuboid with axes

Because I don’t have a 3D drawing app, I did it in Mathematica. And because I’m new to Mathematica, I fumbled around a bit before figuring out what to do. I decided to write up what I learned so I could refer to it later, and I decided to post it here in case it’s of any value to anyone else.

The key function when creating 3D images (that aren’t plots) is Graphics3D. As you can see from the linked documentation, it can take an enormous number of arguments and options. The main argument is a list of the objects to be drawn, which in the drawing above consisted of the boxy representation of an iPhone and three arrows representing the x, y, and z axes (I added the axis labels “by hand” in Acorn).

One of the first things I learned was to create the objects separately instead of trying to build them within the call to Graphics3D. It’s certainly possible to make this image entirely within Graphics3D, but the function call becomes really long and confusing if you do it that way. I started by defining variables with the dimensions of the phone (in millimeters):

b = 71.5
h = 147.5
t = 7.85

In case you’re wondering, b is commonly used in my field for the width of objects—it’s short for breadth. We avoid w because we like to use it for weight.

The boxy iPhone is defined using the Cuboid function:

phone = Cuboid[{-b/2, -h/2, -t/2}, {b/2, h/2, t/2}]

The two arguments are its opposite corners.

In theory, I could use Mathematica’s own knowledge of its coordinate system to draw the axes, but it defaults to drawing axes along the edges of a box that encloses the object, and I didn’t find any handy examples of overriding that default. It was easier to define the axes using the Arrow function:

xaxis = Arrow[{{0, 0, 0}, {b/2 + 25, 0, 0}}]
yaxis = Arrow[{{0, 0, 0}, {0, h/2 + 25, 0}}]
zaxis = Arrow[{{0, 0, 0}, {0, 0, t/2 + 25}}]

The argument to Arrow is a list of two points: the “from” point and the “to” point. As you can see, each arrow starts at the origin (which is the center of the phone) and extends in the appropriate direction 25 mm past the edge of the phone. Why 25 mm? It looked about right when I tried it.

With the objects defined, I called Graphics3D to draw them:

Graphics3D[{Gray, phone, Black, Thick, xaxis, yaxis, zaxis},
Boxed -> False, ImageSize -> Large]

(I’ve split the command into two lines here to make it easier to read, and I’ll do the same from now on.)

As you can see, the list of objects that makes up the first argument is interspersed with directives on how those objects are to be drawn. The first directive, Gray, applies that color to phone. Then Black overrides Gray and is applied to the three axes that follow. I added the Thick directive before the axes when I saw that they looked too spindly by default.

The Boxed->False option stops Mathematica from its default of including a wireframe bounding box in the image. ImageSize->Large does what you think—it makes the image bigger than it otherwise would be.

Here’s what Mathematica displays:

iPhone in default orientation

Mathematica obviously thinks the z direction should be pointing up. This makes sense, but it isn’t what I wanted. The notebook interface allows you “grab” the image and rotate it into any orientation, so that’s what I did, putting it into the position you see at the top of the post. Then I right-clicked on the image and selected Save Graphic As… from the contextual menu. I opened the resulting image file in Acorn, added the axis labels, and uploaded the result to my web server.

After publishing the post, I returned to Mathematica to see if I could get it to clean a few things up. First, I wasn’t happy with the brownish color that appeared on certain edges, depending on the orientation. That was cleared up with the Lighting->Neutral option. Then I wanted programmatic control over the orientation, which I got via ViewPoint->{-50, 30, 75}, which sets the location of the virtual camera, and ViewVertical->{.1, 1, 0}, which rotates the camera about the axis of its lens until the given vector is pointing up in the image.

Finally, I wanted to add the axis labels in Mathematica instead of relying on another program. This meant adding Text objects to the argument list, one for each axis. The final call to Graphics3D looked like this:

Graphics3D[{GrayLevel[.5], phone,
Black, Thick, xaxis, yaxis, zaxis, 
FontSize -> 16,
Text["x", {b/2 + 25, -7, 0}], 
Text["y", {-7, h/2 + 25, 0}],
Text["z", {-5, -5, t/2 + 25}]}, 
Boxed -> False, ImageSize -> Large,
ViewPoint -> {-50, 30, 75}, ViewVertical -> {.1, 1, 0},
Lighting -> "Neutral"]

Each Text object includes both the text and the point at which it is to be displayed. The Text items are preceded by a FontSize directive to make them big enough to see clearly. The Black directive earlier in the list was still in effect, so the text color was black.

Here’s the result:

iPhone cuboid with axes

As you can see, I’ve made the image more upright, and the neutral lighting has gotten rid of the weird brownish and bluish casts of the original. You may also note that I changed the original Gray directive to GrayLevel[.5]. This made no difference in the final output, but the GrayLevel argument did let me play around with different shades of gray before deciding that the 50% provided by Gray was just fine.

I still have a long way to go with Mathematica, but I’m making progress.

Testing MathML

As I mentioned on Mastodon yesterday, I expect to be be including more equations in future posts, and I’d like the equations to appear readable in my RSS feed. This is a test to see if MathML will work.

I’ve been using MathJax (and its predecessor, jsMath) for many years, and it works quite well here on the blog itself, but because it formats the equations via JavaScript, the equations aren’t formatted in the RSS feed. The RSS feed just shows the LaTeX code for each equation—not bad for short equations, but increasingly hard to read as the equations get longer. If you’re an RSS subscriber, you’ve noticed that the following disclaimer appears at the bottom of each article in the feed:

If there are equations in this post, you will see them rendered properly in the original article.

where “the original article” is a link to the blog, where MathJax can do its magic.

So I’m thinking about ways to get the equations to look right in RSS readers. One obvious way is to render them as images, upload them, and insert <img> tags at the appropriate spots,1 but this seems crude and very Web 1.0. Although I suppose I could render the equations as SVGs, which would allow users to zoom in without seeing jaggies.

MathML is the “right” way to do equations and is supported by all the browsers I can think of, so the math should look right for everyone who visits the blog directly.2 The question is whether it’ll be rendered properly in RSS readers. My guess is that it will be, since I believe that RSS readers use the same rendering engines used by browsers. But the only way to know for sure is to write a post with MathML and see how it looks. So here goes:

The general formula for the mass moment of inertia about the x-axis, Ixx, is


This can be specialized for certain geometries. For example, the moment of inertia of a thin rod about an axis through the rod’s center and perpendicular to it is


Finally, for Dan Moren, the parallel axis theorem is


where IxxC is the moment of inertia about an axis through the centroid of the body and IxxP is the moment of inertia about a parallel axis a distance d from the centroid.

After I publish this post, I’ll check my RSS feed in NetNewsWire and update the post with a note on how the equations looked.

Update 14 Sep 2023 10:54 AM
As I hoped, NetNewWire shows the equations rendered properly (apart from some baseline misalignment for the inline math) in my RSS feed. I’m interested in hearing how other feedreaders perform.

  1. Although I use Markdown, I prefer <img> tags to the ! syntax. 

  2. Safari, unfortunately, has the worst MathML renderer of the browsers I’ve tested. What it shows is certainly readable, but the baseline is inconsistent, making the equations look a bit tipsy.