Chapter 1
Kakuro
Kakuro is a crossword for arithmeticians. A grid of black and white cells awaits; the white cells are to receive digits between and . Where the standard crossword demands a word, Kakuro demands a sum. Each horizontal or vertical run of white cells must add to the small number written in the adjacent clue cell, and no digit may repeat inside a run.
The puzzle was published by Maki Kaji’s Nikoli in under the name Kasan Kurosu, a contraction of the Japanese kasan (“addition”) and the English-borrowed kurosu (“cross”). Nikoli shortened this to Kakuro six years later, and the puzzle made its way into the English-speaking world in the early s, often sharing newspaper column inches with Sudoku. The two puzzles share a parent (Dell Magazines’ Cross Sums, ) and a logical substrate: both are constraint-satisfaction problems over the alphabet with all-different constraints on subsets of cells.
Small Kakuros yield to pencil and paper. Large ones, and the sub-class in which clue cells carry three- or four-cell sums, yield fastest to a constraint solver. This chapter does both: a hand-solvable instance to anchor the rules, then a general / integer-programming model that a dozen lines of Python turn into a solver for any Kakuro you can encode.
Rules and a small instance
A Kakuro puzzle is an grid of cells, each of which is one of three kinds. A block cell is uniformly shaded and carries no clue. A clue cell is shaded and holds up to two sums: an across sum in the lower-left triangle referring to the horizontal run of white cells to its right, and a down sum in the upper-right triangle referring to the vertical run of white cells below. A white cell is to be filled with a digit from to .
Two constraints govern each run.
The digits in the run add to the sum declared by its clue.
No digit is used twice inside the run.
A digit may, of course, appear in many runs of a single puzzle; the all-different constraint applies strictly inside each run, never across the whole grid.
Figure 1.1 gives a instance with six white cells, reduced to the minimum that still exhibits all the clue geometries. The two column sums on the top row govern the two columns of white cells below them, and each row clue on the left governs the white cells to its right.
One constraint is instantly visible. The clue at the top of column governs a single white cell, so that cell must be . That cell sits in the row whose across clue is , forcing its neighbour to be ; and so on. Any human solver following these forced implications to their conclusion will arrive at the digits later recovered by the solver in Figure 1.2.
The programming model
Write for the set of white cells and for the set of runs. A run is a maximal horizontal or vertical sequence of white cells governed by a single clue; denote its target sum by and its cell set by . Each white cell belongs to exactly one across-run and exactly one down-run.
Constraint-satisfaction formulation
Associate an integer variable with each white cell . The puzzle becomes
The sum constraints are linear; the all-different constraints are global, but a CP solver handles them natively through hall-interval reasoning. A Kakuro puzzle is well-posed when this system has exactly one integer solution.
Integer-programming formulation
For a plain ILP formulation, replace each cell variable by nine indicators for , where means cell holds digit . The model becomes
Either formulation works; the CP version is shorter to write and usually faster to solve. Google’s OR-Tools CP-SAT backend, used below, exposes the integer model directly.
A solver in thirty lines
The following Python reads a Kakuro specified as a list of clues and a grid of cell coordinates, builds the CP-SAT model, and returns the digit assignment.
from ortools.sat.python import cp_model
def solve_kakuro(cells, runs):
"""Solve a Kakuro and return {cell: digit}.
cells : white-cell coordinates (row, col).
runs : (sum, [cell, ...]) pairs, one per run.
"""
model = cp_model.CpModel()
x = {c: model.NewIntVar(1, 9, f"x{c}") for c in cells}
for s, run_cells in runs:
model.Add(sum(x[c] for c in run_cells) == s)
model.AddAllDifferent([x[c] for c in run_cells])
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status not in (cp_model.OPTIMAL, cp_model.FEASIBLE):
raise RuntimeError("no solution")
return {c: solver.Value(x[c]) for c in cells}
The solver is content-free: every Kakuro-specific fact sits in the cells and runs arguments. For the instance in Figure 1.1, those arguments are
cells = [(1, 1), (1, 2), (2, 1), (2, 2), (3, 2), (3, 3)]
runs = [
(17, [(1, 1), (2, 1)]), # col 1 17 down
(23, [(1, 2), (2, 2), (3, 2)]), # col 2 23 down
(7, [(3, 3)]), # col 3 7 down
(17, [(1, 1), (1, 2)]), # row 1 17 across
(15, [(2, 1), (2, 2)]), # row 2 15 across
(15, [(3, 2), (3, 3)]), # row 3 15 across
]
print(solve_kakuro(cells, runs))
CP-SAT returns in a handful of milliseconds the assignment which Figure 1.2 renders back on the grid.
A larger instance
The toy puzzle is solved as much by inspection as by the solver. To exercise CP-SAT properly, Figure 1.3 gives a Kakuro with white cells and runs, of typical published difficulty: many runs of length three or four, overlapping clue geometries, no obvious forced moves at the start. The same solver code, called on this instance, returns the unique assignment in Figure 1.4 after roughly milliseconds of search. Enumeration confirms uniqueness: the solver, asked for all feasible assignments, finds exactly one.
What carries the search at this size is the all-different constraint’s domain reasoning. The clue over a five-cell run, for instance, instantly forces the digit set to or or one of a handful of other partitions of into five distinct digits between and ; CP-SAT enumerates these at the front of the search and reuses them throughout. The two-cell, low-sum clues like admit only or , and propagate cell-by-cell.
Sources. Kakuro appeared in Nikoli’s magazine Puzzle Tsushin in under the name Kasan Kurosu; Nikoli shortened it to Kakuro in . The American ancestor is Dell Magazines’ Cross Sums, which the puzzle designer Jacob Funk published in in Dell Pencil Puzzles & Word Games. Google’s OR-Tools CP-SAT solver, released open-source in , is used throughout this book; its constraint model is documented at developers.google.com/optimization. The clue geometry in Figure 1.1 is original to this chapter, but the underlying aesthetic — diagonal clue cells, grey block fills, running sums on the outer margin — is Nikoli’s.