brackets-manager
Version:
A simple library to manage tournament brackets (round-robin, single elimination, double elimination)
185 lines • 8.93 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.Find = void 0;
const getter_1 = require("./base/getter");
const helpers = require("./helpers");
class Find extends getter_1.BaseGetter {
/**
* Gets the upper bracket (the only bracket if single elimination or the winner bracket in double elimination).
*
* @param stageId ID of the stage.
*/
async upperBracket(stageId) {
const stage = await this.storage.select('stage', stageId);
if (!stage)
throw Error('Stage not found.');
switch (stage.type) {
case 'round_robin':
throw Error('Round-robin stages do not have an upper bracket.');
case 'single_elimination':
case 'double_elimination':
return this.getUpperBracket(stageId);
default:
throw Error('Unknown stage type.');
}
}
/**
* Gets the loser bracket.
*
* @param stageId ID of the stage.
*/
async loserBracket(stageId) {
const stage = await this.storage.select('stage', stageId);
if (!stage)
throw Error('Stage not found.');
switch (stage.type) {
case 'round_robin':
throw Error('Round-robin stages do not have a loser bracket.');
case 'single_elimination':
throw Error('Single elimination stages do not have a loser bracket.');
case 'double_elimination':
const group = await this.getLoserBracket(stageId);
if (!group)
throw Error('Loser bracket not found.');
return group;
default:
throw Error('Unknown stage type.');
}
}
/**
* Returns the matches leading to the given match.
*
* If a `participantId` is given, the previous match _from their point of view_ is returned.
*
* @param matchId ID of the target match.
* @param participantId Optional ID of the participant.
*/
async previousMatches(matchId, participantId) {
const match = await this.storage.select('match', matchId);
if (!match)
throw Error('Match not found.');
const stage = await this.storage.select('stage', match.stage_id);
if (!stage)
throw Error('Stage not found.');
const group = await this.storage.select('group', match.group_id);
if (!group)
throw Error('Group not found.');
const round = await this.storage.select('round', match.round_id);
if (!round)
throw Error('Round not found.');
const matchLocation = helpers.getMatchLocation(stage.type, group.number);
const previousMatches = await this.getPreviousMatches(match, matchLocation, stage, round.number);
if (participantId !== undefined)
return previousMatches.filter(m => helpers.isParticipantInMatch(m, participantId));
return previousMatches;
}
/**
* Returns the matches following the given match.
*
* If a `participantId` is given:
* - If the participant won, the next match _from their point of view_ is returned.
* - If the participant is eliminated, no match is returned.
*
* @param matchId ID of the target match.
* @param participantId Optional ID of the participant.
*/
async nextMatches(matchId, participantId) {
const match = await this.storage.select('match', matchId);
if (!match)
throw Error('Match not found.');
const stage = await this.storage.select('stage', match.stage_id);
if (!stage)
throw Error('Stage not found.');
const group = await this.storage.select('group', match.group_id);
if (!group)
throw Error('Group not found.');
const { roundNumber, roundCount } = await this.getRoundPositionalInfo(match.round_id);
const matchLocation = helpers.getMatchLocation(stage.type, group.number);
const nextMatches = helpers.getNonNull(await this.getNextMatches(match, matchLocation, stage, roundNumber, roundCount));
if (participantId !== undefined) {
if (!helpers.isParticipantInMatch(match, participantId))
throw Error('The participant does not belong to this match.');
if (!helpers.isMatchStale(match))
throw Error('The match is not stale yet, so it is not possible to conclude the next matches for this participant.');
const loser = helpers.getLoser(match);
if (stage.type === 'single_elimination' && (loser === null || loser === void 0 ? void 0 : loser.id) === participantId)
return []; // Eliminated.
if (stage.type === 'double_elimination') {
// TODO: refactor `getNextMatches()` to return 1 next match per group. Then we can get rid of `getMatchesByGroupDoubleElimination()`.
const { winnerBracketMatch, loserBracketMatch, finalGroupMatch } = await this.getMatchesByGroupDoubleElimination(nextMatches, new Map([[group.id, group]]));
const winner = helpers.getWinner(match);
if (matchLocation === 'loser_bracket') {
if (participantId === (loser === null || loser === void 0 ? void 0 : loser.id))
return []; // Eliminated from lower bracket.
if (participantId === (winner === null || winner === void 0 ? void 0 : winner.id))
return loserBracketMatch ? [loserBracketMatch] : [];
}
else if (matchLocation === 'winner_bracket') {
if (!loserBracketMatch)
throw Error('All matches of winner bracket should lead to loser bracket.');
if (participantId === (loser === null || loser === void 0 ? void 0 : loser.id))
return [loserBracketMatch]; // Eliminated from upper bracket, going to lower bracket.
if (participantId === (winner === null || winner === void 0 ? void 0 : winner.id))
return winnerBracketMatch ? [winnerBracketMatch] : [];
}
else if (matchLocation === 'final_group') {
if (!finalGroupMatch)
throw Error('All matches of a final group should also lead to the final group.');
return [finalGroupMatch];
}
}
}
return nextMatches;
}
/**
* Finds a match in a given group. The match must have the given number in a round of which the number in group is given.
*
* **Example:** In group of id 1, give me the 4th match in the 3rd round.
*
* @param groupId ID of the group.
* @param roundNumber Number of the round in its parent group.
* @param matchNumber Number of the match in its parent round.
*/
async match(groupId, roundNumber, matchNumber) {
return this.findMatch(groupId, roundNumber, matchNumber);
}
/**
* Finds a match game based on its `id` or based on the combination of its `parent_id` and `number`.
*
* @param game Values to change in a match game.
*/
async matchGame(game) {
return this.findMatchGame(game);
}
/**
* Returns an object with 1 match per group type. Only supports double elimination.
*
* @param matches A list of matches.
* @param fetchedGroups A map of groups which were already fetched.
*/
async getMatchesByGroupDoubleElimination(matches, fetchedGroups) {
var _a, _b, _c;
const getGroup = async (groupId) => {
const existing = fetchedGroups.get(groupId);
if (existing)
return existing;
const group = await this.storage.select('group', groupId);
if (!group)
throw Error('Group not found.');
fetchedGroups.set(groupId, group);
return group;
};
let matchByGroupType = {};
for (const match of matches) {
const group = await getGroup(match.group_id);
matchByGroupType = {
winnerBracketMatch: (_a = matchByGroupType['winnerBracketMatch']) !== null && _a !== void 0 ? _a : (helpers.isWinnerBracket('double_elimination', group.number) ? match : undefined),
loserBracketMatch: (_b = matchByGroupType['loserBracketMatch']) !== null && _b !== void 0 ? _b : (helpers.isLoserBracket('double_elimination', group.number) ? match : undefined),
finalGroupMatch: (_c = matchByGroupType['finalGroupMatch']) !== null && _c !== void 0 ? _c : (helpers.isFinalGroup('double_elimination', group.number) ? match : undefined),
};
}
return matchByGroupType;
}
}
exports.Find = Find;
//# sourceMappingURL=find.js.map
;