mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-05-20 18:29:48 -05:00
178 lines
5.4 KiB
TypeScript
178 lines
5.4 KiB
TypeScript
import { suite } from "uvu";
|
|
import * as assert from "uvu/assert";
|
|
import {
|
|
eliminationBracket,
|
|
fillParticipantsWithNullTillPowerOfTwo,
|
|
Match,
|
|
TeamIdentifier,
|
|
} from "./algorithms";
|
|
import { countRounds } from "./bracket";
|
|
|
|
const AmountOfTeams = suite("Amount of teams");
|
|
const Byes = suite("Byes");
|
|
const Seeds = suite("Seeds");
|
|
const BracketPaths = suite("Bracket path");
|
|
const FillParticipantsWithNull = suite(
|
|
"fillParticipantsWithNullTillPowerOfTwo()"
|
|
);
|
|
|
|
AmountOfTeams("Generates right amount of rounds (16 participants - SE)", () => {
|
|
const bracket16 = eliminationBracket(16, "SE");
|
|
assert.equal(removeMatchesWithByes(bracket16.winners).length, 15);
|
|
assert.equal(removeMatchesWithByes(bracket16.losers).length, 0);
|
|
});
|
|
|
|
AmountOfTeams("Generates right amount of rounds (16 participants - DE)", () => {
|
|
const bracket16 = eliminationBracket(16, "DE");
|
|
assert.equal(removeMatchesWithByes(bracket16.winners).length, 17);
|
|
assert.equal(removeMatchesWithByes(bracket16.losers).length, 14);
|
|
});
|
|
|
|
AmountOfTeams("Generates right amount of rounds (15 participants - DE)", () => {
|
|
const bracket15 = eliminationBracket(15, "DE");
|
|
assert.equal(removeMatchesWithByes(bracket15.winners).length, 16);
|
|
assert.equal(removeMatchesWithByes(bracket15.losers).length, 14); // one bye
|
|
});
|
|
|
|
AmountOfTeams("Generates right amount of rounds (17 participants - DE)", () => {
|
|
const bracket17 = eliminationBracket(17, "DE");
|
|
assert.equal(removeMatchesWithByes(bracket17.winners).length, 18);
|
|
assert.equal(removeMatchesWithByes(bracket17.losers).length, 30);
|
|
|
|
assert.equal(removeMatchesWithByes(bracket17.winners).length, 18);
|
|
assert.equal(removeMatchesWithByes(bracket17.losers).length, 30);
|
|
});
|
|
|
|
AmountOfTeams("Same amount of rounds as next power of two", () => {
|
|
const bracket17 = eliminationBracket(17, "DE");
|
|
const bracket32 = eliminationBracket(32, "DE");
|
|
assert.equal(bracket17.winners.length, bracket32.winners.length);
|
|
assert.equal(bracket17.losers.length, bracket32.losers.length);
|
|
});
|
|
|
|
Byes("Right amount of byes", () => {
|
|
const bracket17 = eliminationBracket(17, "DE");
|
|
assert.equal(countOpponentsWithByes(bracket17.winners), 15);
|
|
});
|
|
|
|
Byes("Correct team has bye", () => {
|
|
const bracket15 = eliminationBracket(15, "DE");
|
|
assert.equal(teamWithBye(bracket15.winners), 1);
|
|
});
|
|
|
|
Seeds("First and second seed are spread apart", () => {
|
|
const bracket16 = eliminationBracket(16, "DE");
|
|
assert.ok(
|
|
[bracket16.winners[0].upperTeam, bracket16.winners[0].lowerTeam].includes(
|
|
1
|
|
) ||
|
|
[bracket16.winners[0].upperTeam, bracket16.winners[0].lowerTeam].includes(
|
|
2
|
|
)
|
|
);
|
|
let lastMatchWithATeam = bracket16.winners[0];
|
|
for (const match of bracket16.winners) {
|
|
if (!match.upperTeam) break;
|
|
|
|
lastMatchWithATeam = match;
|
|
}
|
|
|
|
assert.ok(
|
|
[lastMatchWithATeam.upperTeam, lastMatchWithATeam.lowerTeam].includes(1) ||
|
|
[lastMatchWithATeam.upperTeam, lastMatchWithATeam.lowerTeam].includes(2)
|
|
);
|
|
});
|
|
|
|
BracketPaths("Following winners", () => {
|
|
const bracket16 = eliminationBracket(16, "DE");
|
|
const count = countRounds(bracket16);
|
|
|
|
let latest: Match = bracket16.winners[0];
|
|
let rounds = 0;
|
|
const roundIds = new Set();
|
|
while (latest) {
|
|
rounds++;
|
|
roundIds.add(latest.id);
|
|
if (!latest.winnerDestinationMatch) {
|
|
break;
|
|
}
|
|
assert.equal(latest.side, "winners");
|
|
assert.ok(latest.loserDestinationMatch);
|
|
latest = latest.winnerDestinationMatch;
|
|
}
|
|
|
|
// no duplicate rounds
|
|
assert.equal(roundIds.size, rounds);
|
|
|
|
assert.equal(rounds, count.winners);
|
|
});
|
|
|
|
BracketPaths("Following losers", () => {
|
|
const bracket16 = eliminationBracket(16, "DE");
|
|
const count = countRounds(bracket16);
|
|
|
|
let latest: Match | undefined = bracket16.winners[0];
|
|
let rounds = 0;
|
|
let countWinnerDestNoLoserDest = 0;
|
|
const roundIds = new Set();
|
|
while (latest) {
|
|
rounds++;
|
|
roundIds.add(latest.id);
|
|
if (!latest.winnerDestinationMatch && !latest.loserDestinationMatch) {
|
|
break;
|
|
}
|
|
if (latest.winnerDestinationMatch && !latest.loserDestinationMatch) {
|
|
countWinnerDestNoLoserDest++;
|
|
}
|
|
latest = latest.loserDestinationMatch ?? latest.winnerDestinationMatch;
|
|
}
|
|
|
|
// no duplicate rounds
|
|
assert.equal(roundIds.size, rounds);
|
|
|
|
assert.equal(rounds, count.losers + 3); // 3 rounds of winners: first round, grand finals & bracket reset
|
|
assert.equal(countWinnerDestNoLoserDest, count.losers);
|
|
});
|
|
|
|
FillParticipantsWithNull("17", () => {
|
|
const participants: TeamIdentifier[] = new Array(17)
|
|
.fill(null)
|
|
.map((_, i) => i + 1);
|
|
assert.equal(participants.length, 17);
|
|
fillParticipantsWithNullTillPowerOfTwo(participants);
|
|
assert.equal(participants.length, 32);
|
|
assert.equal(
|
|
participants.reduce((acc: number, cur) => acc + (cur === "BYE" ? 1 : 0), 0),
|
|
32 - 17
|
|
);
|
|
});
|
|
|
|
function countOpponentsWithByes(matches: Match[]) {
|
|
const byes = matches.filter(
|
|
(match) => match.upperTeam === "BYE" || match.lowerTeam === "BYE"
|
|
);
|
|
|
|
return byes.length;
|
|
}
|
|
|
|
function removeMatchesWithByes(matches: Match[]) {
|
|
return matches.filter(
|
|
(match) => match.upperTeam !== "BYE" && match.lowerTeam !== "BYE"
|
|
);
|
|
}
|
|
|
|
function teamWithBye(matches: Match[]) {
|
|
for (const match of matches) {
|
|
if (match.lowerTeam === "BYE") return match.upperTeam;
|
|
if (match.upperTeam === "BYE") return match.lowerTeam;
|
|
}
|
|
|
|
throw new Error("No team with a BYE");
|
|
}
|
|
|
|
AmountOfTeams.run();
|
|
Byes.run();
|
|
Seeds.run();
|
|
BracketPaths.run();
|
|
FillParticipantsWithNull.run();
|