Chapter 269
Can You Connect The Dots?
Riddler Express
Driving north on a grid, at each intersection you turn left or right, each with probability . After intersections, what is the probability you are again driving north? Extra credit: if at each intersection you instead go left, right, or straight, each with probability , what is the probability after intersections?
The Riddler, FiveThirtyEight, June 26, 2020(original post)
Solution
Track the heading as a number (north , east , south , west ). A left turn adds , a right turn adds ; you face north again when the turns sum to a multiple of .
With only left and right turns, every turn is , so after turns the heading is , which is even, hence north or south, never east or west. The sum is a multiple of exactly when the number of right turns is odd, and among fair turns that happens half the time: The extra credit adds a “straight” move (). Using the roots-of-unity filter, the probability of returning to north after steps is with , in which the term gives and the others contribute : The straight option pulls the answer almost exactly to : with three turn choices the four headings are nearly equally likely after ten steps.
The computation
Encode the heading as a state and propagate the exact probability distribution over turns, for both turn rules.
from fractions import Fraction as F
from collections import defaultdict
def north_after(moves, steps=10):
dist = defaultdict(lambda: F(0)); dist[0] = F(1)
for _ in range(steps):
nd = defaultdict(lambda: F(0))
for h, pr in dist.items():
for mv in moves: nd[(h + mv) % 4] += pr * F(1, len(moves))
dist = nd
return dist[0]
print(north_after([1, 3])) # 1/2 (left/right only)
print(north_after([1, 3, 0])) # 4921/19683 ~ 0.2500 (with straight)
Riddler Classic
Polly connects six unlabelled dots into a hexagon, and finds many different (non-self-intersecting) hexagons on the same six points. What is the greatest possible number of unique hexagons on six points? (Hint: with four points, the answer is three.) Extra credit: the greatest number of heptagons on seven points?
The Riddler, FiveThirtyEight, June 26, 2020(original post)
Solution
A hexagon on six fixed points is a cyclic ordering of them, and there are such orderings (a cycle read in either direction is the same hexagon). Most of these self-intersect; Polly wants the simple ones, whose edges do not cross. The count depends on where the points lie, and it is largest not when the points are spread out but when they are nested: the record is set by putting three points inside the triangle formed by the other three.
For that arrangement the number of simple hexagons is and for seven points (where there are orderings) the maximum is These are the first entries of OEIS sequence A063546, the largest number of crossing-free Hamiltonian cycles on points (Aichholzer’s enumerations): for
The computation
Encode a hexagon as a cyclic order, and call it simple when no two non-adjacent edges cross (a standard segment-intersection test). Count the simple orderings for an optimal nested configuration of six points, and of seven points.
from itertools import permutations, combinations
def crosses(a, b, c, d):
def turn(p, q, r): return (q[0]-p[0])*(r[1]-p[1]) - (q[1]-p[1])*(r[0]-p[0])
return (turn(c, d, a) > 0) != (turn(c, d, b) > 0) and \
(turn(a, b, c) > 0) != (turn(a, b, d) > 0)
def simple_count(pts):
n = len(pts); total = 0
for perm in permutations(range(1, n)):
o = (0,) + perm
if o[1] > o[-1]: continue # one direction per cycle
e = [(o[i], o[(i + 1) % n]) for i in range(n)]
if all(not crosses(pts[a], pts[b], pts[c], pts[d])
for (a, b), (c, d) in combinations(e, 2)
if len({a, b, c, d}) == 4):
total += 1
return total
hex6 = [(0,0),(12,0),(6,11),(4,3),(8,2),(6,6)] # 3 points inside a triangle
hep7 = [(0,0),(20,0),(10,19),(15,2),(17,2),(15,6),(12,3)]
print(simple_count(hex6)) # 29
print(simple_count(hep7)) # 92