Books · The Fiddler: Solutions
Chapter 68
Can You Bounce a Ball Like an AI?
A unit square rotates about its centre at constant angular speed. A ball moves at constant speed inside it, reflecting off each edge as though the square were momentarily still. On a special periodic path the ball touches only a single point of the square (never a corner). What is the shortest such path in one loop?
The Fiddler, Zach Wissner-Gross, February 7, 2025(original post)
Solution
Let the single contact point be the midpoint of an edge, a distance from the centre. Send the ball straight along the diameter through the centre and that midpoint. It strikes head-on (normal incidence) and reflects straight back. While it travels the length of that diameter, which for a unit square is the edge-to-edge distance , let the square turn a half-revolution; then the same edge, carrying the same point , has swung to the opposite side, and the ball meets again at normal incidence. The motion is a clean oscillation along a fixed diameter. One full period (the square returning to its start, a complete revolution) is two such crossings:
The computation
Simulate the real thing: a ball of unit speed inside the square spinning at angular speed (so a half-turn per unit-length crossing), reflecting off whichever edge it reaches. Launched along a diameter through an edge midpoint, it oscillates; the path measures per revolution, and every contact, viewed in the square’s own frame, falls on the same single point.
import numpy as np
w = np.pi; dt = 1e-5; ang0 = np.arange(4) * np.pi / 2
p = np.array([0.0, -0.5]); d = np.array([0.0, 1.0]) # start at a midpoint, moving in
t = path = 0.0; contacts = []; cool = 0
for _ in range(int(6.0 / dt)): # three full revolutions
N = np.c_[np.cos(w * t + ang0), np.sin(w * t + ang0)]
k = int(np.argmax(N @ p - 0.5))
if (N @ p - 0.5)[k] >= 0 and d @ N[k] > 0 and cool <= 0:
d = d - 2 * (d @ N[k]) * N[k] # reflect off edge k
c, s = np.cos(-w * t), np.sin(-w * t)
contacts.append((c * p[0] - s * p[1], s * p[0] + c * p[1])) # square frame
cool = int(0.2 / dt)
cool -= 1; p = p + d * dt; t += dt; path += dt
print(round(path / 3, 3), np.round(np.array(contacts), 3).tolist()) # 2.0 all (0,-0.5)
Extra Credit
What is the length of the next-shortest single-contact path?
Every contact happens at the point , which always sits on its orbit circle of radius , so all bounce points lie on that circle and the path is a closed polygon inscribed in it, the square turning through a fixed fraction of a revolution between hits. The diameter is the degenerate two-vertex case; the next paths are genuine inscribed stars whose chord directions still satisfy the reflect-as-if-stationary rule. Pinning down means solving those joint angle conditions, and the value sits behind the source’s paywall, so I leave as a stated open target rather than assert a length I cannot independently confirm.