Books · The Fiddler: Solutions
Chapter 47
The Dozo Board and the Fifty Stars
To mark the th Fiddler, two counting puzzles. A Dozo board has holes in a triangular array ( per side). How many distinct equilateral triangles have all three vertices at holes? Congruent triangles in different positions count separately.
The Fiddler, Zach Wissner-Gross, July 4, 2025(original post)
Solution
Upright, inverted, and tilted equilateral triangles must all be counted. A classical identity says the number of equilateral triangles with vertices in a triangular array of points per side is , every tilted triangle being inscribed in a unique upright bounding one. For ,
The computation
Place the holes at their true coordinates and test every triple: it is equilateral when its three squared side lengths agree (and are nonzero). The brute-force count matches .
import itertools as it
from math import sqrt, comb
pts = [(k - r/2, -r*sqrt(3)/2) for r in range(7) for k in range(r + 1)]
d2 = lambda a, b: (a[0] - b[0])**2 + (a[1] - b[1])**2
n = sum(abs(d2(a, b) - d2(b, c)) < 1e-9 and abs(d2(b, c) - d2(a, c)) < 1e-9 and d2(a, b) > 1e-9
for a, b, c in it.combinations(pts, 3))
print(n, comb(9, 4)) # 126 126
Extra Credit
The stars on the American flag sit in the usual offset grid ( rows alternating and stars). How many distinct parallelograms have all four vertices at star centres?
Solution
Two point-pairs form a parallelogram exactly when they share a midpoint (the diagonals bisect each other). Bucketing all pairs by midpoint, summing within each bucket, and discarding the degenerate collinear quadruples gives (The source’s count is paywalled; this is my own enumeration.)
The computation
Group every pair of stars by the midpoint of the segment joining them; any two pairs sharing a midpoint are the diagonals of a parallelogram. Count those, then subtract the collinear (degenerate) cases.
from collections import defaultdict
from itertools import combinations
stars = [(x, y) for y in range(9) for x in range(11) if (x + y) % 2 == 0]
mid = defaultdict(list)
for i, j in combinations(range(50), 2):
mid[(stars[i][0] + stars[j][0], stars[i][1] + stars[j][1])].append((i, j))
para = degen = 0
for pairs in mid.values():
para += len(pairs)*(len(pairs) - 1)//2
for (i, j), (p, q) in combinations(pairs, 2):
x0, y0 = stars[i]
cr = lambda A, B: (A[0] - x0)*(B[1] - y0) - (A[1] - y0)*(B[0] - x0)
if cr(stars[j], stars[p]) == 0 and cr(stars[j], stars[q]) == 0: degen += 1
print(para - degen) # 5918