231 lines
7.2 KiB
TypeScript
231 lines
7.2 KiB
TypeScript
import { FILE } from 'dns';
|
|
import { SpeedCompetitionCategoryResult } from '../models/Competition';
|
|
import { Participant } from '../models/Participant';
|
|
|
|
export interface SpeedRoundPair {
|
|
laneA?: Participant;
|
|
laneB?: Participant;
|
|
}
|
|
|
|
export interface SpeedRound {
|
|
pairs: SpeedRoundPair[];
|
|
roundIndex: number;
|
|
roundName?: string;
|
|
}
|
|
|
|
/**
|
|
* Class for use with speed flowcharts
|
|
*/
|
|
export class SpeedFlowchart {
|
|
private _result: SpeedCompetitionCategoryResult;
|
|
|
|
/**
|
|
*
|
|
* @param {SpeedCompetitionCategoryResult} result
|
|
*/
|
|
constructor(result: SpeedCompetitionCategoryResult) {
|
|
this._result = result;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @return {SpeedRound[]} list of speed rounds
|
|
*/
|
|
public _convert() {
|
|
const allData: SpeedRound[] = [];
|
|
|
|
const rounds =
|
|
Object.keys(this._result.route_names).length > 2
|
|
? this._result.route_names['2']?.includes('8')
|
|
? 2
|
|
: 1
|
|
: 0;
|
|
|
|
const setAorB = (pair: SpeedRoundPair, participant: Participant) => {
|
|
if (pair.laneA === undefined) pair.laneA = participant;
|
|
else pair.laneB = participant;
|
|
};
|
|
// console.log(this._result.route_names);
|
|
|
|
for (const round in this._result.route_names) {
|
|
if (
|
|
Object.keys(this._result.route_names).indexOf(round) >= 0 &&
|
|
parseInt(round) >= 0
|
|
) {
|
|
// console.log(round);
|
|
|
|
if (parseInt(round) === 0) {
|
|
// this is the first round
|
|
|
|
// find pairs (always worse vs. best (1-16; 1-15; ...)) (they are sorted by the rank of the better athlete (1-2-3-4-5-6-7-8)
|
|
|
|
const qualificationResults: Participant[] = [];
|
|
|
|
for (let x = 0; x < this._result.participants.length; x++) {
|
|
qualificationResults.push(this._result.participants[x]);
|
|
}
|
|
|
|
qualificationResults.sort(function (a, b) {
|
|
return (
|
|
parseInt(a.result_rank0 ?? '') - parseInt(b.result_rank0 ?? '')
|
|
);
|
|
});
|
|
|
|
const nextRoundPairs: SpeedRoundPair[] = [];
|
|
const totalMatches =
|
|
(Object.keys(this._result.route_names).length > 2
|
|
? this._result.route_names['2']?.includes('8')
|
|
? 2
|
|
: 1
|
|
: 0) + 2;
|
|
const nextRoundMatches = Math.pow(2, totalMatches - 1);
|
|
|
|
for (let i = 0; i < nextRoundMatches; i++) {
|
|
nextRoundPairs.push({
|
|
laneA: qualificationResults[i],
|
|
laneB: qualificationResults[nextRoundMatches * 2 - i - 1],
|
|
});
|
|
}
|
|
|
|
// build second round pairs (sorted by the rank of the better athlete and worst vs. best (1-8; 2-7; ... ))
|
|
|
|
const sortedFirstRoundPairs: [SpeedRoundPair?, SpeedRoundPair?][] =
|
|
[];
|
|
|
|
for (let i = 0; i < nextRoundMatches; i += 1) {
|
|
sortedFirstRoundPairs.push([
|
|
nextRoundPairs.shift(),
|
|
nextRoundPairs.pop(),
|
|
]);
|
|
}
|
|
|
|
// sort these pairs (containing two pairs of athletes) by the rank of the better athlete (1-4;2-3)
|
|
|
|
const finalSortedFirstRoundPairs = [];
|
|
|
|
for (let i = 0; i < nextRoundMatches / 4; i++) {
|
|
finalSortedFirstRoundPairs.push(sortedFirstRoundPairs[i]);
|
|
finalSortedFirstRoundPairs.push(
|
|
sortedFirstRoundPairs[nextRoundMatches / 2 - i - 1],
|
|
);
|
|
}
|
|
|
|
// convert the list of pairs of pairs of athletes back to a single list of pairs of athletes
|
|
|
|
const finalFirstRoundPairs: SpeedRoundPair[] = [];
|
|
|
|
for (let i = 0; i < finalSortedFirstRoundPairs.length; i++) {
|
|
if (finalSortedFirstRoundPairs[i][0] !== undefined)
|
|
finalFirstRoundPairs.push(finalSortedFirstRoundPairs[i][0]!);
|
|
if (finalSortedFirstRoundPairs[i][1] !== undefined)
|
|
finalFirstRoundPairs.push(finalSortedFirstRoundPairs[i][1]!);
|
|
}
|
|
|
|
// push the first round to all data
|
|
allData.push({
|
|
pairs: finalFirstRoundPairs,
|
|
roundIndex: 2,
|
|
roundName: this._result.route_names[2] ?? '',
|
|
});
|
|
|
|
// console.log(allData);
|
|
} else if (parseInt(round) > 0) {
|
|
// this is not the first round
|
|
const nextRound: SpeedRound = {
|
|
pairs: [],
|
|
roundIndex: -1,
|
|
roundName: '',
|
|
};
|
|
|
|
// only used when the current round is the 1/2 final
|
|
const smallFinal: SpeedRoundPair = {};
|
|
const Final: SpeedRoundPair = {};
|
|
|
|
for (
|
|
let i = 0;
|
|
i < allData[allData.length - 1].pairs.length;
|
|
i += 1
|
|
) {
|
|
const thisPair: SpeedRoundPair =
|
|
allData[allData.length - 1].pairs[i];
|
|
let thisWinner;
|
|
let thisLooser;
|
|
const thisWinnerIsFirstOfNewPair = i % 2 === 0;
|
|
|
|
if (thisPair.laneA === undefined || thisPair.laneB === undefined) {
|
|
continue;
|
|
}
|
|
|
|
if (thisWinnerIsFirstOfNewPair) {
|
|
nextRound.pairs.push({});
|
|
}
|
|
|
|
if (
|
|
Object.keys(thisPair.laneA).indexOf('result_rank' + round) < 0 ||
|
|
Object.keys(thisPair.laneB).indexOf('result_rank' + round) < 0
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
if (
|
|
parseInt(thisPair.laneA['result_rank' + round] as string) <
|
|
parseInt(thisPair.laneB['result_rank' + round] as string)
|
|
) {
|
|
thisWinner = thisPair.laneA;
|
|
thisLooser = thisPair.laneB;
|
|
} else if (
|
|
parseInt(thisPair.laneA['result_rank' + round] as string) >
|
|
parseInt(thisPair.laneB['result_rank' + round] as string)
|
|
) {
|
|
thisWinner = thisPair.laneB;
|
|
thisLooser = thisPair.laneA;
|
|
} else {
|
|
// no result yet!!
|
|
/* console.log(
|
|
'got no winner yet, rank 0: ' +
|
|
thisPair.laneA['result_rank' + round] +
|
|
' rank 1: ' +
|
|
thisPair.laneB['result_rank' + round],
|
|
);*/
|
|
continue;
|
|
}
|
|
|
|
// console.log(thisWinner['firstname'] + ' has won in round ' + round);
|
|
|
|
if (parseInt(round) - rounds === 2) {
|
|
// if we are in the 1/2 final
|
|
setAorB(Final, thisWinner);
|
|
setAorB(smallFinal, thisLooser);
|
|
} else {
|
|
setAorB(nextRound.pairs[nextRound.pairs.length - 1], thisWinner);
|
|
}
|
|
}
|
|
|
|
if (smallFinal.laneA !== undefined && Final.laneA !== undefined) {
|
|
// Final
|
|
allData.push({
|
|
pairs: [Final],
|
|
roundIndex: parseInt(round) + 2,
|
|
roundName:
|
|
this._result.route_names[String(parseInt(round) + 2)] +
|
|
' / ' +
|
|
this._result.route_names[String(parseInt(round) + 1)],
|
|
});
|
|
// small Final
|
|
allData.push({
|
|
pairs: [smallFinal],
|
|
roundIndex: parseInt(round) + 1,
|
|
});
|
|
} else {
|
|
nextRound.roundIndex = parseInt(round) + 1;
|
|
nextRound.roundName = this._result.route_names[parseInt(round) + 1];
|
|
allData.push(nextRound);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return allData;
|
|
}
|
|
}
|