brackt/app/lib/__tests__/afl-wildcard-reseed.test.ts
Claude b566c5f1a5
Re-seed AFL Wildcard winners into the Elimination Finals
The two Wildcard Round winners were crossed into the Elimination Finals by
which game they came out of — the 7v10 winner always met 6th and the 8v9
winner always met 5th. The AFL pairs those games by ladder position, as the
classic final eight pairs 5v8 and 6v7: the higher host draws the
lower-ranked survivor. So when 10th wins through, 5th should meet 10th, not
the 8v9 winner.

Placement now resolves both games together. A 7v10 winner is placed as soon
as it is decided (7th outranks either possible opponent, 10th is outranked
by both), while an 8v9 winner is held until the other game is decided rather
than being placed and later moved, so results can be entered in either
order.

The simulator paired the Elimination Finals the same fixed way, which biased
every projection that ran off an undecided Wildcard Round; it now re-seeds
too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VDbHrCce1UhahbkwKkc7hK
2026-09-04 15:13:13 +00:00

117 lines
4.1 KiB
TypeScript

/**
* The AFL Wildcard winners are re-seeded into the Elimination Finals by ladder position
* (5th draws the lower-ranked winner, 6th the higher-ranked one) rather than crossing
* over from a fixed Wildcard match. These tests pin that mapping for every combination
* of results, and for either order of entry.
*/
import { describe, it, expect } from "vitest";
import {
resolveAflWildcardPlacements,
AFL_WILDCARD_DRAW,
AFL_ELIMINATION_HOSTS,
type AflWildcardResult,
} from "../afl-wildcard-reseed";
/** Both Wildcard games decided, addressed by the seed that won each. */
function bothDecided(match1Winner: 7 | 10, match2Winner: 8 | 9): AflWildcardResult[] {
return [
{ matchNumber: 1, winnerSlot: match1Winner === 7 ? 1 : 2 },
{ matchNumber: 2, winnerSlot: match2Winner === 8 ? 1 : 2 },
];
}
/** Elimination Finals match number each winning seed was sent to. */
function slotsBySeed(results: AflWildcardResult[]): Record<number, number> {
return Object.fromEntries(
resolveAflWildcardPlacements(results).map((p) => [p.seed, p.eliminationMatchNumber])
);
}
describe("AFL Wildcard draw constants", () => {
it("draws 7v10 and 8v9", () => {
expect(AFL_WILDCARD_DRAW[1]).toEqual([7, 10]);
expect(AFL_WILDCARD_DRAW[2]).toEqual([8, 9]);
});
it("hosts the Elimination Finals with seeds 5 and 6", () => {
expect(AFL_ELIMINATION_HOSTS[1]).toBe(5);
expect(AFL_ELIMINATION_HOSTS[2]).toBe(6);
});
});
describe("resolveAflWildcardPlacements", () => {
it("sends the higher-ranked winner to 6th and the lower to 5th (7 and 8 win)", () => {
expect(slotsBySeed(bothDecided(7, 8))).toEqual({ 7: 2, 8: 1 });
});
it("re-seeds when the lower seed wins the 7v10 game (10 and 8 win)", () => {
// The bug this replaces sent the 7v10 winner to 6th regardless, pairing 5th with
// 8th and handing 6th the weakest survivor.
expect(slotsBySeed(bothDecided(10, 8))).toEqual({ 8: 2, 10: 1 });
});
it("re-seeds when the lower seed wins the 8v9 game (7 and 9 win)", () => {
expect(slotsBySeed(bothDecided(7, 9))).toEqual({ 7: 2, 9: 1 });
});
it("re-seeds when both lower seeds win (10 and 9 win)", () => {
expect(slotsBySeed(bothDecided(10, 9))).toEqual({ 9: 2, 10: 1 });
});
it("places the 7v10 winner alone, since its rank is settled either way", () => {
// 7th outranks both possible 8v9 winners; 10th is outranked by both.
expect(slotsBySeed([
{ matchNumber: 1, winnerSlot: 1 },
{ matchNumber: 2, winnerSlot: null },
])).toEqual({ 7: 2 });
expect(slotsBySeed([
{ matchNumber: 1, winnerSlot: 2 },
{ matchNumber: 2, winnerSlot: null },
])).toEqual({ 10: 1 });
});
it("holds an 8v9 winner back until the 7v10 game is decided", () => {
// 8th and 9th both sit between 7th and 10th, so either slot is still possible.
expect(slotsBySeed([
{ matchNumber: 1, winnerSlot: null },
{ matchNumber: 2, winnerSlot: 1 },
])).toEqual({});
expect(slotsBySeed([
{ matchNumber: 1, winnerSlot: null },
{ matchNumber: 2, winnerSlot: 2 },
])).toEqual({});
});
it("places nothing while both games are undecided", () => {
expect(resolveAflWildcardPlacements([
{ matchNumber: 1, winnerSlot: null },
{ matchNumber: 2, winnerSlot: null },
])).toEqual([]);
});
it("gives the same answer whichever result is entered first", () => {
for (const m1 of [7, 10] as const) {
for (const m2 of [8, 9] as const) {
const final = slotsBySeed(bothDecided(m1, m2));
// Whatever a single result places must survive the second result unchanged.
const m1First = slotsBySeed([
{ matchNumber: 1, winnerSlot: m1 === 7 ? 1 : 2 },
{ matchNumber: 2, winnerSlot: null },
]);
for (const [seed, slot] of Object.entries(m1First)) {
expect(final[Number(seed)]).toBe(slot);
}
}
}
});
it("rejects a match number outside the Wildcard draw", () => {
expect(() => resolveAflWildcardPlacements([{ matchNumber: 3, winnerSlot: 1 }])).toThrow(
/Unknown AFL Wildcard Round match number 3/
);
});
});