Live model · Spotify shuffle
See how it actually works. Then change one thing.
Built for people who want to understand, not memorize. Every visual here is real code running.
- D1
- A3
- B4
- A1
- B3
- B1
- A4
- A6
- D2
- C1
- C2
- A2
- D3
- B2
- A5
- C3
- CH1 Artist A
- CH2 Artist B
- CH3 Artist C
- CH4 Artist D
fisherYates() on 16 songs, seed 0x3F2A. Done: the same artist plays back to back 3 times. Outlined pairs are the repeats.
Table
| Same artist back to back, per shuffle | Pure random | Spread out |
|---|---|---|
| 0 | 1.5% (30) | 57.8% (1155) |
| 1 | 9.1% (182) | 38.0% (759) |
| 2 | 18.9% (378) | 4.3% (86) |
| 3 | 26.4% (528) | 0.0% (0) |
| 4 | 22.2% (444) | 0.0% (0) |
| 5 | 13.1% (262) | 0.0% (0) |
| 6 | 5.8% (116) | 0.0% (0) |
| 7 | 2.4% (47) | 0.0% (0) |
| 8+ | 0.7% (13) | 0.0% (0) |
The rule
We didn't animate it. We ran it.
That play order came from the function below. The page calls it every time you press Shuffle again or move the slider. Nobody drew it, and every lesson on codebrew works this way: the frames are what the code produced.
Every change to it is checked against a plain-Python copy of the same algorithm, on hundreds of random playlists. They have to agree on every order.
The codeThis is the function that shuffled the playlist.
The runNow it runs, one line at a time.
The resultSame order the hero showed. Nobody drew it.
- D1
- A3
- B4
- A1
- B3
- B1
- A4
- A6
- D2
- C1
- C2
- A2
- D3
- B2
- A5
- C3
- CH1 Artist A
- CH2 Artist B
- CH3 Artist C
- CH4 Artist D
Done: the same artist plays back to back 3 times.
function fisherYates<T>(
songs: readonly T[],
rand: () => number,
trace?: Trace<T>
): T[] {
const order = songs.slice()
for (let i = order.length - 1; i > 0; i--) {
const j = Math.floor(rand() * (i + 1))
trace?.("pick", i, j, order) // to the stage
;[order[i], order[j]] = [order[j]!, order[i]!]
trace?.("swap", i, j, order) // to the stage
}
return order
}Spread out runs spreadShuffle()
function spreadShuffle<T extends { artist: string }>(
songs: readonly T[],
rand: () => number,
trace?: (artist: string, m: number, offset: number, placed: readonly { song: T; pos: number }[]) => void
): T[] {
// Space each artist's songs evenly across the playlist,
// starting at a random offset, with a little jitter.
const byArtist = new Map<string, T[]>()
for (const song of songs) {
if (!byArtist.has(song.artist)) byArtist.set(song.artist, [])
byArtist.get(song.artist)!.push(song)
}
const placed: { song: T; pos: number }[] = []
for (const [artist, mine] of byArtist) {
const m = mine.length
const order = fisherYates(mine, rand)
const offset = rand() / m
order.forEach((song, i) => {
const jitter = (rand() - 0.5) * (0.2 / m)
placed.push({ song, pos: offset + i / m + jitter })
})
trace?.(artist, m, offset, placed) // report the step to the stage
}
placed.sort((a, b) => a.pos - b.pos)
return placed.map((p) => p.song)
}Flagships
How it actually works
Models of things you use every day, running in your browser.
Spotify shuffle
Why does a truly random shuffle play the same artist twice in a row?
Fisher–Yates against a shuffle that spreads each artist out, run thousands of times and counted.
Autocorrect
How does “definately” become “definitely”?
Edit distance between the word you type and a dictionary, filled in as a DP grid.
Explore
Explore by mechanism
A window sliding, a grid filling, a frontier spreading. Pick the mechanism, then step through the problems that use it.
Hashing & Frequency Maps
Runs liveTrade memory for O(1) lookups, counts, and dedupe.
Dynamic Programming
Runs liveBreak a problem into overlapping subproblems and reuse the answers.
Graph Traversal (BFS & DFS)
Runs liveVisit every node once: breadth-first for shortest paths, depth-first for structure.
Two Pointers
Runs liveWalk a sorted array from both ends to skip impossible work.
Binary Search
Runs liveHalve the range that can hold the answer, on a sorted array or a range of answers.
Sliding Window
Runs liveTurn nested-loop scans of contiguous ranges into linear time.
Step through a problem
Requests
What should we explain next?
Name a thing you use and wonder about. The most-requested ones get built as models, checked, and published.
Prepping for a coding interview?
The same lessons, organized into tracks and company plans.