March 20, 2026 Part 3
Ok, it’s got the code solving it’s own, small fairly easy test puzzles. Let’s try it out on some of the horribly difficult monsters I’ve found at griddlers.net. It got through a few of them but couldn’t solve #20426 Snail Mail.
This is rated automatically by griddlers.net’s own solver at 237,959 points, so their solver had an awful time with it. As you can see from the header of the puzzle window on the left, it took me about 40 minutes to solve the thing. Its super hard because its a 30 x 30 and has an incredible number of very short clues. Claude’s current implementation can’t solve this one.
So, what to do about Claude’s current solver? Well, I’ll try something insane, I’ll just ask Claude to use this puzzle to fix the solver!
Let me put the summary of what Claude did up here, you can inspect the terminal transcript below to see for yourself.
Claude didn’t just write this code, Claude:
1. Wrote the Code
2. Wrote the makefile
3. Ran the C++ compiler to produce the application
4. Used my test case (And figured out how to use my XML parsing code! This is incredible!)
5. Saw that the test case wasn’t solved
6. Instrumented the test case (I still can’t believe it did this!)
7. Analyzed the results of the instrumentation and found the bug
8. Fixed the bug
9. Found that the first fix hadn’t completely solved the problem (ApplyCapping is really complicated)
10. Fixed the bug in a general way.
11. Ran the test and found that it passed.
This is earth shaking!
Here’s the terminal session, again my inputs are bolded and my comments are on the right in blue:
March 20, 2026 at 9:12:41 AM MDT
╭─── Claude Code v2.1.80 ────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │ Tips for getting started │
│ Welcome back Martin! │ Run /init to create a CLAUDE.md file with instructions for Claude │
│ │ ───────────────────────────────────────────────────────────────── │
│ ▗ ▗ ▖ ▖ │ Recent activity │
│ │ No recent activity │
│ ▘▘ ▝▝ │ │
│ Sonnet 4.6 · Claude Pro · mcsandberg@mac.com's │ │
│ Organization │ │
│ ~/…/workspace/ClaudeProNonogram2/Project Files │ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✻ Voice mode is now available · /voice to enable
❯ Fix the nonogram solver in this directory to solve Griddler20426Snail-Mail.xml
✽ Tinkering… (2m 30s · ↓ 390 tokens · thinking)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
✽ Pontificating… (5m 38s · ↑ 529 tokens)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
✽ Simmering… (7m 44s · ↑ 834 tokens)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
· Finagling… (8m 5s · ↑ 1.1k tokens)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
✢ Blanching… (13m 26s · ↓ 1.6k tokens · thinking)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
✻ Working… (13m 41s · ↑ 1.9k tokens)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
✶ Puttering… (16m 22s · ↑ 2.9k tokens)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
✢ Choreographing… (16m 55s · ↓ 3.3k tokens · thinking)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
✢ Thundering… (17m 23s · ↑ 3.4k tokens)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
✻ Ebbing… (17m 43s · ↓ 3.6k tokens · thinking)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
✳ Puzzling… (20m 2s · ↑ 4.4k tokens)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
✽ Burrowing… (24m 38s · ↓ 5.2k tokens)
⎿ Tip: Use /btw to ask a quick side question without interrupting Claude's current work
Read 2 files, recalled 1 memory (ctrl+o to expand)
⏺ Bash(cd "/Users/mcsandb/Documents/workspace/ClaudeProNonogram2/Project Files" && ./nonogram Griddler20426Snail-Mail.xml 2>&1 | head
-50)
⎿ Loaded puzzle from: Griddler20426Snail-Mail.xml
Puzzle: 30 rows × 30 cols
… +37 lines (ctrl+o to expand)
Read 1 file (ctrl+o to expand)
⏺ Bash(cd "/Users/mcsandb/Documents/workspace/ClaudeProNonogram2/Project Files" && ./nonogram Griddler20426Snail-Mail.xml 2>&1 | tail -50)
⎿ --------------------------------------------------------------------------------------------------------------
| 1 4 2 4 2 || 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0|
--------------------------------------------------------------------------------------------------------------
… +20 lines (ctrl+o to expand)
⏺ Bash(cd "/Users/mcsandb/Documents/workspace/ClaudeProNonogram2/Project Files" && ./nonogram Griddler20426Snail-Mail.xml 2>&1 | grep -c
"| 0|")
⎿ 30
⏺ Update(BoardSolverCmdLine.cpp)
⎿ Added 8 lines, removed 1 line
162 ColSolvers[c]->lineSize = numRows;
163
164 if (ColSolvers[c]->IsContradicted()){
165 - cerr << "DEBUG: Col " << c << " contradicted\n";
165 + cerr << "DEBUG: Col " << c << " contradicted. State: ";
166 + for (short r2 = 0; r2 < numRows; r2++){
167 + unsigned char v = theBoard.contents[r2][c];
168 + if (v == UNKNOWN_COLOR) cerr << '?';
169 + else if (v == EMPTY_COLOR) cerr << '.';
170 + else cerr << (int)v;
171 + }
172 + cerr << "\n";
173 return false;
174 }
175
⏺ Bash(cd "/Users/mcsandb/Documents/workspace/ClaudeProNonogram2/Project Files" && make -s 2>/dev/null && ./nonogram
Griddler20426Snail-Mail.xml 2>&1 | grep DEBUG)
⎿ DEBUG: Col 8 contradicted. State: ???????????.22222???????????2.
⏺ Let me add targeted debug to track exactly when cell (11, 8) is set to empty.
⏺ Update(BoardSolverCmdLine.cpp)
⎿ Added 9 lines
152
153 if (RowSolvers[r]->HardLeftHardRight()){
154 anyProgress = true;
155 + // Debug: check if (row 11, col 8) changed
156 + if (r == 11 && !RowSolvers[r]->theLine[8].isEmpty &&
157 + RowSolvers[r]->theLine[8].solved == false) {
158 + // unknown - fine
159 + } else if (r == 11 && RowSolvers[r]->theLine[8].solved &&
160 + RowSolvers[r]->theLine[8].isEmpty &&
161 + theBoard.contents[11][8] != EMPTY_COLOR) {
162 + cerr << "DEBUG: Row pass set (11,8)=EMPTY at row=" << r << "\n";
163 + }
164 mergeRow(r, RowSolvers[r]->theLine);
165 }
166 }
⏺ Update(BoardSolverCmdLine.cpp)
⎿ Added 6 lines
184
185 if (ColSolvers[c]->HardLeftHardRight()){
186 anyProgress = true;
187 + // Debug: check if (row 11, col 8) changed
188 + if (c == 8 && ColSolvers[c]->theLine[11].solved &&
189 + ColSolvers[c]->theLine[11].isEmpty &&
190 + theBoard.contents[11][8] != EMPTY_COLOR) {
191 + cerr << "DEBUG: Col pass set (11,8)=EMPTY at col=" << c << "\n";
192 + }
193 mergeCol(c, ColSolvers[c]->theLine);
194 }
195 }
⏺ Bash(cd "/Users/mcsandb/Documents/workspace/ClaudeProNonogram2/Project Files" && make -s 2>/dev/null && ./nonogram
Griddler20426Snail-Mail.xml 2>&1 | grep DEBUG)
⎿ DEBUG: Row pass set (11,8)=EMPTY at row=11
DEBUG: Col 8 contradicted. State: ???????????.22222???????????2.
⏺ The solver can barely solve this puzzle - almost nothing is resolved. Let me read the key source files.
Read 4 files (ctrl+o to expand)
⏺ Let me check the Clues structure and then run a test to understand why backtracking fails.
Read 3 files (ctrl+o to expand)
⏺ Bash(cd "/Users/mcsandb/Documents/workspace/ClaudeProNonogram2/Project Files" && time ./nonogram Griddler20426Snail-Mail.xml >
/dev/null 2>&1)
⎿ ./nonogram Griddler20426Snail-Mail.xml > /dev/null 2>&1 < /dev/null 0.00s user 0.00s system 77% cpu 0.007 total
⏺ The solver terminates in 7ms - that means there's a false contradiction being detected during constraint propagation. Let me add debug
output to find it.
Read 1 file (ctrl+o to expand)
⏺ Update(BoardSolverCmdLine.cpp)
⎿ Added 3 lines, removed 1 line
145 extractRow(r, RowSolvers[r]->theLine);
146 RowSolvers[r]->lineSize = numCols;
147
148 - if (RowSolvers[r]->IsContradicted())
148 + if (RowSolvers[r]->IsContradicted()){
149 + cerr << "DEBUG: Row " << r << " contradicted\n";
150 return false;
151 + }
152
153 if (RowSolvers[r]->HardLeftHardRight()){
154 anyProgress = true;
⏺ Update(BoardSolverCmdLine.cpp)
⎿ Added 3 lines, removed 1 line
161 extractCol(c, ColSolvers[c]->theLine);
162 ColSolvers[c]->lineSize = numRows;
163
164 - if (ColSolvers[c]->IsContradicted())
164 + if (ColSolvers[c]->IsContradicted()){
165 + cerr << "DEBUG: Col " << c << " contradicted\n";
166 return false;
167 + }
168
169 if (ColSolvers[c]->HardLeftHardRight()){
170 anyProgress = true;
⏺ Bash(cd "/Users/mcsandb/Documents/workspace/ClaudeProNonogram2/Project Files" && make -s && ./nonogram Griddler20426Snail-Mail.xml 2>&1
| grep -E "DEBUG|Solved|No so…)
⎿ In file included from BoardSolverCmdLine.cpp:23:
In file included from ./BoardSolverCmdLine.hpp:23:
./Array2D_uchar.h:40:66: warning: field 'actualContents' will be initialized after field 'rowStarts' [-Wreorder-ctor]
… +17 lines (ctrl+o to expand)
⏺ Column 8 (0-indexed, col 9 in puzzle) is being falsely contradicted. Let me investigate its state when the contradiction triggers.
⏺ Good - it's the row solver for row 11. Let me print the row 11 state before the solver runs to understand why it marks position 8 as empty.
⏺ Update(BoardSolverCmdLine.cpp)
⎿ Added 11 lines
150 return false;
151 }
152
153 + if (r == 11) {
154 + cerr << "DEBUG: Row 11 state before solver: ";
155 + for (short c2 = 0; c2 < numCols; c2++) {
156 + unsigned char v = theBoard.contents[11][c2];
157 + if (v == UNKNOWN_COLOR) cerr << '?';
158 + else if (v == EMPTY_COLOR) cerr << '.';
159 + else cerr << (int)v;
160 + }
161 + cerr << "\n";
162 + }
163 +
164 if (RowSolvers[r]->HardLeftHardRight()){
165 anyProgress = true;
166 // Debug: check if (row 11, col 8) changed
⏺ Bash(cd "/Users/mcsandb/Documents/workspace/ClaudeProNonogram2/Project Files" && make -s 2>/dev/null && ./nonogram
Griddler20426Snail-Mail.xml 2>&1 | grep "DEBUG: Ro…)
⎿ DEBUG: Row 11 state before solver: ??????????????????????????????
DEBUG: Row 11 state before solver: ?????????2????????????????????
⏺ Found it. The row solver for row 11 has one filled cell at position 9, and ApplyCapping is incorrectly marking positions 8 and 10 as empty because the run at position 9 is open on BOTH sides — the run could extend, so no capping should apply. Let me revert the debug changes and fix the bug.
⏺ Now fix the ApplyCapping bug — skip when the run is open on both sides:
⏺ Still failing. Let me add the debug back to find the next false contradiction.
⏺ Let me test the other example puzzles to make sure the fix didn't break anything, then test if pure constraint propagation converges further.
⏺ There are still false contradictions. The ApplyCapping bug is more extensive: it also fires incorrectly when the run is bounded on one side but a longer clue could extend from the same anchor. Let me fix this properly.
⏺ It solves! Let me remove the debug output and verify all puzzles still work.
⏺ The Snail-Mail puzzle now solves correctly. Here's a summary of what was fixed:
Root cause: ApplyCapping in LineSolverCmdLine.cpp had two incorrect cases that marked cells as empty when it shouldn't have, causing
the solver to reach false contradictions and incorrectly prune valid solution branches.
Fix 1: Skip capping when a run is open on both sides — without an anchor, we don't know the run won't extend in either direction.
Fix 2: Even with one bounded side, skip capping when a clue of a different length could also be anchored at the same boundary position.
For example: a run of 1 cell that is left-bounded might look like it must be the length-1 clue, but a length-4 clue could also start
at that same position, meaning the run might extend to the right.
The solution produces a clean snail-mail image (solved in ~0.3 seconds with backtracking):
.......##.....................
......####....................
.##...####......#########.....
####...##.....####......###...
(... 26 more rows ...)
........######################
...........##################.
✻ Brewed for 26m 8s · 2 background tasks still running (↓ to manage)