Floyd’s cycle detection, walked step by step on a straight tail feeding into a loop — the ρ shape the algorithm is named for. A tortoise steps one node per tick, a hare steps two; phase one runs until they land on the same node, which is guaranteed once both are inside the loop. Phase two resets the hare to the head and both walkers now step one node per tick — and they meet again exactly at the loop’s entrance.
That second meeting is the part every explanation asserts and few show: the distance from the head to the entrance (μ) is provably the same as the distance from the phase-one meeting point forward to the entrance. Once the walk finishes, a ribbon draws both spans under the track so the equality is visible instead of taken on faith.
Tune tail length (μ) and loop length (λ), or hit randomize. Step through one tick at a time or let it autoplay at a fixed rate.
Reuse
src/rho.js is a framework-free ES module with two exports:
makeRho(mu, lambda)— builds thenextpointer array for a rho-shaped sequence:mutail nodes thenlambdaloop nodes, wired so the last loop node points back to the first.floyd(next, start)— runs Floyd’s algorithm over anynextarray (not just one frommakeRho) and returns{ mu, lambda, entrance, seekMeet, trace }.traceis a frame per algorithm tick —{ tag: 'seek' | 'locate', tortoise, hare }— which is what makes it animatable; step through it on any renderer, same shape asastar-grid’svisitedOrder.
No dependencies, no rendering or timers in the module — canvas drawing and
the play/step controls in demo/ are reference code, not the reusable
piece.
Gotchas
floydworks over anynextmapping, not just rho shapes — pass a pointer array built some other way (e.g.x -> f(x) mod n) and it still detects the cycle.makeRhois just the generator used for this demo’s controllable, guaranteed-cyclic graphs.- The demo bundles its own copy of
rho.js(self-contained by contract); re-copy after editingsrc/. - μ = 0 is a valid, slightly odd case: the walk starts already inside the loop, so phase two ends immediately at node 0 — the ribbon’s tail span collapses to a point, which is correct, not a bug.