R4.05.1 · Leaderboards — dive 1
ZADD and ZREVRANK.
A player's score goes in with ZADD; the rank comes out with ZREVRANK.
The score is the ranking key — the set orders by it, and the rank is a position in that order, computed
on read.
Grounding: echo/apps/codemojex/lib/codemojex/board.ex · Codemojex.Board.record/3
— the best-of ZADD to cm:<game>:board via the real EchoWire.Cmd builders.
ZREVRANK (0 = leader) and its mirror ZRANK.ZREVRANK counts from the top (0 = leader); ZRANK is the mirror from the bottom, and
the two add up to N−1.The leader is vega at 540 (ZREVRANK 0); the trailing
player is nori at 180 (ZREVRANK 7). No row stores a rank.
ZADD — the score is the write
leaderboards.md.txt · Core OperationsA sorted set holds members, each with a numeric score, and keeps them ordered by score. The whole write is
ZADD: a score and a member. Run ZADD on a member already on the board and its score
is overwritten, and the member is re-placed in the order. The score is the entire index — there is no
separate ranking column. A player's own score is read with ZSCORE, which is O(1).
ZADD leaderboard 540 "vega" # write a member and a score ZADD leaderboard 510 "mango" # re-running ZADD overwrites and re-places ZSCORE leaderboard "vega" # => 540 (O(1))
After three writes, reading the set high-to-low gives the leader first; reading it low-to-high gives the trailing player. The set maintains the order — nothing was sorted by hand.
There is no insert versus update: one verb does both. The score is the write, and the order is maintained for free.
ZREVRANK — the rank is a position
leaderboards.md.txt · Rank vs Reverse RankA rank is a player's position in the order, counted from one end. ZREVRANK counts from the top,
so the leader is rank 0. The rank is 0-based: rank 0 is first place, rank 1 is second. The set computes it by
walking the order to the member, which is O(log N). The rank is not stored anywhere — it is derived from
the score order on each read, so it is always exactly the current order; there is no snapshot to fall out of
date.
sora and
watch the board re-place her — the ZREVRANK falls out of the new order.ZADD for sora; the board re-orders and her ZREVRANK is read from the new
position.Each write is one ZADD; the rank is never written. A higher score moves
sora up, and every player she passes drops a place — none of them is rewritten, only their
computed rank differs on the next read.
ZRANK — the mirror from the bottom
leaderboards.md.txt · Rank vs Reverse RankZRANK is the same position counted from the other end — low-to-high, so the lowest score
is rank 0. For a board where higher is better, ZREVRANK is the rank a player wants to see;
ZRANK answers the opposite question. The two are mirrors of one position in the same order: if the
board holds N players, a member's ZRANK and ZREVRANK add up to N−1. Reading
either end leaves the set unchanged.
ZREVRANK leaderboard "vega" # => 0 (top of the order) ZRANK leaderboard "vega" # => 7 (the same position, from the bottom)
In codemojex — ZADD in Board.record/3
echo/apps/codemojex · board.ex · scoring.excodemojex is a Telegram emoji-guessing game on the same stack; its leaderboard is exactly
this. The competitive state is in Valkey, the board is one sorted set per game keyed
cm:<game>:board, and the score is the linear total from Codemojex.Scoring
— points = 100 - 20 * d per emoji at distance d, summed over six positions, out
of 600. When a guess is scored, Codemojex.Board.record/3 writes the player's best linear total to
the board.
old = hget_int(conn, k(game, "base"), player) new_base = max(old, base) ← fold to the best-so-far Cmd.hset(k(game, "base"), player, to_string(new_base)) |> Wire.run(conn) Cmd.zadd(k(game, "board")) |> Cmd.score(new_base, player) |> Wire.run(conn) ← ZADD cm:<game>:board score player
Notes on ValkeyZADD key score member adds or updates one
member in O(log N) and keeps the set ordered; ZREVRANK reads a 0-based rank, also O(log N) —
valkey.io/commands/zadd.
Cmd.zadd/1 and Cmd.score/3 are the real EchoWire.Cmd builders;
k(game, "board") is cm:<game>:board. The write is a best-of overwrite:
ZADD re-places the player at their highest base, never lowering it — the raw linear best is
the sole rank, no tier ladder, no first-mover bonus. The rank is read back later from the order, not stored.
Where EchoMQ ranks for real
A leaderboard is a generic sorted-set ranking, not the queue protocol. Where EchoMQ orders by a score is the
Queue pillar — work ranked by a packed schedule and priority score in the emq:{q}: keyspace.
Open the Queue pillar for the queue ranking built on the same score order.
ZADD writes a score and ZREVRANK reads a 0-based rank from the score order,
computed on read.
Codemojex.Board.record/3 writes each player's best linear total with
Cmd.zadd("cm:<game>:board") |> Cmd.score(new_base, player); the rank is the player's
position in that order on read.
The score is the write and the rank is the read; nothing stores a rank. codemojex's
Board.record/3 is that ZADD, with a best-of fold so a player's rank only ever
climbs.
References
sources · relatedSources
- Redis — ZADD — add or update a member's score; the single write that places a player in the order.
- Redis — ZREVRANK — a member's rank, 0-based from the top, computed on read.
- Redis — Sorted sets — the data type behind the board: members ordered by a numeric score.
Related in this course
- R4.05 · Leaderboardsthe module hub
- R4.05.2 · Top-N and around-methe two read shapes over this order
- R4.05.3 · The score-update pathupdating a score, the rank recomputed
- R4.03 · Composite priority scorespacking two axes into one score
- /echomq · the Queue pillarthe queue ranking on the same score order