Write-up for 2 × 4 = 8
Overview
The puzzle is basically 8 × 8 Sudoku, where each solver is given a board randomly filled with numbers 1 to 8, and the solution is to fill the remaining squares such that each row, column, and 2 × 4 subgrid contain the numbers 1 through 8 once each.
Generating the starting position
First, the generate
function generates a seed by hashing the player's address.
Then, the function loops through the seed until it's completely used up or 1 through 8 have each been assigned a unique, random index on the board. To ensure each index is unique, we use a bitmap, where a 1
at the corresponding least significant bit (LSb) position indicates the index has been "seen"/used up.
See a deeper explanation of a simpler application of this technique here.
By generating the starting position in such a way, every output must have a valid solution.
Verifying Sudoku rules
First, at each of the 64 squares, the verify
function performs a few rudimentary checks:
- No square must be empty.
- Each non-empty square in the starting position must equal the square provided in the solution.
Then, at each of the 64 squares, the function conditionally applies Sudoku rule checks via a helper check
function, which checks if are present given a set of 8 indices to look at.
check
uses the same technique used in generate
, except it can check the existence of
in any set of 8 indices by taking in a series of shifts to apply after each iteration, rather
than just shifting by 4 bits every time.
This is very helpful because Sudoku is quite repetitive: for each row, column, and subgrid, we perform the same check. With the way the helper function is set up, we can do that easily by defining the index shifts to look at for a row, column, or subgrid.
For example, for a subgrid, we'd want to shift by 4 bits, then 4, 20, 4, 4, 4, and 4 to read each square:
The final key is to apply the correct shifts at the correct indices. For example, applying SUBGRID_SHIFTS
at index 4 would read a nonexistent subgrid because no subgrid starts from index 4. To achieve this, at each of the 64 squares, we retrieve a value from a bitpacked uint256 CHECKS
of 4-bit words with the following meanings:
- 0th LSb: whether to perform a subgrid check.
- 1st LSb: whether to perform a column check.
- 2nd LSb: whether to perform a row check.
- 3rd LSb: empty bit.
Then, we read which checks to perform via & 7
and dispatch it with the respective constants into check
.
If all of these checks pass at every index of the board, we have a valid solution!