Books · Solving Puzzles through Mathematical Programming
Chapter 21
Verbal Arithmetic and Mastermind
Two puzzles of deduction sit comfortably inside the same small frame of integer programming. The first is verbal arithmetic, where the digits of a sum have been hidden behind letters and the solver must read them back. The second is Mastermind, where a secret number is hunted through guesses and the scored replies they draw. Both are problems of assigning digits under constraints, the alphametic by the arithmetic of carrying, Mastermind by the bookkeeping of which guessed digits landed and where, and both fall to a handful of linear constraints. The pairing follows John Simon’s note in the INFORMS Transactions on Education puzzle column.
Verbal arithmetic
In an alphametic, each letter stands for a digit, distinct letters take distinct digits, and no number begins with a zero. The most famous is Henry Dudeney’s, on the eight letters .
Variables and constraints
Let each letter be an integer variable in , with the eight constrained all different, and so neither four-digit number has a leading zero. The arithmetic is read one column at a time, right to left, carrying a or into the next. With carries , and the final carry is the leading digit, . The column identities are exactly the schoolbook addition, made into linear equations.
The solver
from ortools.sat.python import cp_model
def send_more_money():
m = cp_model.CpModel()
S, E, N, D, M, O, R, Y = (m.NewIntVar(0, 9, c) for c in "SENDMORY")
m.AddAllDifferent([S, E, N, D, M, O, R, Y])
m.Add(S >= 1); m.Add(M >= 1)
c1, c2, c3, c4 = (m.NewIntVar(0, 1, f"c{k}") for k in range(4))
m.Add(D + E == Y + 10 * c1) # units
m.Add(c1 + N + R == E + 10 * c2) # tens
m.Add(c2 + E + O == N + 10 * c3) # hundreds
m.Add(c3 + S + M == O + 10 * c4) # thousands
m.Add(c4 == M) # the final carry is M
s = cp_model.CpSolver()
s.Solve(m)
return {ch: s.Value(v)
for ch, v in zip("SENDMORY", (S, E, N, D, M, O, R, Y))}
The puzzle has a single solution, , , and the rest falling into place to give
Mastermind
In the numerical Mastermind played here, a secret is a five-digit number with all digits different. A guess is another such number, and the reply scores it two ways: , the count of digits that are correct and in the correct position, and , the count of guessed digits that appear somewhere in the secret, in place or not, so . In the familiar pegboard, is the black pegs and the white. After a run of guesses, each scored, the question is which secret is consistent with every reply, and that consistency is an integer program.
Variables and constraints
Let be the secret’s digits, constrained all different, and let the boolean record whether digit occurs in the secret. For a guess scored , the count of positions where the secret matches the guess must equal , and the count of the guess’s (distinct) digits that the secret contains must equal : Each guess contributes one such pair of equations. Solving the accumulated system returns a secret consistent with all the evidence; when only one survives, the secret is found.
The solver
from ortools.sat.python import cp_model
def mastermind(clues): # clues: list of (guess, P, D)
m = cp_model.CpModel()
p = [m.NewIntVar(0, 9, f"p{i}") for i in range(5)]
m.AddAllDifferent(p)
has = [m.NewBoolVar(f"h{d}") for d in range(10)]
for d in range(10):
occ = []
for i in range(5):
b = m.NewBoolVar("")
m.Add(p[i] == d).OnlyEnforceIf(b)
m.Add(p[i] != d).OnlyEnforceIf(b.Not())
occ.append(b)
m.Add(has[d] == sum(occ)) # digits distinct, so 0 or 1
for guess, P, D in clues:
exact = []
for i in range(5):
b = m.NewBoolVar("")
m.Add(p[i] == guess[i]).OnlyEnforceIf(b)
m.Add(p[i] != guess[i]).OnlyEnforceIf(b.Not())
exact.append(b)
m.Add(sum(exact) == P) # right digit, right place
m.Add(sum(has[d] for d in set(guess)) == D) # right digit, any place
s = cp_model.CpSolver()
s.Solve(m)
return tuple(s.Value(pi) for pi in p)
Figure 21.1 works one secret through six guesses. The first guess, , already scores one black peg and four whites; by the sixth the integer program has only one number left to report, the secret . The model never guesses, it only deduces: each reply is a constraint, and the constraints tighten until a single five-digit number satisfies them all.
Sources. Both formulations follow John T. Simon, Puzzle—Verbal Arithmetic and Mastermind, INFORMS Transactions on Education volume , number (), pages –. The alphametic SEND MORE MONEY is Henry E. Dudeney’s, from Strand Magazine (). Mastermind was devised by Mordecai Meirowitz around ; the optimal-strategy analysis of the classic pegs-and-colours version is Donald Knuth’s The Computer as Master Mind (Journal of Recreational Mathematics, ). The deduction instance solved here is constructed so that six scored guesses determine the secret uniquely.