Skip to content
Vamshi Jandhyala

Books · The Fiddler: Solutions

Chapter 21

Can You Hop in a Spiral?

Frankie the frog hops on a vast hexagonal lattice of lily pads, each pad of diameter 11, so neighbouring centres sit 11 apart. Starting from pad AA, she hops to neighbouring pads in a counterclockwise spiral, subject to two rules: each pad must be in a more counterclockwise direction from AA than the previous one, and each pad must be farther from AA than the previous one. After spiralling around, she finds herself once again due east of AA. How close to AA can she be?

The Fiddler, Zach Wissner-Gross, January 30, 2026(original post)

Solution

She can be no closer than 64.\boxed{64}.

The two rules say her bearing from AA strictly increases and her distance from AA strictly increases at every hop. To come back due east she must wind her bearing all the way from 00^\circ round to 360360^\circ. The lattice has six-fold symmetry, with pads lined up along the six rays at 0,60,,3000^\circ, 60^\circ, \dots, 300^\circ. Crossing from one ray to the next, the tightest legal corner Frankie can turn, still gaining both bearing and distance, is a 303060609090 triangle, which doubles her distance from AA. Six such sectors carry her once around, multiplying her distance by 26=642^6 = 64: starting one pad out, she returns due east no nearer than 6464.

A spiral obeying both rules, winding once around AA and returning due east at distance 6464, the closest possible.

The computation

Encode the two rules on the lattice: process pads in order of distance from AA (a valid order, since each legal hop strictly increases distance) and mark a pad reachable if some marked neighbour hops to it while gaining both distance and counterclockwise bearing. The nearest reachable due-east pad past the start is 6464.

import numpy as np
from math import atan2, pi, hypot
S3 = np.sqrt(3)/2
NB = [(1,0),(-1,0),(0,1),(0,-1),(1,-1),(-1,1)]   # 6 lattice neighbours
def rad(a, b): return hypot(a + b/2, b*S3)
def prin(a, b):
    t = atan2(b*S3, a + b/2); return t if t >= 0 else t + 2*pi
def ccw(P, Q):                                   # bearing strictly increases
    return ((prin(*Q) - prin(*P) + pi) % (2*pi) - pi) > 1e-9
RMAX = 80.0; M = int(RMAX) + 2
pts = sorted([(a, b) for a in range(-M, M+1) for b in range(-M, M+1)
              if 1e-9 < rad(a, b) <= RMAX], key=lambda p: rad(*p))
reach = {(1, 0)}
for P in pts:                                    # radius order = valid topological order
    if P not in reach: continue
    for da, db in NB:
        Q = (P[0]+da, P[1]+db)
        if rad(*Q) > rad(*P)+1e-9 and rad(*Q) <= RMAX and ccw(P, Q): reach.add(Q)
east = sorted(p[0] for p in reach if p[1] == 0 and p[0] > 1)
print(east[0])                                   # 64

Extra Credit

Frankie stores food on pad AA. Every second, the food on each pad splits into six equal portions that jump to its six neighbours. After how many seconds N>2N>2 does pad AA hold less than 11 percent of the original amount?

Solution

The fraction left on AA after NN seconds is exactly the probability that a random walk on the lattice, stepping to a uniformly chosen neighbour each second, sits back at its start after NN steps. Propagating the distribution second by second, this return fraction falls below 11 percent for the first time at N=28.N = \boxed{28}. At N=27N=27 it is still 1.00%1.00\%, at N=28N=28 it is 0.97%0.97\%. (The source’s value is behind its paywall; this is my own.)

The computation

Diffuse the food directly: hold the amount on every pad and, each second, split each pad’s amount evenly to its six neighbours. Watch the amount back on AA until it drops below 11 percent.

from collections import defaultdict
cur = {(0, 0): 1.0}
for N in range(1, 30):
    nxt = defaultdict(float)
    for (a, b), m in cur.items():
        for da, db in NB: nxt[(a+da, b+db)] += m/6
    cur = nxt
    if N > 2 and cur[(0, 0)] < 0.01:
        print(N, round(cur[(0, 0)], 5)); break    # 28 0.00967