← Back to app

How the Algorithms Work

The Favourite Colour app offers two ranking methods. Both present pairs of colours for you to compare; they differ in which pairs are shown and how the final ranking is built.

Tennis Ladder — Merge Sort

The Tennis Ladder method works like a merge sort tournament. Colours are randomly split into pairs; the winner of each pair advances. Winners are then merged with other winners, and so on, until a complete ranking emerges.

The metaphor: imagine colours as players on a tennis ladder. Initially every player is their own top seed. Through a series of head-to-head matches, players "climb" or "fall" the ladder until the final order is settled.

Key properties

Step-by-step example (4 colours)

Suppose the colours are 🔴 Red, 🟢 Green, 🔵 Blue, 🟡 Yellow, shuffled randomly into [Green, Red, Yellow, Blue].

  1. Pass 1 — merge pairs of 1: Compare Green vs Red → you prefer Red. Compare Yellow vs Blue → you prefer Yellow. Sorted runs: [Red, Green] and [Yellow, Blue].
  2. Pass 2 — merge pairs of 2: Merge [Red, Green] with [Yellow, Blue]. Compare Red vs Yellow → prefer Red. Compare Green vs Yellow → prefer Yellow. Flush Blue. Final: [Red, Yellow, Green, Blue].

Total: 4 comparisons for 4 colours (optimal).

Flow diagram

flowchart TD A([Start]) --> B[Shuffle colours randomly] B --> C[Each colour is a sorted run of size 1] C --> D{Queue has ≥ 2 runs?} D -- Yes --> E[Take the first two runs A and B] E --> F{Both A and B have\nelements remaining?} F -- Yes --> G[Compare front of A\nvs front of B] G --> H{User picks\nwhich colour?} H -- Prefers A --> I[Move A's front\nto merged result] H -- Prefers B --> J[Move B's front\nto merged result] I --> F J --> F F -- No --> K[Flush remaining elements\nfrom the non-empty side] K --> L[Push merged run\nto back of queue] L --> D D -- No → 1 run left --> M([Done — final ranking complete!]) style A fill:#c0392b,color:#fff style M fill:#27ae60,color:#fff

Why merge sort?

Comparison-based sorting requires at least O(n log n) comparisons in the worst case — merge sort achieves this optimally. For 8 colours that is ~24 questions; for 16 colours ~64; for 64 colours ~384. This is the minimum number of questions needed to produce a complete, correct ranking.

Chess Ranking — Elo Rating System

The Chess Ranking method adapts the Elo rating system, originally designed for chess players, to colour preferences. Every colour starts with a rating of 1500. After each comparison, the winner gains rating points and the loser loses them. The amount gained or lost depends on how surprising the outcome was.

The Elo formula

Expected score for A: E_A = 1 / (1 + 10^((R_B − R_A) / 400))
New rating for A: R_A′ = R_A + K × (S_A − E_A)

Where:
R_A, R_B = current ratings of colours A and B
S_A = 1 if A wins, 0 if B wins
K = 32 (how quickly ratings adjust)

If two colours have similar ratings and the comparison result is a surprise, ratings shift a lot. If one colour is already rated much higher and wins as expected, ratings change only a little.

Pair selection strategy

To maximise the information gained per comparison, the algorithm selects pairs as follows:

  1. Find the colour that has been compared the fewest times (the "anchor").
  2. Among all other colours, find the one whose rating is closest to the anchor's.
  3. This pair is the most informative: evenly-matched colours produce the most rating movement.

Stopping criterion

The session ends once every colour has been compared at least k times, where k = max(3, ⌈log₂(n)⌉). For 16 colours this is 4 comparisons each, for a total of ~64 comparisons — the same order as Tennis Ladder.

Flow diagram

flowchart TD A([Start]) --> B[Assign rating 1500 to\nevery colour] B --> C[Select pair: anchor = fewest\ncomparisons, opponent = closest\nElo rating to anchor] C --> D[Show pair to user] D --> E{User picks\nwhich colour?} E -- Colour A --> F[S_A=1, S_B=0] E -- Colour B --> G[S_A=0, S_B=1] F --> H[Update:\nR_A′ = R_A + K·1−E_A\nR_B′ = R_B + K·0−E_B] G --> I[Update:\nR_A′ = R_A + K·0−E_A\nR_B′ = R_B + K·1−E_B] H --> J{Every colour compared\nat least k times?} I --> J J -- No --> C J -- Yes --> K([Done — rank by final Elo rating]) style A fill:#c0392b,color:#fff style K fill:#27ae60,color:#fff

Advantages of Elo

Side-by-side Comparison

quadrantChart title Characteristics of each algorithm x-axis Fewer comparisons --> More comparisons y-axis Partial ranking quality --> Complete ranking quality quadrant-1 "Best of both" quadrant-2 "Quick & complete" quadrant-3 "Quick but approximate" quadrant-4 "Thorough but long" "Tennis Ladder (8)": [0.15, 0.95] "Tennis Ladder (16)": [0.35, 0.95] "Chess Elo (8)": [0.12, 0.78] "Chess Elo (16)": [0.30, 0.82] "Chess Elo (64)": [0.55, 0.80] "Tennis Ladder (64)": [0.75, 0.96]
Property Tennis Ladder Chess Ranking
Algorithm Merge Sort Elo Rating
Comparisons (n=16) ~64 ~64
Result type Complete sort Rating-based rank
Early stopping Partial (via button) Natural (per-colour quota)
Best for Definitive ranking Large palettes

Session Persistence

All progress is saved to localStorage under the key favourite-colour-v1. The saved data includes:

On reload, the app detects the saved state and offers to resume. You can also clear the session and start fresh at any time.

No data is sent to any server. Everything stays in your browser.

Usage Analytics

The results page updates the browser URL to include an encoded results token, for example:

https://example.github.io/favouritecolour/?r=AS8fGC8xBg0fIA0JCyM_Bj8nVQ...

The token stores algorithm, favourite colour, and top-10 colours in a lightweight obfuscated format. If GoatCounter (or any analytics tool that records paths) is configured, events are sent to results/<token> so you can later decode aggregate outcome patterns.

To enable GoatCounter, replace YOUR_ACCOUNT in the <script> tag near the bottom of index.html with your GoatCounter site code.