Average player age at registration; age-matched round 1 for bracket-only tournaments
Optional age on signup and the desk. Auto-generated brackets pair neighbours by age with byes spread down the sheet; teams without an age are placed at random, fully random when no ages exist. Release 0.6.0. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01MB7nCCAscYsb3zzkT6LHZi
This commit is contained in:
1 parent
3f60a39e45
commit
103c221a12
10 files changed
+114
-19
No files matched your search
@@ -242,3 +242,36 @@ test('withdrawal mid-bracket shows as forfeits (not byes) and play continues to
|
||||
assert.ok(theirs.every(m => m.status === 'forfeit' && m.loser === quitter), 'every match of the quitter is a forfeit against them');
|
||||
assert.equal(t.matches.filter(m => m.status === 'bye' && m.round > 1).length, 0, 'no silent byes created by the withdrawal');
|
||||
});
|
||||
|
||||
test('age-matched round 1: neighbours in age play each other, byes spread evenly, everyone placed once', () => {
|
||||
const t = setup(0, { stages: ['bracket'] });
|
||||
const ages = [52, 23, 41, 38, 19, 60, 44, 25, 33, 29, null, 47];
|
||||
ages.forEach((a, i) => t.registerTeam({ name: `T${i + 1}`, players: 2, avgAge: a }));
|
||||
t.closeRegistration();
|
||||
const pairs = t.pairsByAge();
|
||||
assert.equal(pairs.length, 8); // 12 teams -> 16 bracket -> 8 matches
|
||||
assert.equal(pairs.filter(([a, b]) => a && b).length, 4); // 4 real matches, 4 byes
|
||||
const placed = pairs.flat().filter(Boolean);
|
||||
assert.equal(new Set(placed).size, 12);
|
||||
// every real match pairs two teams within 10 years of each other
|
||||
for (const [a, b] of pairs) if (a && b) {
|
||||
const x = t.teams.get(a).avgAge, y = t.teams.get(b).avgAge;
|
||||
if (x != null && y != null) assert.ok(Math.abs(x - y) <= 10, `${x} vs ${y}`);
|
||||
}
|
||||
// byes are spread, not bunched at the bottom
|
||||
const byeRows = pairs.map(([a, b], i) => (!a || !b) ? i : -1).filter(i => i >= 0);
|
||||
assert.ok(byeRows[0] < 4 && byeRows.at(-1) >= 4);
|
||||
t.generateBracketFromPairs(pairs, { type: 'double' });
|
||||
assert.throws(() => t.registerTeam({ name: 'Bad', players: 2, avgAge: 150 }, { force: true }));
|
||||
});
|
||||
|
||||
test('no ages at all: round-1 pairing is random, still valid', () => {
|
||||
const t = setup(8, { stages: ['bracket'] });
|
||||
t.closeRegistration();
|
||||
let seed = 3; const rnd = () => ((seed = (seed * 1664525 + 1013904223) >>> 0) / 2 ** 32);
|
||||
const pairs = t.pairsByAge(undefined, rnd);
|
||||
assert.equal(pairs.length, 4);
|
||||
assert.equal(new Set(pairs.flat()).size, 8);
|
||||
assert.notDeepEqual(pairs.flat(), ids(t), 'order should not simply be seed order');
|
||||
t.generateBracketFromPairs(pairs, { type: 'single' });
|
||||
});
|
||||
Reference in new issue
Block a user