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++) { const [laneA, laneB] = finalSortedFirstRoundPairs[i]; if (laneA !== undefined) finalFirstRoundPairs.push(laneA); if (laneB !== undefined) finalFirstRoundPairs.push(laneB); } // 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; } }