Product Engineering

How We Built a Daily Puzzle Everyone Shares

How We Built a Daily Puzzle Everyone Shares article illustration

Every day, Puzji Games shows one featured puzzle, and every player in the world gets exactly the same board. You can solve it on your phone, send the link to a friend, and they will see the board you solved, not a fresh random one. There is no puzzle database behind this and no server deciding what today’s board is. This article explains how it works, and the design choices that made it simple to run.

The requirement: one board per day, for everyone

A shared daily challenge only works if the board is identical for every player. If two friends compare times on different boards, the comparison means nothing. The board also has to change at a predictable moment, it has to be solvable, and it should load instantly, including on a slow connection or after the player goes offline.

The obvious design is a server that generates or stores a puzzle each day and hands it out through an API. That works, but it adds a database, a scheduled job and an API that must stay online for the game to work at all. We wanted the daily puzzle to keep working even when the API is down, so we made the board a pure function of the date.

Step 1: turn the date into a seed

The day is defined in UTC, so the board changes at the same instant everywhere. The game counts whole days since 1 January 2026 and uses that number for two things: the challenge number shown on screen, and which game is featured. Seven games rotate in a fixed order (Trace, Zip, Patches, Queens, Tally, Streak and Ripple), so the featured game follows the day index modulo seven.

Next, the game builds a short text key from a version number, the date and the game, for example “puzji-daily:v1:2026-10-14:zip”, and hashes it with FNV-1a, a small and fast 32-bit hash. The result is a seed: a number that is always the same for that day and game, and almost always different for any other day.

The version number matters more than it looks. If we ever change a generator in a way that would change past boards, we bump the version, and every old share link keeps describing the board it was created for.

Step 2: a random generator that is not random

Generating a puzzle needs random choices: where to start a path, how long each segment is, which cells hold clues. Browsers provide Math.random, but it cannot be seeded, so two players would get two different boards.

Instead, each generator uses a tiny seeded pseudo-random function from the Mulberry32 family. It keeps one 32-bit number of state and mixes it with multiplications and bit shifts each time it is called. Given the same seed it produces the same sequence of numbers on every device and browser, because it uses only 32-bit integer operations (Math.imul and unsigned shifts) that behave identically everywhere. That determinism is the whole trick: same seed in, same board out.

Step 3: build the board from its solution

A random board is only useful if it can be solved. Rather than placing clues and hoping a solution exists, our generators work backwards from a finished solution.

Take Trace, the connect-the-dots game. The generator first draws a single path that visits every cell of the grid exactly once, known as a Hamiltonian path. It searches with backtracking, and at each step it prefers the neighbouring cell with the fewest unvisited neighbours of its own. This rule of thumb, known as Warnsdorff’s rule from the knight’s tour problem, keeps the search from painting itself into a corner and usually finds a full path quickly. The search has a hard limit on work, so if one start point fails it moves on rather than freezing the page.

The finished path is then cut into four to seven segments of different lengths, and each segment becomes one colour. The two ends of each segment become the dots you see. Because the board was made by cutting up a real solution, it is guaranteed to be solvable, and every cell is covered. Other games follow the same idea: Zip numbers points along a path through the grid, and Tally checks how many solutions its clues allow so the clues lead to one answer.

Step 4: share links that replay the exact board

When a player shares today’s challenge, the link includes the date and the seed, written in base 36 to keep it short. Opening the link runs the same generator with the same seed, so the friend sees the identical board even if they open it days later, after the featured puzzle has moved on.

Each generated board also has a stable ID made from its size, seed and generation attempt. Results are saved on the player’s device under that ID, which is how the home page knows whether you have already solved today’s puzzle and can show your time.

Step 5: make it work offline

Because a board needs nothing from a server, the remaining job is to make sure the game code itself is available. A service worker caches the app after the first visit, so the games and the daily challenge keep working on a train or in airplane mode. Progress and results stay in local storage on the device, so nothing is lost when the connection drops.

What we would tell another team

If your feature can be described as “the same thing for everyone, changing on a schedule”, consider computing it instead of storing it. You remove a database table, a scheduled job and an outage risk, and you get reproducibility for free, which makes bugs easy to replay: give a developer the seed and they can see the exact board a player saw.

  • Define the period in UTC and derive everything from a day index
  • Hash a versioned text key into a seed so old links never change meaning
  • Use a small seeded generator with integer-only maths for identical results on every device
  • Generate content from a known-good solution so it is always valid
  • Put the seed in share links, and cache the app for offline play

Related service: Product engineering and MVP development

Have a product or automation challenge?

Share the business goal with Puzji and we will help identify a practical product, AI, integration, or cloud delivery path.

Plan the next step