Ranking
- 126
- games ranked
- 1,877
- comparisons
- 16%
- called a tie
- 93
- top score
Numbers underlined like thisEvery underlined number is read from the live database when the page loads, and changes as more comparisons accumulate. are read from the live database at page load and change as comparisons accumulate.
Latest update
What's changed?
Comparing with . Movement is measured among the 121 games ranked in both updates, so new entries do not create artificial movement.
- 4
- new entries
- 95
- games moved
- 0
- clearer ranks
New to the ranking
Biggest moves
- Arma 2#90 → #79
- Sudden Strike#43 → #33
- Command & Conquer: Generals#69 → #59
- Elden Ring#53 → #63
- Counter-Strike: Global Offensive#62 → #53
- Battlefield Vietnam#63 → #55
- Resident Evil#75 → #83
- Subnautica: Below Zero#98 → #90
- F.E.A.R.#61 → #68
- Persona 5 Royal#64 → #71
- Company of Heroes 2#80 → #73
- Inscryption#84 → #91
- Valorant#87 → #94
- Grand Theft Auto: Vice City#25 → #19
- Doom 3#29 → #35
Positions above refer to the shared games only. Small moves can reflect uncertainty, rather than a change in taste.
Becoming clearer
No narrower intervals recorded in both snapshots. Older snapshots may not include interval history.
1 games left the published ranking. Their comparison history is preserved.
How the ranking works
Everything starts with pairwise comparisons. Given two games, I simply select the one I prefer. Repeating that process enough times (1,877A live number, read from the current data. comparisons so far) provides the statistical model with enough information to estimate the relative strength of every game. Those strength estimates are then used to generate each game's score, ranking, and tier.
Comparisons
Each round shows two games and takes one of three answers: pick a winner, declare a tie, or skip (used when I don't remember a game well enough to judge it). Skips are recorded but carry no preference. Ties are currently about 16%A live number, read from the current data. of answers.
Pairs are chosen adaptively. A comparison teaches the most when the model cannot predict its answer, so the selector concentrates on close matchups among games it is still uncertain about. One pair in five is instead drawn uniformly at random. Random pairs also keep the comparison graph connected, and because the model had no hand in choosing them, they serve as the held-out sample its predictions are checked against. A game with fewer than two comparisons gets placement pairs against opponents of similar provisional strength.
The model
Strengths are estimated with a Davidson model, a standard paired-comparison model that handles ties. Each game i is assigned a real-valued strength θi, every matchup gets three probabilities (I pick i, I pick j, or I call it a tie), and whenever a winner IS picked the model reduces exactly to the classic Bradley-Terry form: the probability of preferring i over j is the logistic function of their strength difference,
P(i beats j | a winner is picked) = σ(θi − θj)where σ(x) = 1 / (1 + e−x). Equal strengths give 50%. A difference of 1 gives about 73%. The tie probability peaks for two equals and fades as the gap grows, with the overall tie propensity fitted from the data. And because the winner-picked formula above holds exactly no matter what, ties can never change what a gap means in odds, however common they become; a tie still counts as evidence that two games are close, it just cannot redefine the unit. The strengths are fitted by maximum likelihood over the whole log at once, so the result is independent of the order in which comparisons were made.
Maximum likelihood alone fails for a game that has never lost or tied: its likelihood increases monotonically in θ, so the estimate diverges (complete separation). To prevent this, every game receives a small virtual win and virtual loss against a fixed reference opponent at θ = 0, and the weight of that regularization is chosen fresh at every recomputation using a reserved calibration sample, while a separate evaluation sample checks its predictions (the advanced view shows exactly how). A still-undefeated game's strength is a lower bound, so its score is shown with an arrow (90↑A live number, read from the current data.) that disappears at its first loss or tie (either one ends the runaway and makes the estimate finite).
The score scale
The displayed score is a fixed linear map of the strength θ:
score = 50 + B·θBoth parts are declared once and frozen, never fitted, so no score ever moves because the scale was redrawn. A = 50: an average game, and a brand-new one with no evidence yet, sits at 50, the middle of my list. Not review-culture's "50 = mediocre"; the median of a library I love is a 50 here, and that is the point. B is the unit, declared by odds: a 2-point gap means I'd pick one game over the other about two times out of three (2:1). The model's calibration is checked on reserved comparisons. Observed frequencies can differ, especially with sparse evidence. Points add as odds multiply:
Scores run 0 to 100, but the ends are asymptotic: reaching them would take overwhelming one-sided evidence, so every game sits inside rather than at the ceiling. Rank is this game's position once the list is ordered by the strength θ, the score is a fixed increasing map of that same θ, and tiers are cut from the rank, so the number, the rank, and the tier are three views of one ordering and never disagree.
Tiers
Tiers are quantiles of rank, not score thresholds: S is the top 8% of ranked games, A extends to 25%, B to 55%, C to 85%, and D is the remainder. Current distribution across 126A live number, read from the current data. ranked games:
The bands are deliberately uneven. Rank uncertainty in the middle of the list spans roughly 25 positions, about the width of a tier, so at that resolution the tier is the meaningful unit and a precise mid-list rank is mostly noise. Cutting by rank rather than by score also makes score order, rank order, and tier assignment consistent by construction.
A two-letter badge such as B/C marks a game whose tier is not stable under resampling: it lands in its home tier in fewer than 75% of bootstrap refits (next section). The first letter is the actual position; the second is the adjacent tier it could plausibly occupy. The flag is per-game, which is why split badges are not contiguous in the list. 14A live number, read from the current data. of 126A live number, read from the current data. games currently carry one.
Uncertainty
Each θ has a standard error from the observed information matrix, shown as ± in score points (two standard errors, scaled by the ruler's B). Overlapping intervals indicate uncertainty; they do not establish a tie. These approximate model intervals can undercover in simulation. Because the score is bounded to [0, 100], its interval is bounded with it: near the ends the ± is drawn as the clamped range it maps to, so an undefeated game's floor runs up to the ceiling rather than implying a score the scale can't hold. Rank ranges such as #13–28 are 80% intervals from a nonparametric bootstrap: the log is resampled with replacement and the whole model refitted 1000A live number, read from the current data. times, and the spread of resulting positions is reported.
A companion figure answers a different question, standing rather than strength: "beats a typical game" is the mean chance this game beats one drawn at random from the library, each matchup shrunk toward 50/50 by its uncertainty, so even a dominant game never reads 100%. Being field-relative, it can differ slightly from the strength ranking.
Recomputation
The comparison log is the only primary data. Scores, ranks, tiers, and intervals are derived values, recomputed from the full log on every refresh; nothing is updated incrementally and nothing is frozen. A game enters the ranking once it has at least 8 comparisons. Because the score map is fixed, a published number moves only with evidence: mostly the game's own new comparisons, plus a small joint-fit echo when its opponents' records change.
Back to the backlogWhat one click records
Every downstream number is a pure function of one append-only table. When a matchup is answered in the Versus tool, the browser constructs one row for comparisons and queues it. The columns that matter statistically:
| column | why it exists |
|---|---|
| left_id, right_id | Stored as displayed on screen, never sorted. Coin-flip orientation plus faithful storage is what makes side bias measurable at all; a canonicalized pair would destroy that information permanently. |
| outcome | left, right, tie ("too close to call", a real answer and a predicted outcome in its own right), or skip ("don't remember it", recorded but excluded from the likelihood entirely). |
| pair_strategy | information, random, or placement. The random subset is the only sample the model did not choose using its own beliefs, which makes it the only honest held-out set. Everything in the calibration machinery below rests on this column. |
| predicted_p, predicted_tie | The model's uncertainty-adjusted forecast at the moment of judgment: P(left wins given someone wins) and P(tie). Stored so "how often did I surprise the model" is answerable later without refitting history. model_version tags which model made the claim. |
| session, timing, context | Sitting id, in-session sequence, response time, input method: raw material for fatigue and decision-speed analyses later. |
Three storage guarantees carry the whole system. Append-only, enforced at the database level: comparison history can be added to but never edited or deleted, by anything. Undo is a retraction, not a deletion: pressing undo appends a retraction record (unique per comparison, so double-undo is a no-op) and the fit filters retracted judgments out; the original answer remains on the record as "answered, then taken back". Duplicate-proof and offline-safe: judgments buffer locally when offline and every save is idempotent, so a flaky connection that retries a successful save cannot double-count a judgment, and an undo racing an in-flight save resolves to a retraction rather than a silent loss.
Which games are eligible
Games become eligible after being played or dropped, or when marked Played before. An earlier playthrough keeps a game eligible during a replay or pause. Unfinished first playthroughs stay outside the pool, and the per-game exclusion still overrides eligibility. Comparisons involving a game that later leaves the pool stay in the log forever and are simply filtered out of the fit. Currently 126A live number, read from the current data. games hold a published rank.
Choosing the next pair
Three strategies, checked in order. Placement: any game seen fewer than 2 times gets priority, matched against one of the 8 games nearest it in the old hand ratings, so a newcomer's first match is informative rather than a foregone conclusion. Random, probability 0.2: one pair in five is uniform. This keeps the comparison graph connected (strengths are only identified within a connected component) and builds the held-out set. Information, the remaining ~80%: every possible pair is scored as
score(i,j) = H₃(p_win, p_tie, p_loss) · Var(θᵢ − θⱼ) · (1 + 1/√(1+nᵢ) + 1/√(1+nⱼ))H₃ is the entropy of the three-way forecast in bits (a dead-even pair with ties in play carries up to log₂3 ≈ 1.585 bits; a blowout a fraction of one): it asks can I predict the answer? Var(θᵢ − θⱼ) is the exact posterior variance of the gap, from the full covariance matrix below: it asks is there anything left to learn? A pair can look even for opposite reasons, two settled neighbours or two barely-seen games sitting at the prior default, and entropy alone cannot tell them apart; the gap variance can. The last factor is an under-comparison bonus decaying like 1/√n so no game starves. The chooser keeps the top 8 pairs and samples among them proportionally to score, with the last 200 served pairs on cooldown.
One deliberate wrinkle: the entropy uses plug-in probabilities while the stored forecasts use the uncertainty-adjusted ones. Shrinking before computing entropy would push every uncertain pair toward maximum entropy and double-count the uncertainty that the variance factor already prices. The factors stay orthogonal by construction.
The model: Davidson
Each game i gets a latent strength θᵢ; the library gets one tie affinity ν. With π = e^θ and D = πᵢ + πⱼ + ν·√(πᵢπⱼ), every matchup has a three-way forecast:
P(i wins) = πᵢ/D P(j wins) = πⱼ/D P(tie) = ν·√(πᵢπⱼ)/DDividing through by √(πᵢπⱼ) shows everything depends only on the gap d = θᵢ − θⱼ: the tie probability is ν / (2·cosh(d/2) + ν), maximal for two equals and fading as the pair separates. The property the whole site rests on:
P(i wins | someone wins) = σ(θᵢ − θⱼ)Conditional on a decisive pick, Davidson collapses exactly to Bradley-Terry, so the ruler's odds sentence stays a literal theorem "when I pick a winner" no matter how common ties become. Ties still inform the fit itself, a tie is evidence that two strengths are close and pulls them together like any other observation; what can never drift is the meaning of a gap in odds, and the half-win scale compression of earlier versions cannot recur. This exactness is why Davidson was chosen over Rao-Kupper (the threshold alternative, whose decisive-conditional is only approximately Bradley-Terry). Earlier model versions folded ties in as half a win each; that is a pseudo-likelihood that cannot predict a tie, cannot be scored on ties, and compresses the scale as ties grow. The fitted affinity is currently ν = 0.601A live number, read from the current data. (a dead-even pair ties about 23.1%A live number, read from the current data. of the time), against a tie rate of 16%A live number, read from the current data. in the comparisons the fit uses.
The likelihood
L(θ, ν) = Σ_wins log(π_winner / D) + Σ_ties log(ν·√(πᵢπⱼ) / D)The fitted parameters maximize the probability of the exact click history that happened. Each term is linear minus log-sum-exp in (θ, ln ν), hence concave; with the strictly concave anchor and ν prior added, the objective has exactly one maximum, so the answer cannot depend on where the optimizer starts (asserted on every simulation run to 1e-9). The likelihood is a product over picks, and products do not care about order, which is why the whole log is refit from scratch every time: unlike Elo's online updates, no early unlucky run can leave a permanent dent.
The anchor, solved for calibration
Plain maximum likelihood diverges on any game with no losses and no ties (complete separation: every increase of its θ raises the likelihood; even one tie ends it, because tie probability falls as the gap grows). The repair: every game receives c virtual wins and c virtual losses against a phantom fixed at θ = 0, adding c·[log σ(θᵢ) + log σ(−θᵢ)] per game. This makes the optimum unique and finite, pins the zero point, sends a no-data game to exactly θ = 0 (score 50), and makes the information matrix positive-definite so standard errors always exist.
The weight c is the one true hyperparameter, and it does not press evenly: roughly 40% of served comparisons are near-ties, which are coin flips and carry almost no information about the global stretch of the scale, so along that direction the anchor pulls nearly unopposed. A fixed weight was measurably wrong in both directions at different times: too heavy, and a predicted 68/32 pair realized at 88/12 (temperature 0.40); too light on a low-spread library, and chained noise over-disperses the scale (temperature ≈ 1.9 in simulation).
So every publish run solves for calibration directly. Define T by fitting P = σ(logit(p̂)/T) on the held-out random pairs: T = 1 means the model's stated odds match realized outcomes, T < 1 too timid, T > 1 overconfident. T is monotone decreasing in c, so T(c) = 1 has a unique root, found by bisection on ln c over [0.02, 8] in about a dozen diagnostic fits. The current published fit solved c = 0.208A live number, read from the current data. with T = 1.001A live number, read from the current data.. Two guard rails refuse publication outright: no root existing in range (a model-class misspecification no regularizer can fix), and the calibrated weight fitting the held-out data more than 0.02 nats worse than the best weight seen (calibration must never cost accuracy).
ν gets the same courtesy in miniature: a weak Gaussian prior on ln ν (centred on the observed affinity, worth less than a handful of ties) keeps it finite and sane when ties are scarce, and drowns immediately once they are not.
The optimizer
Damped Newton with a backtracking line search on the joint vector (θ₁…θₙ, ln ν). Concavity means the Newton direction always points uphill and the line search guarantees the log-likelihood never falls (a monotone flag asserts this on every fit); convergence is quadratic, typically 3 to 10 steps to machine precision (5 stepsA live number, read from the current data. on the latest published fit). θ is clamped to ±15 purely as a numerical guard rail: σ(15) is within 3·10⁻⁷ of 1, and only undefeated floors ever creep near it. The stationarity condition Newton solves reads cleanly: at the peak, every game's expected points equal its actual points, where points are wins plus half of ties and a game's expected points against an opponent are P(win) + P(tie)/2. The half-point for a tie is a consequence of the model, not an assumption inserted into it.
Uncertainty: the information matrix
At the maximum, certainty is curvature. The observed information H (negative Hessian of the penalized log-likelihood) is assembled over (θ, ln ν) jointly: per comparison it is the covariance form Aᵀ(diag q − qqᵀ)A with q the three-way forecast, positive semi-definite by construction, and the anchor and ν prior make the total strictly positive-definite. A Cholesky factorization gives the full inverse:
Σ = H⁻¹, se(θᵢ) = √Σᵢᵢ, Var(θᵢ − θⱼ) = Σᵢᵢ + Σⱼⱼ − 2ΣᵢⱼThree deliberate choices. The θ standard errors include the uncertainty in ν because the matrix is joint. The exact pair covariance is used wherever a gap's variance is needed: the θ-θ off-diagonals of H are nonpositive, and on a connected comparison graph (which the pipeline asserts before publishing) the resulting θ covariances come out nonnegative, with the fitter flooring the pair variance at zero as a final guard. That nonnegativity is why the old shortcut of summing two variances overstated gap variance, by ~60% for well-connected pairs. And the diagonal shortcut 1/√Hᵢᵢ is not used anywhere: it understates uncertainty by ~10% on average by ignoring the couplings.
Honesty about the error bars themselves: pairs are chosen adaptively using the same data that is later fitted, which flatters the information matrix somewhat. Simulation puts one-sigma coverage at roughly 65-75% against a nominal 68% at the solved anchor. The displayed ±2se intervals are near-nominal but should be read as approximate; the live mean displayed interval is ±2.4 ptsA live number, read from the current data. at one sigma against a published-score spread of 15.6A live number, read from the current data. points.
Predictions: plug-in vs marginal
Two probability calculations coexist on purpose. The plug-in forecast treats fitted parameters as exact and is used only inside the pair chooser's entropy. Every published claim about an outcome (predicted_p, predicted_tie, "beats a typical game") uses the marginal version, because pushing noisy point estimates through a steep sigmoid systematically overstates confidence. The correction is MacKay's Gaussian approximation:
P(i wins | decisive) = σ( (θᵢ − θⱼ) / √(1 + (π/8) · Var(θᵢ − θⱼ)) )with the exact gap variance from above; the full three-way forecast feeds the same shrunk gap through the Davidson formula, so the triple stays internally consistent (its decisive split equals the marginal, everything sums to one, and the shrink errs toward predicting more ties for uncertain pairs, which is the honest direction). The constant is π/8 ≈ 0.3927 (the probit-matching factor; checked against numerical integration to a few thousandths). "Beats a typical game" is the mean of the decisive-conditional marginal against every other ranked game, which is why even an undefeated game never reads 100%.
From strength to score
score = 50 + B·θ, B = 2/ln 2 = 2.8854Both constants are declared, never fitted. A = 50 puts θ = 0 (an average game, and the no-data prior) at the midpoint. B is the unit, declared in odds: a 2-point gap is a θ gap of ln 2, and σ(ln 2) = 2/3 exactly, so 2 points means 2:1 among decisive picks, 4 points 4:1, 6 points 8:1. The odds sentence is only worth its name if θ is calibrated, and since the calibration solve the anchor is chosen on calibration data. Separate evaluation data tests whether those probabilities generalize; the solve is not a guarantee about future outcomes.
Because θ is clamped to ±15, every score lies inside 50 ± 43.3, i.e. (6.7, 93.3): the endpoints 0 and 100 are asymptotes, unreachable by any amount of clicking. Fixing the ruler removes one whole source of drift (no score ever moves because the scale was redrawn), with one honest caveat: the anchor weight is re-solved from the log each publish, so the field can re-space slightly as calibration evidence accumulates, a deterministic drift of order 1/√n recorded in every snapshot, while preserving the declared model scale. An undefeated game's θ is a floor, not a measurement (only the phantom loss restrains it), so its score wears an up-arrow; winless mirrors with a down-arrow. Currently 0A live number, read from the current data. games sit on a floor; the best two-sided measurement is World of Warcraft at 93A live number, read from the current data., and the field bottoms out at 7A live number, read from the current data..
Ranks and tiers
Only games with at least 8 comparisons get published numbers; below that the number is too unstable to stand behind, its bootstrap interval spans half the list. (The gate is stability, not prior domination: at the solved anchor the prior carries only a few percent of even a four-comparison game's weight.) Published games are ranked by θ (the score is a monotone map of it, so the orderings cannot disagree), and tiers are quantiles of rank: S is the top 8%, A to 25%, B to 55%, C to 85%, D the rest. Rank cuts rather than score thresholds keep score order, rank order, and tier assignment consistent by construction and stop tiers drifting when the score distribution changes shape. The bands are uneven on purpose: mid-list rank uncertainty spans roughly a tier's width, so there the tier is the honest unit of position and a precise mid-list rank is mostly noise.
The bootstrap
Rank intervals come from a nonparametric bootstrap: resample the 1,838A live number, read from the current data. non-skip comparisons the fit uses with replacement, refit the entire model (θ and ν, at the solved anchor weight, warm-started since the optimum is unique), record every game's rank and tier, repeat 1000A live number, read from the current data. times with a seeded generator so reruns reproduce identical intervals. The 10th-90th percentile of finishing positions is the displayed 80% rank range; a game landing in its point-estimate tier in fewer than 75% of refits shows a split badge (its home tier plus its most common alternative). The badge is a per-game stability flag, not a position, which is why split badges are not contiguous in a list: two adjacent games can straddle the same line from opposite sides. Live: the median 80% interval is 10 positionsA live number, read from the current data. wide and 14A live number, read from the current data. of 126A live number, read from the current data. games carry a split badge.
One acknowledged approximation: resampling treats the log as exchangeable, but the rows were collected adaptively (each pair was chosen using earlier answers). The intervals are a good first-order picture of resampling noise, not an exact frequentist guarantee.
What gets published
A publish run recomputes everything above from the full log and updates every game's published record at once: score, its uncertainty in points, rank and its interval, tier and alternate, win/tie/loss record, floor/ceiling flags, win rate, and the model version that produced them. The update is all-or-nothing, so the site can never render a mixture of two fits. Every requested snapshot is also archived in full (model version, counts, fit quality, held-out metrics, the solved configuration, every game's parameters), the raw material for a future score-over-time graph. Publication is refused when the calibration guard rails trip.
Diagnostics and tripwires
Computed and printed on every fit, whether or not anything is written:
Held-out evaluation. The random sample is split before fitting: one part selects the calibration weight and a separate part evaluates it. Viewer splits keep each judge in only one diagnostic partition. Decisive evaluation pairs are scored by log-loss against a coin-flip baseline: currently 0.1445A live number, read from the current data. vs 0.6931A live number, read from the current data., a gain of +0.5486 natsA live number, read from the current data. per pair. Accuracy is reported but never headlined, because accuracy on random pairs mostly measures how far apart the games were, not model quality. New with the tie model: a three-way log-loss over all held-out rows including ties, against a predict-the-frequencies baseline, the first number that scores the tie model itself.
The tie profile. Predicted vs realized tie rate by gap bin, over the whole log. ν fixes the height of the tie curve; this table watches its shape. On the calibrating fit of 2026-07-13 it read: gap under 0.5: predicted 13.7%, realized 21.7%; gap 1-2: predicted 11.2%, realized 7.3%; gap 2-4: predicted 7.1%, realized 2.9%. Real ties are sharper than Davidson's e^(−d/2) tail: they cluster harder at zero and vanish faster with distance. Because tie observations enter the fit (each one pulls two strengths together), a misfit tie shape can nudge the strengths themselves, not just the tie forecasts; what it can never change is the decisive-conditional meaning of a gap. It is the standing tripwire for a steeper tie kernel in a future model version once enough ties accumulate to fit one honestly.
And the rest: side bias (left-card win share among decisive picks, measurable only because orientation is stored as displayed; ~49% currently, i.e. unbiased), comparison-graph connectivity (must be one component for strengths to be comparable), the anchor bisection trace with its solved weight, prequential calibration of the stored forecasts, and the settled count (games with se(θ) ≤ 0.5, about ±3 points at two sigma).
Known limitations and invariants
Statistical honesty means saying what is not established. The tails are extrapolation: the data can demonstrate that the top game beats the bottom game essentially always, but cannot distinguish 500:1 from 5000:1, so extreme score gaps are principled extrapolation on the declared odds scale rather than measurement. Preferences are assumed static: every comparison votes forever with equal weight; the snapshot history accumulates exactly the evidence needed to detect taste drift, and nothing models it until the data demands it. Repeat judgments are not independent: the same person re-answering a remembered matchup is correlated evidence; the 200-pair cooldown limits it, and the error bars are read as approximate partly for this reason. The tie kernel's shape misfits, as measured above. Each of these has a diagnostic attached; none has a responsible fix before more data exists.
And the invariants that make the whole thing trustworthy: the log is the only primary data and everything else is a rebuildable cache; refits are idempotent and order-independent; the ruler is a constant and the one data-driven knob is solved deterministically, printed with its evidence, stored in the snapshot, and guarded by the publication gate; a game's score is driven by its own evidence plus a small joint-fit echo from its opponents; and uncertainty is displayed, never hidden.
Back to the backlog