As a kid growing up in South-West Louisiana, my family spent a few weeks every winter in West Texas camping and hunting deer. A regular occurrence of these trips was eating at Cracker Barrel.
Having spent the whole morning sitting in the woods alone and missing my N64, I got obsessed with the “jump all but one” game present on every table.
The the game begins by placing a tee in every hole except one (of your choice). You then “jump” the tees (similar to checkers)
until no jumps can be made. The goal is to leave just one tee. The more tees you leave on the board, the more
“ignorant” you are (as the rules state). Given that we went there so often, I was able to work out a solution and memorized it. I liked challenging
myself every following year to see if I could remember the solution (or resynthesize it).
I went back to Cracker Barrel recently for the first time in 15 years. The game was still there.
I gave solving it a shot but left 2 tees on the board. While I was playing, a lot of questions were going through my head. Stuff like:
Out of all possible games, how are they distributed? Is leaving one tee really that rare? It almost seemed harder to leave more than 4.
Does it matter where you leave the first hole?
How hard is it for the last tee to land in the hole you started with? (something I could do as a kid)
I realized that there probably aren’t that many possible games
and we should be able to brute force some of these answers by simulating the game and enumerating every possible
move. Perhaps there are purely analytical answers to these questions, but I’m personally able to express this much more easily in code than in math.
Creating a notation
For some reason, I got the itch to start this while I was in a cabin in Mississippi without my computer.
So the first thing I did was write down a notation and a set of legal moves on a bookmark and I snapped a pic of it with my phone.
I chose a notation similar to chess (rank and file). The common board orientation will
be with one of the tips of the triangle pointing at you. So each row will be labeled going up (A, B, C, D, E)
and each column (1,2,3,4,5).
Because we will be storing the positions in a 2D list,
we need a way to store positions and convert them to and from their cartesian point system and
their chess-like notation.
Example use:
The Game object will then be constructed with an open_position (the hole you are leaving open).
There will be a _board variable which contains the 2D list of Holes which are either filled or not.
Example use. The game pretty-prints an ASCII board:
We now need a way to encode the rules of the game, and a way to get from one game state to another.
First let’s describe the directions which a piece may possibly move as an Enum:
We can encode a “move” in the game as an object with 2 positions:
Even though there are 6 directions a peg may move, certain holes limit which direction a peg can
move. For instance, from the tip of the pyramid, only 2 directions are possible.
Instead of calculating this during the runtime of the game, I decided to encode all possible “jumps”
into each hole.
Now we need a way to calculate which moves are valid and the ability to make them:
This should be enough to play the game:
Now that we can play a game, we need some code to play every possible game. We’ll do this by doing a
depth-first search through every move. At each “branchng” in this tree of moves, we’ll clone the game state
and the moves we made so far so we can save all the games in memory.
I’ve decided to call this thing that plays all possible games a “Session” due to lack of creative energy:
You run the session like so:
And now sess.log contains all possible games.
So it appears there are 568630 possible games that start with this configuration.
What about the distribution of scores?
In number of tees remaining:
29760 (5.2% of games)
139614 (24.5% of games)
259578 (45.6% of games)
123664 (21.7% of games)
14844 (2.6% of games)
844 (0.1% of games)
326
What’s pretty interesting is that there are 2 games that end in 8:
Here are the moves to achieve those game states:
We now have a framework for analyzing the game. Below is the full code (it’s meant to be run in a Jupyter notebook):