RANDOM WALK
Pólya's Recurrence · ℤ¹ ℤ² ℤ³
Walk parameters
Steps 5,000
Seed
Controls
Speed ×1.0
Live stats — by dimension
1D
2D
3D
|Xₙ|
0
0
0
Returns
0
0
0
Distinct sites
1
1
1
# Quadrants touched
1/2
1/4
1/8
Pólya's theorem
1D & 2D: walker returns to origin with probability 1.
3D: only p₃ ≈ 0.3405 probability of ever returning.
⟨|Xn|²⟩ = n in every d.
Color = where in space
Each path segment is colored by the quadrant / octant of the walker. Newer steps brighter; older steps fade.
+x −x  (1D)
Q1 (++) Q2 (−+) Q3 (−−) Q4 (+−) (2D)
Keyboard
Space+drag pan 3D   R reset
B build   End jump to last
←/→ step ±1   ↑/↓ ±100
1D · ±1 on a line · scroll/drag · dbl-click reset x=0ret=0
2D · ℤ² (N/S/E/W)
ℤ² (N/S/E/W)
Knight's-move
ℤ² + obstacles
Hex lattice
Triangular lattice
Kurt's Step (forage)
Kurt's Forest
Homesick walker
Mood drift
Hungry walker
Momentum walker
Roaming homer
(0,0)ret=0
3D · drag rotate · space/shift+drag pan · scroll zoom · dbl-click reset (0,0,0)ret=0
0 / 5,000
Built for a bigger screen. This dashboard is dense — try landscape, or open it on a laptop.
ui.speedR.addEventListener('input', () => { const v = +ui.speedR.value; state.speed = Math.pow(2, v); ui.speedV.textContent = '×' + (state.speed >= 1 ? state.speed.toFixed(1) : state.speed.toFixed(2)); }); ui.presetBtns.forEach(b => { b.addEventListener('click', () => { ui.nstepsR.value = +b.dataset.steps; ui.nstepsV.textContent = (+ui.nstepsR.value).toLocaleString(); build(); }); }); document.getElementById('btn-random-seed').addEventListener('click', () => { const r = 1 + Math.floor(Math.random() * 10000); ui.seed.value = r; build(); }); ui.btnBuild.addEventListener('click', build); ui.btnPlay.addEventListener('click', () => { if (!state.built) { build(); state.playing = true; ui.btnPlay.textContent = '⏸ Pause'; ui.btnPlay.classList.add('active'); return; } state.playing = !state.playing; ui.btnPlay.textContent = state.playing ? '⏸ Pause' : '▶ Play'; ui.btnPlay.classList.toggle('active', state.playing); if (state.playing && state.step >= state.nSteps) state.step = 0; }); ui.btnStep.addEventListener('click', () => { if (!state.built) build(); state.step = Math.min(state.nSteps, state.step + 1); render(); }); ui.btnJump.addEventListener('click', () => { if (!state.built) build(); state.step = state.nSteps; render(); }); ui.btnReset.addEventListener('click', () => { state.step = 0; state.playing = false; ui.btnPlay.textContent = '▶ Play'; ui.btnPlay.classList.remove('active'); state.viz1D.yMaxShown = 8; state.viz2D.bb = null; if (state.built) render(); }); ui.scrub.addEventListener('input', () => { state.step = +ui.scrub.value; if (state.built) render(); }); ui.scrubPrev.addEventListener('click', () => { state.step = Math.max(0, state.step - Math.max(1, Math.floor(state.nSteps / 100))); if (state.built) render(); }); ui.scrubNext.addEventListener('click', () => { state.step = Math.min(state.nSteps, state.step + Math.max(1, Math.floor(state.nSteps / 100))); if (state.built) render(); }); window.addEventListener('keydown', e => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'SELECT') return; if (e.code === 'Space') { e.preventDefault(); state.spaceHeld = true; } else if (e.key === 'r' || e.key === 'R') ui.btnReset.click(); else if (e.key === 'b' || e.key === 'B') ui.btnBuild.click(); else if (e.key === 'ArrowRight') { state.step = Math.min(state.nSteps, state.step + 1); if (state.built) render(); } else if (e.key === 'ArrowLeft') { state.step = Math.max(0, state.step - 1); if (state.built) render(); } else if (e.key === 'ArrowUp') { state.step = Math.min(state.nSteps, state.step + 100); if (state.built) render(); } else if (e.key === 'ArrowDown') { state.step = Math.max(0, state.step - 100); if (state.built) render(); } else if (e.key === 'End') ui.btnJump.click(); }); window.addEventListener('keyup', e => { if (e.code === 'Space') state.spaceHeld = false; }); window.addEventListener('blur', () => { state.spaceHeld = false; }); window.addEventListener('resize', () => { if (state.threeCtx) state.threeCtx.onResize(); if (state.built) render(); }); init1D(); init2D(); init3D(); buildChartGrid(); ui.nstepsV.textContent = (+ui.nstepsR.value).toLocaleString(); ui.speedV.textContent = '×1.0'; build(); requestAnimationFrame(loop);