LinkedIn's daily Zip puzzle is simple to explain: draw one line through every cell of a grid, passing the numbered cells in order (1, 2, 3 …), never crossing a wall. Underneath, it's a classic problem: finding a Hamiltonian path that visits every cell exactly once.
You only get one official puzzle a day, so I built a free Zip Unlimited with 480 boards from 5×5 to 8×8, plus a daily board that's the same for everyone. The hard part wasn't drawing lines. It was making sure every board has exactly one solution, because a puzzle with two answers feels broken. Here's how the generator works.
1. Start from a random path, not from the numbers
It's tempting to scatter numbers on a grid and hope a path exists. That fails constantly. Instead, I generate the answer first: a random Hamiltonian path over the whole grid.
The trick is the backbite move:
- Start with a boring snake path (left to right, then right to left, row by row).
- Pick one end of the path (flip a coin to choose which end).
- Pick a random grid neighbour
xof that end. - If
xisn't the cell just before the end, connect the end toxand reverse the part of the path afterx. The result is still a path through every cell.
Repeat that a few thousand times (I use cells × 40 attempts) and the snake turns into a well-mixed random path. It's cheap and always valid.
def backbite(path, rows, cols, rng): if rng.random() < 0.5: path.reverse() end = path[-1] nbrs = [(end[0]+dr, end[1]+dc) for dr, dc in ((0,1),(1,0),(0,-1),(-1,0)) if 0 <= end[0]+dr < rows and 0 <= end[1]+dc < cols] x = rng.choice(nbrs) if x == path[-2]: return path i = path.index(x) return path[:i+1] + path[i+1:][::-1] 2. Put numbers on the path
Cell 1 is the start of the path and the last number is its end. A few more numbers go on random positions along the path, more on bigger boards (5–7 numbers on 5×5, up to 8–13 on 8×8). Because they are numbered in path order, the puzzle is solvable by construction.
3. Prove it has only one solution
Now the important part. I wrote a solver that searches for solutions and stops as soon as it finds two: one is fine, two means the board is ambiguous.
A plain depth-first search is far too slow on 8×8, so it prunes hard. Cells are bits in a Python integer, which makes the checks fast:
- Number order: you can only step onto a numbered cell if it's the next number.
- The end cell comes last: stepping onto the last number with cells left over is a dead end.
- Degree check: every unvisited cell needs at least two open neighbours (one if it's the end cell). Otherwise it can never be passed through.
- Connectivity: a flood fill from the current head must reach every unvisited cell. If the line has cut the board in two, stop.
That last check alone removes most dead branches, because a human solver uses the same rule ("don't split the board").
4. Fix ambiguity by looking where the answers split
If the solver finds a second solution, I compare it with the intended path and find the first cell where they go different ways. Then I add a constraint right there:
- either a wall between the two cells the other solution uses (if that link isn't part of the intended path),
- or a new number on the intended path at that position.
Then solve again. Most boards become unique after a few rounds. Any board that still isn't unique after 60 rounds, or that takes the solver too long, is thrown away.
5. How fast is it?
Measured on a laptop (Python, single core):
| Size | Kept / tried | Time per kept board |
|---|---|---|
| 5×5 | 8 / 15 | 0.01 s |
| 6×6 | 8 / 13 | 0.03 s |
| 7×7 | 8 / 26 | 0.6 s |
| 8×8 | 8 / 40 | 11 s |
8×8 is where the search gets expensive, which is why the boards are generated ahead of time and shipped as one small JSON file (about 80 KB for all 480). The browser never has to solve anything.
6. The front end
The game itself is vanilla JavaScript drawing an SVG grid. A few details that made it feel good on phones:
- Pointer events with
touch-action: noneon the board, so dragging doesn't scroll the page. - Dragging back over your line undoes it; tapping a cell on the line cuts it there.
- If you swipe quickly along a row, it fills every cell up to your finger, so fast swipes don't skip cells.
- The daily board is chosen in the browser: a fixed shuffle of the boards (seeded PRNG), walked one step per day, so everyone gets the same puzzle without a server.
Try it
The boards from this generator are playable at Zip Unlimited. They're my own puzzles in the same style, not LinkedIn's, and the site isn't affiliated with LinkedIn.
This post was written with the help of AI, and the project was built with an AI coding assistant. The algorithms and timings above are taken from the actual code and measurements.