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
117 lines
4.1 KiB
TypeScript
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/
|
|
);
|
|
});
|
|
});
|