How many pieces do you really need for a calendar puzzle?
A few weeks ago, in a shop here in China, I picked up a puzzle off the shelf. It took me a minute to work out how it played, because the instructions were in Chinese, but the idea became clear: twelve months labelled around the top of a board, days one through thirty-one below, and eight polyomino pieces in a bag. You leave today’s month and today’s day uncovered, and cover the rest of the board exactly once with the pieces. One puzzle for every day of the year.
Coming home and searching for it, it appears to be a clone of A-Puzzle-A-Day by DragonFjord. The board is 43 cells in a 7×7 grid with a chunk missing:
Jan Feb Mar Apr May Jun
Jul Aug Sep Oct Nov Dec
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Each of the 366 dates — Feb 29 included — marks two cells as uncovered, leaving 41 to be tiled by the eight pieces (seven pentominoes and one 2×3 hexomino). Pieces may be rotated and reflected.
It seems like a nice puzzle, but I immediately started thinking: which sets of pieces could solve this puzzle? Could I get away with only seven pieces? Is the set of eight pieces unique? How hard is the puzzle? That wondering got out of control, and turned into this post.
All the code lives at github.com/chrisjefferson/calendar-puzzle — CP-SAT solvers, a Rust difficulty-measuring backtracker, search scripts, and the generated data that feeds the widget at the bottom of this page.
What sets of pieces are allowed?
Given 31 days and 12 months, two uncovered, we need to cover 41 cells. The commercial version has seven pentominoes plus a 2×3 hexomino. The puzzle allows you to rotate and reflect. But there are a number of interesting questions we can ask:
- Can we do it in seven? The average piece size would be about 5.86 — so you’d be looking at mostly hexominoes and maybe a heptomino. Geometrically that’s much more constrained: a big piece has few valid placements, so covering 366 different date patterns with only seven pieces means every piece has to be remarkably flexible.
- Are there other eight-piece designs? If so, are some easier than the commercial one? Harder? Is DragonFjord’s choice near the average for puzzle difficulty, or at one of the extremes?
- Can the puzzle tell you when a date is impossible? A well-designed calendar puzzle would fail on Feb 30, Apr 31, and the other four dates that aren’t real — giving the user unambiguous feedback that they’ve picked nonsense. The commercial puzzle does not; it happily tiles Feb 30. Can we design one that does?
I’ll take these in order. First a false start.
A detour: adding AM/PM
My first impulse was to put my own twist on the puzzle. How about I make it so you get two puzzles a day? One for AM and one for PM. There is even a natural place to put this, as two rows of six months leaves two naturally empty squares at the right-hand end of the month rows — perfect for AM and PM labels. 45 cells now, three uncovered per target (month, AM/PM, day), giving 732 targets.
I wrote a CP-SAT tiler, built a monomino-merging generator (start with 45 single-cell pieces; repeatedly merge adjacent pieces; only accept merges that preserve solvability on all 732 targets), and let it run overnight.
The generator reliably reached 15–18 pieces and stopped. Every candidate merge broke at least one target. This turned out to be the board’s fault, not the search’s.
The structural problem. Consider the target “June, PM, day-anything”. June is the cell at row 0, column 5. PM is the cell at row 1, column 6. The AM cell sits at row 0, column 6 — directly above PM and directly to the right of June. When both June and PM are uncovered, AM has no on-board neighbours: the cell above is off the board, the cell to its right is off the board, and its only two on-board neighbours are uncovered. It’s a single cell, stranded.
An isolated cell can only be covered by a monomino. So any piece set that solves every AM/PM target must contain at least one monomino. That’s a feature of the board, independent of how clever your search is. A puzzle with a mandatory single-square piece is much less elegant than one without.
(There’s a second issue, which I’ll mention briefly because it’s pretty: parity. Colour the grid like a chessboard — 23 cells of one colour, 22 of the other. Every tetromino covers exactly two of each, and two dominoes cover 2+2. So a piece set made entirely of tetrominoes and dominoes is parity-balanced, which means it can only tile date configurations whose three uncovered cells split 2+1 by colour. About half the dates split 3+0 or 0+3, and for those no balanced set will ever work. This isn’t fatal on its own — you can include unbalanced pieces — but combined with the isolation issue it made me want a cleaner board.)
I dropped AM/PM and went back to the 43-cell board. Everything from here on is on the 43-cell version.
Searching for piece sets: try one (merge)
Same approach, smaller board. Start with 41 monominoes. Repeatedly pick two pieces, merge them, accept the merge if the new piece set still solves all 366 targets.
CP-SAT per target averages about 18ms at high piece counts, so a solvability check across all 366 targets takes seven seconds. That’s tolerable when you’re still merging freely early on. Once you get past about fifteen pieces most merges are rejected, and the generator spends almost all its time verifying states that don’t move.
Result: reliably reaches 15–18 pieces, then stops. Every merge proposes a new shape, and every new shape breaks at least one of the 366 targets.
What goes wrong? Merging two pieces doesn’t give us enough room to explore. Once you have lots of pieces of size 2 and 3, there aren’t that many merge choices, and most of them produce an awkward shape that fails some date. This should be able to produce any solution if we ran it for long enough — the moves are reversible in principle — but it just gets stuck too often.
Try two (shrink)
Second idea: don’t start small, start good. Seven one-sided tetrominoes, three triominoes, and an extra I-tetromino. Eleven pieces, 41 cells. I checked with CP-SAT that this set solves all 366 targets using rotation alone — no reflection needed.
Now shrink it. At each step: pick a piece of minimum size, remove one cell (chosen so the piece stays connected), then attach that cell to some other piece (extend any other piece by one adjacent cell). If the new set still solves all 366, accept. A piece that shrinks to a single cell and then has that cell taken disappears entirely — that’s how piece count decreases.
Pure local search, no backtracking, no restarts.
With rotation only, across 100 seeds running 1000 moves each: 59 reached 9 pieces, 41 stuck at 10. With reflection enabled, across 30 seeds: 21 reached 8, the rest 9 or 10. Encouraging — we match DragonFjord’s count.
Except: every single terminal state contains a trapped monomino. Typical endings:
[1, 4, 5, 5, 5, 6, 7, 8][1, 4, 5, 5, 6, 6, 7, 7][1, 5, 5, 5, 6, 6, 6, 7]
Eight pieces, one of which is a single cell. I tried adding a brute-force final polish that tests every way of extending every other piece by the monomino’s cell. Zero successes across all 30 reflection-enabled runs. At the terminal state, there is simply no single-cell move that absorbs the monomino and keeps all 366 targets solvable.
The monomino is doing real work — it’s a flexible filler that handles whichever awkward cell the current piece shapes fail to cover for some date. But it’s ugly, and an “eight-piece solution with a monomino” is really a nine-piece solution dressed up.
Try three (grow, with the piece count fixed)
Both previous approaches drift in piece count during the search. The merging generator drifts downward and stalls; the shrinking generator drifts down to 8 or 9 and lands with a monomino. What if we fix the piece count from the start and force the search to build a solution with exactly that many pieces?
Start state: eight monomino placeholders at random cells. Total covered: 8. Target: 41. Three move types:
- Grow: pick a piece (smallest first), add an adjacent on-board cell. Total goes up by 1.
- Rebalance: move a cell from a larger piece to a smaller one. Keeps the donor piece connected. Total unchanged; the shapes reshuffle.
- Shuffle: when the search stalls, knock a cell off several pieces at once and let them regrow. The “knock off” count ramps up the longer we stay stuck.
Accept any move that keeps the set solvable on all 366 targets. While the piece shapes are still growing and total < 41, we let the CP-SAT solver assume there are 41 − total invisible monomino fillers available — each covers one arbitrary cell. This lets us check solvability mid-search, before the real pieces are large enough to cover the board on their own. When total reaches 41 the fillers vanish and we have a genuine 8-piece solution.
The piece count never changes during the search. Either we reach total = 41 with eight real pieces, or we stall below it. No trapped monomino is possible by construction: it would mean total < 41 at the end, which means failure.
Results
A hundred seeds, eight parallel workers, roughly 8.5 hours of wall time.
| Outcome | Count |
|---|---|
| Reached total = 41 (a genuine 8-piece solution) | 81 / 100 |
| Stalled at total = 40 (one invisible-monomino short) | 19 / 100 |
81 successes, all verified against all 366 targets. And of those 81, 80 are distinct — two seeds happened to converge to the same canonical piece set. I canonicalised each piece to the lexicographically smallest shape under all 8 rotations and reflections, then sorted the list within each set.
The size distributions are surprisingly constrained. Only three patterns appear:
| Count | Sizes | Note |
|---|---|---|
| 67 | [5, 5, 5, 5, 5, 5, 5, 6] |
DragonFjord structure |
| 10 | [4, 5, 5, 5, 5, 5, 6, 6] |
— |
| 4 | [4, 5, 5, 5, 5, 5, 5, 7] |
— |
Eighty-three per cent of our successes hit the commercial structure. Given how different the search is from whatever DragonFjord used, that’s a strong convergence result: “seven pentominoes and one hexomino” isn’t just a choice, it’s the most natural size distribution for the problem. But within that size profile there’s real variety — 67 distinct shape choices, none of which is the commercial set (the commercial pieces are L, U, V, P, Y, N, S plus a 2×3, and none of our 67 hits that exact collection).
Timing per seed: 26 to 73 minutes, median 49.
Seven pieces?
With 81 eight-piece sets to hand I finally went after the real question. For seven pieces summing to 41, the average size is 41/7 ≈ 5.86. You’d need most pieces to be hexominoes with at least one heptomino, or something like six pentominoes plus an undecomino (11-cell piece).
Big pieces are a problem. Every date picks two cells to exclude, and a big piece has to avoid both of them in some placement. With 366 different exclusion patterns the piece has to be shaped so that no matter which two cells are blocked, it can still be placed somewhere — and the bigger the piece, the fewer orientations and anchors remain to hide it. That’s a tough ask.
The CP-SAT formulation
I wrote a direct CP-SAT model asking “does there exist a 7-piece set that solves all 366 dates?”. The variables:
- Shape variables per piece — a 7×7 binary grid saying which cells the piece occupies in its canonical orientation.
- Placement variables per date, piece, orientation, and anchor.
- Coverage auxiliaries linking placements to the actual board cells they cover.
- A connectivity constraint per piece (rooted-tree encoding with distance labels) to forbid disconnected shapes.
- Symmetry breaking by ordering pieces by size.
The full model for all 366 dates has roughly 4 million mutex constraints and over 100,000 placement booleans. That’s at the edge of what CP-SAT handles comfortably, and the search didn’t terminate in any reasonable time.
The cheat
Before scaling up to all 366 dates, we start by trying to solve a subset — just a handful — to get a feel for how the model behaves and what kind of solutions it finds.
Without an upper bound on piece size, CP-SAT finds “solutions” in minutes — but they’re degenerate. A 7-piece solution of shape [1, 1, 1, 1, 1, 1, 35] is trivially feasible on any single date: the 35-cell piece picks up most of the board, and the six monominoes mop up the remaining cells. Of course we then have to check whether the 35-cell piece works on all 366 dates, and it doesn’t — the one CP-SAT found happened to fit only 24 dates.
This is a real concern: any 7-piece solution that leans on one huge piece plus five or six monominoes is “solving” the puzzle in a lawyer-y way. We want to know the biggest a single piece can possibly be and still cover its own cells across all 366 date patterns.
The biggest possible single piece
Here’s a cleaner question. Is there a connected polyomino of size K such that, for every date, some rotated/reflected placement covers K cells of that date’s to-cover region?
If yes for K, then [1, 1, 1, 1, 1, 1, 41−K] is a candidate 7-piece layout — six monominoes plus one K-piece — provided 41 − K ≤ 6, i.e. K ≥ 35. If no for K, then no 7-piece solution can contain a piece of size K or larger, because even on its own it fails on some date, and extra pieces can only make things worse.
Binary-searching K with CP-SAT on all 366 dates:
- K = 22: feasible.
- K = 23: infeasible.
The feasible 22-cell polyomino:
#.###..
##.##..
#####..
#..#...
###....
####...
.......
So in any 7-piece solution, no piece can exceed 22 cells. That rules out the [1, 1, 1, 1, 1, 1, 35] cheat — it also rules out cheats like [1, 1, 1, 1, 1, 5, 31] or [1, 1, 1, 1, 4, 10, 23]. All seven pieces have to be 22 cells or fewer. We’ve bounded the search space considerably.
But it didn’t help enough
With the size bound in place, I ran a sequence of progressively harder CP-SAT searches:
| max piece | # dates | status | wall time |
|---|---|---|---|
| 22 | 2 | SAT: [1, 1, 2, 2, 2, 11, 22] |
20s |
| 22 | 3 | SAT: [1, 1, 1, 1, 10, 13, 14] |
14s |
| 22 | 5 | UNKNOWN | 2 min |
| 10 | 5 | UNKNOWN | 2 min |
| 10 | 10 | UNKNOWN | 3 min |
| 10 | 15 | UNKNOWN | 1 hour |
The two-date and three-date solutions are still cheat-y — heavy on monominoes — because CP-SAT can afford to let a tiny handful of dates be satisfied by a single-use big piece and a bunch of fillers. Tightening max_piece to 10 kills that slack, but then the solver has to commit to pieces that genuinely generalise, and it can’t do it within an hour even for 15 dates. An 8-hour overnight run with different formulations got nowhere.
I gave up on the CP-SAT attack. This doesn’t prove anything — the natural CP-SAT encoding being intractable isn’t a proof of non-existence, just a failure of one approach. My gut tells me no 7-piece solution exists, but I absolutely can’t be sure, and I have no idea how to prove it doesn’t. If you want a clean open question: does there exist a piece set of seven connected polyominoes, all rotatable and reflectable, summing to 41 cells, that tiles the 43-cell calendar board leaving any given (month, day) pair uncovered, across all 366 valid dates? I don’t have the answer.
How hard are the 81 sets?
Back to the eight-piece sets. CP-SAT tells us “is this solvable?” but not “how hard is it for a person?”. For that I wrote a small Rust solver that does roughly what a careful human does:
- Depth-first backtracking with minimum-remaining-values branching.
- At each node, we consider two viewpoints simultaneously: which piece has the fewest places it could go, and which uncovered square has the fewest pieces that could cover it. Attacking the puzzle from both directions at once catches progress that either view on its own would miss — a piece might only have one valid placement left (so we force that placement), or a square might have only one piece that could possibly cover it (even if that piece still has lots of places it could go elsewhere).
- Pick the option with the fewest choices across both viewpoints — zero means dead branch, one means forced move, more than one means real branch.
- Run to exhaustion (enumerate every solution) for a stable metric.
Report difficulty = nodes / n_solutions — roughly, the expected number of search steps between successive solutions. A puzzle with one unique, deeply-hidden solution has high difficulty; one with many easy solutions has low difficulty. This is the same idea I used in the jigsaw puzzle post.
I swept all 81 sets across all 366 dates (366 × 81 ≈ 30 000 solves, around 25 minutes of compute) and recorded (min, average, max) difficulty per set.
| Category | avg difficulty | hardest single date | Notes |
|---|---|---|---|
| Easiest set (seed 86) | 29.6 | 61.6 | — |
| Median set | ≈ 120 | ≈ 500 | — |
| DragonFjord | 176.3 | 1478 | ~80th percentile |
| Hardest set (seed 37) | 411.6 | 3255 | 2.3× harder than DragonFjord |
| Hardest single date (any set) | — | 4472 | seed 98 on one specific date |
There’s a 14× spread between easiest and hardest set. The commercial DragonFjord puzzle sits on the harder side — designed for engaging difficulty — but 15 of the 81 random sets are harder still.
The most interesting observation: size distribution alone does not predict difficulty. Four of the five easiest and four of the five hardest sets have the same [5, 5, 5, 5, 5, 5, 5, 6] pattern as DragonFjord. The difference is in the specific shapes, not the histogram. Which pentominoes you choose matters; how many pentominoes matters less.
The six impossible dates
A nicely-designed calendar puzzle would fail on exactly the six non-dates: Feb 30, Feb 31, Apr 31, Jun 31, Sep 31, Nov 31. A user who asks for “Feb 30” should be told by the puzzle itself that this isn’t a real date — no arrangement of pieces tiles the board.
I ran every one of the 81 sets against all six impossibles. Every set tiles all six. DragonFjord too. Not a single piece set in our collection distinguishes valid from invalid dates.
The reason is geometric: the impossible dates pair a month cell with day 30 or 31, which are cells in the sparse bottom rows of the board. Their uncovered configurations aren’t particularly different — in a tiling sense — from valid (month, day) pairs with similarly placed day cells. With both rotation and reflection available, the piece sets are simply flexible enough to handle them too.
I tried a refinement phase: after finding an 8-piece solution, run local moves (cell swaps between pieces, single-cell shape changes) that keep the 366 valid dates solvable but drop the impossible count from 6. In smoke tests I couldn’t push below 6/6. Intuitively, failing on “Feb 31” means failing on several similarly-shaped valid dates too — these configurations aren’t structurally isolated from the real ones.
I also tried a stronger formulation: search directly for an 8-piece set that (a) solves all 366 valid, (b) fails all 6 impossible, simultaneously — a different CP-SAT model with some targets required feasible and others required infeasible. CP-SAT handled the joint constraint but timed out without finding a solution. I don’t think this is a proof that none exists on this board; but I suspect the property is unachievable without changing the board layout itself. If you want to reject impossible dates unambiguously, you probably need to design the physical board to make those configurations geometrically impossible, not the piece set.
Play with them
Here are all 81 piece sets, embedded in a browser widget. Pick a set from the dropdown, pick a date, drag the pieces onto the board. R rotates the focused piece, F flips it. The top two entries are the extremes from the difficulty sweep — [easy] is seed 86 (the gentlest), [hard] is seed 37 (the most annoying).
Try [hard] with today’s date and see how long you last.
Where this stops
- 81 new 8-piece sets that solve all 366 valid dates, found by random grow-search (80 canonically distinct — two seeds collided). Plus DragonFjord’s original design, that’s 82 known eight-piece solutions.
- Three size distributions only: 67×
[5,5,5,5,5,5,5,6](DragonFjord structure), 10×[4,5,5,5,5,5,6,6], 4×[4,5,5,5,5,5,5,7]. - 22 is the hard upper bound on any single piece in any hypothetical 7-piece solution, via CP-SAT on all 366 dates.
- 14× difficulty range across the 81 sets measured by an MRV-branching Rust solver. DragonFjord is at the 80th percentile for hardness — designed for engagement, but not an outlier.
- Whether a 7-piece solution exists is open. The natural CP-SAT formulation doesn’t resolve it in reasonable time. My gut says no such set exists, but I can’t be sure, and I don’t know how one would prove it.
- Whether an 8-piece set can cleanly reject the 6 impossible dates is open. Every set I found (including DragonFjord) tiles all 6 of them. A refinement pass couldn’t move below 6/6; a direct CP-SAT formulation timed out. The property may simply not be achievable on this board shape.
Plenty of directions left. A proof of non-existence for 7 pieces (if that’s the right answer) probably needs a cleverer argument than CP-SAT — perhaps a coloured weighting that assigns every connected polyomino of size ≤ 22 a sum that fails on some specific date for some specific reason, like a chromatic-invariant argument. If anyone has a nice idea, tell me.