242 lines
5.8 KiB
TypeScript
242 lines
5.8 KiB
TypeScript
import {
|
|
RouteNames,
|
|
SpeedCompetitionCategoryResult,
|
|
} from '../models/Competition';
|
|
import {
|
|
Participant,
|
|
participantFromApiParticipant,
|
|
} from '../models/Participant';
|
|
|
|
export interface SpeedRoundParticipant {
|
|
id: string;
|
|
firstName: string;
|
|
hasWon: boolean;
|
|
}
|
|
|
|
export interface SpeedRoundPair {
|
|
laneA?: Participant;
|
|
laneB?: Participant;
|
|
winner?: 'A' | 'B';
|
|
}
|
|
|
|
export interface SpeedRound {
|
|
pairs: SpeedRoundPair[];
|
|
roundIndex: number;
|
|
roundName?: string;
|
|
}
|
|
|
|
export interface SpeedFlowchartResult {
|
|
rounds: SpeedRound[];
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {number} roundNumber
|
|
* @param {RouteNames} routeNames
|
|
* @return {string | undefined}
|
|
*/
|
|
function getRoundName(
|
|
roundNumber: number,
|
|
routeNames: RouteNames,
|
|
): string | undefined {
|
|
if (roundNumber < 2 || roundNumber > 6) return undefined;
|
|
|
|
return routeNames[roundNumber];
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {string} name
|
|
* @return {number}
|
|
*/
|
|
function getRoundRank(name: string): number {
|
|
const match = name.match(/1\/([842])/);
|
|
console.log(match);
|
|
if (match === undefined || match === null || match.length !== 2) {
|
|
return 2;
|
|
}
|
|
return parseInt(match[1]);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {SpeedRoundPair} pair
|
|
* @param {number} roundIndex
|
|
*/
|
|
function computeWinnerOfPair(pair: SpeedRoundPair, roundIndex: number) {
|
|
if (
|
|
pair.laneA?.results[roundIndex]?.rank === undefined ||
|
|
pair.laneB?.results[roundIndex]?.rank === undefined
|
|
)
|
|
return;
|
|
|
|
if (pair.winner === undefined) {
|
|
pair.winner =
|
|
pair.laneA.results[roundIndex].rank > pair.laneB.results[roundIndex].rank
|
|
? 'B'
|
|
: 'A';
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {SpeedRoundPair} pair
|
|
* @param {number} roundNumber
|
|
* @return {Participant | undefined}
|
|
*/
|
|
function getWinnerOfPair(
|
|
pair: SpeedRoundPair,
|
|
roundNumber: number,
|
|
): Participant | undefined {
|
|
computeWinnerOfPair(pair, roundNumber);
|
|
return pair.winner === 'A' ? pair.laneA : pair.laneB;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {SpeedRoundPair} pair
|
|
* @param {number} roundNumber
|
|
* @return {Participant | undefined}
|
|
*/
|
|
function getLooserOfPair(
|
|
pair: SpeedRoundPair,
|
|
roundNumber: number,
|
|
): Participant | undefined {
|
|
computeWinnerOfPair(pair, roundNumber);
|
|
return pair.winner === 'A' ? pair.laneB : pair.laneA;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {number} roundIndex index of the new round
|
|
* @param {string} roundName name of the new round
|
|
* @param {SpeedRound} previousRound
|
|
* @param {boolean} takeLooser
|
|
* @return {SpeedRound}
|
|
*/
|
|
function computeRoundFromPreviousRound(
|
|
roundIndex: number,
|
|
roundName: string,
|
|
previousRound: SpeedRound,
|
|
takeLooser = false,
|
|
): SpeedRound {
|
|
const getAdvancingParticipant = takeLooser
|
|
? getLooserOfPair
|
|
: getWinnerOfPair;
|
|
const nextRoundPairs = new Array(previousRound.pairs.length / 2)
|
|
.fill(0)
|
|
.map((_, i) => {
|
|
return {
|
|
laneA: getAdvancingParticipant(
|
|
previousRound.pairs[i * 2],
|
|
previousRound.roundIndex,
|
|
),
|
|
laneB: getAdvancingParticipant(
|
|
previousRound.pairs[i * 2 + 1],
|
|
previousRound.roundIndex,
|
|
),
|
|
};
|
|
});
|
|
|
|
return {
|
|
pairs: nextRoundPairs,
|
|
roundIndex: roundIndex,
|
|
roundName: roundName,
|
|
};
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {SpeedCompetitionCategoryResult} result The result to process
|
|
* @return {SpeedFlowchartResult}
|
|
*/
|
|
export function convertResultsToSpeedFlowchartResult(
|
|
result: SpeedCompetitionCategoryResult,
|
|
): SpeedFlowchartResult {
|
|
const rounds: SpeedRound[] = [];
|
|
const convertedParticipants = result.participants
|
|
.map(fromApi => participantFromApiParticipant(fromApi))
|
|
// sort by qualification result
|
|
.sort((a, b) => a.results[0].rank - b.results[0].rank);
|
|
|
|
const roundIndices = Object.keys(result.route_names)
|
|
.map(number => parseInt(number))
|
|
.filter(number => number > 0);
|
|
|
|
console.log(`Have final rounds:`, roundIndices);
|
|
|
|
// process first round
|
|
const firstRoundName = getRoundName(roundIndices[0], result.route_names);
|
|
const firstRoundNumber = getRoundRank(
|
|
getRoundName(roundIndices[0], result.route_names) ?? '',
|
|
);
|
|
|
|
const getOpponent = (ofRank: number): Participant => {
|
|
return convertedParticipants[firstRoundNumber * 2 - 1 - ofRank];
|
|
};
|
|
|
|
// Should be:
|
|
// 0, 1, 2, 3, 4, 5, 6, 7
|
|
// - 1,16, 8, 9, 4,13, 5,12, 2,15, 7,10, 3,14, 6,11
|
|
// - 1, 8, 4, 5, 2, 7, 3, 6 for firstRoundNumber=8
|
|
// - 1, 4, 2, 3 for firstRoundNumber=4
|
|
// - 1, 2 for firstRoundNumber=2
|
|
// TODO: come up with a proper alogorithm maybe
|
|
const ranksOfLaneAInOrder = [
|
|
[1, 2],
|
|
[1, 4, 2, 3],
|
|
[1, 8, 4, 5, 2, 7, 3, 6],
|
|
][firstRoundNumber / 4];
|
|
console.log(ranksOfLaneAInOrder);
|
|
|
|
const firstRoundPairs = ranksOfLaneAInOrder.map(rank => {
|
|
return {
|
|
laneA: convertedParticipants[rank - 1],
|
|
laneB: getOpponent(rank - 1),
|
|
};
|
|
});
|
|
|
|
const firstRound: SpeedRound = {
|
|
pairs: firstRoundPairs,
|
|
roundIndex: roundIndices[0],
|
|
roundName: firstRoundName,
|
|
};
|
|
|
|
rounds.push(firstRound);
|
|
|
|
// compute following rounds
|
|
for (let i = 1; i < roundIndices.length - 2; i++) {
|
|
rounds.push(
|
|
computeRoundFromPreviousRound(
|
|
roundIndices[i],
|
|
result.route_names[roundIndices[i]] ?? '',
|
|
rounds[i - 1],
|
|
),
|
|
);
|
|
}
|
|
|
|
// compute final and semi final
|
|
const semifinalRoundIndex = roundIndices[roundIndices.length - 2];
|
|
const semifinal = computeRoundFromPreviousRound(
|
|
semifinalRoundIndex,
|
|
result.route_names[semifinalRoundIndex] ?? '',
|
|
rounds[rounds.length - 1],
|
|
true,
|
|
);
|
|
computeWinnerOfPair(semifinal.pairs[0], semifinalRoundIndex);
|
|
rounds.push(semifinal);
|
|
|
|
const finalRoundIndex = roundIndices[roundIndices.length - 1];
|
|
const final = computeRoundFromPreviousRound(
|
|
finalRoundIndex,
|
|
result.route_names[finalRoundIndex] ?? '',
|
|
rounds[rounds.length - 2],
|
|
);
|
|
computeWinnerOfPair(final.pairs[0], finalRoundIndex);
|
|
rounds.push(final);
|
|
|
|
return {
|
|
rounds: rounds,
|
|
};
|
|
}
|