tods-competition-factory 1.7.2 → 1.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/forge/generate.d.ts +7 -2
- package/dist/forge/generate.mjs +350 -223
- package/dist/forge/generate.mjs.map +1 -1
- package/dist/forge/query.mjs +1 -1
- package/dist/forge/query.mjs.map +1 -1
- package/dist/forge/transform.mjs +1 -1
- package/dist/forge/transform.mjs.map +1 -1
- package/dist/index.mjs +303 -187
- package/dist/index.mjs.map +1 -1
- package/dist/tods-competition-factory.development.cjs.js +336 -233
- package/dist/tods-competition-factory.development.cjs.js.map +1 -1
- package/dist/tods-competition-factory.production.cjs.min.js +1 -1
- package/dist/tods-competition-factory.production.cjs.min.js.map +1 -1
- package/package.json +4 -4
package/dist/forge/generate.mjs
CHANGED
|
@@ -1557,6 +1557,7 @@ function getMatchUpFormatAverageTimes({
|
|
|
1557
1557
|
});
|
|
1558
1558
|
}
|
|
1559
1559
|
|
|
1560
|
+
const DYNAMIC = "DYNAMIC";
|
|
1560
1561
|
const RANKING = "RANKING";
|
|
1561
1562
|
const RATING = "RATING";
|
|
1562
1563
|
const SCALE = "SCALE";
|
|
@@ -2962,7 +2963,7 @@ function getRoundMatchUps({
|
|
|
2962
2963
|
roundProfile[roundNumber].finishingRound = finishingRoundMap[roundNumber]?.finishingRound;
|
|
2963
2964
|
roundProfile[roundNumber].roundName = finishingRoundMap[roundNumber]?.roundName;
|
|
2964
2965
|
roundProfile[roundNumber].abbreviatedRoundName = finishingRoundMap[roundNumber]?.abbreviatedRoundName;
|
|
2965
|
-
roundProfile[roundNumber].finishingPositionRange = roundMatchUps[roundNumber][0]
|
|
2966
|
+
roundProfile[roundNumber].finishingPositionRange = roundMatchUps[roundNumber]?.[0]?.finishingPositionRange;
|
|
2966
2967
|
if (roundNumber === 1 || !roundProfile[roundNumber - 1]) {
|
|
2967
2968
|
const orderedDrawPositions = currentRoundDrawPositions.sort(numericSort);
|
|
2968
2969
|
const pairedDrawPositions = chunkArray(orderedDrawPositions, 2);
|
|
@@ -14092,6 +14093,7 @@ function generateCurtisConsolation(params) {
|
|
|
14092
14093
|
finishingPositionOffset,
|
|
14093
14094
|
structureName = MAIN,
|
|
14094
14095
|
stageSequence = 1,
|
|
14096
|
+
structureNameMap,
|
|
14095
14097
|
staggeredEntry,
|
|
14096
14098
|
stage = MAIN,
|
|
14097
14099
|
matchUpType,
|
|
@@ -14125,8 +14127,9 @@ function generateCurtisConsolation(params) {
|
|
|
14125
14127
|
const consolationItems = feedRoundOffsets.map((roundOffset, index) => {
|
|
14126
14128
|
const stageSequence2 = index + 1;
|
|
14127
14129
|
const { consolationStructure } = consolationFeedStructure({
|
|
14128
|
-
structureId: uuids?.pop(),
|
|
14129
14130
|
idPrefix: idPrefix && `${idPrefix}-c${index}`,
|
|
14131
|
+
structureId: uuids?.pop(),
|
|
14132
|
+
structureNameMap,
|
|
14130
14133
|
stageSequence: stageSequence2,
|
|
14131
14134
|
roundOffset,
|
|
14132
14135
|
matchUpType,
|
|
@@ -14155,9 +14158,9 @@ function generateCurtisConsolation(params) {
|
|
|
14155
14158
|
isMock
|
|
14156
14159
|
});
|
|
14157
14160
|
const playoffStructure = structureTemplate({
|
|
14161
|
+
structureName: structureNameMap?.[PLAY_OFF] || PLAY_OFF,
|
|
14158
14162
|
structureId: uuids?.pop(),
|
|
14159
14163
|
matchUps: playoffMatchUps,
|
|
14160
|
-
structureName: PLAY_OFF,
|
|
14161
14164
|
stageSequence: 2,
|
|
14162
14165
|
stage: PLAY_OFF,
|
|
14163
14166
|
matchUpType
|
|
@@ -14182,6 +14185,7 @@ function generateCurtisConsolation(params) {
|
|
|
14182
14185
|
}
|
|
14183
14186
|
function consolationFeedStructure({
|
|
14184
14187
|
stageSequence = 1,
|
|
14188
|
+
structureNameMap,
|
|
14185
14189
|
roundOffset = 0,
|
|
14186
14190
|
matchUpType,
|
|
14187
14191
|
structureId,
|
|
@@ -14202,7 +14206,8 @@ function consolationFeedStructure({
|
|
|
14202
14206
|
isMock,
|
|
14203
14207
|
uuids
|
|
14204
14208
|
});
|
|
14205
|
-
const
|
|
14209
|
+
const defaultName = `${CONSOLATION} ${index + 1}`;
|
|
14210
|
+
const structureName = structureNameMap?.[defaultName] || defaultName;
|
|
14206
14211
|
const consolationStructure = structureTemplate({
|
|
14207
14212
|
matchUps: consolationMatchUps,
|
|
14208
14213
|
stage: CONSOLATION,
|
|
@@ -14487,6 +14492,7 @@ function processPlayoffGroups({
|
|
|
14487
14492
|
}
|
|
14488
14493
|
const params = {
|
|
14489
14494
|
structureId: playoffGroup.structureId ?? uuids?.pop(),
|
|
14495
|
+
structureNameMap: playoffGroup.structureNameMap,
|
|
14490
14496
|
structureName: playoffGroup.structureName,
|
|
14491
14497
|
idPrefix: idPrefix && `${idPrefix}-po`,
|
|
14492
14498
|
appliedPolicies: policyDefinitions,
|
|
@@ -19605,98 +19611,6 @@ function generateVoluntaryConsolation(params) {
|
|
|
19605
19611
|
return generateVoluntaryConsolation$1({ participants: tournamentParticipants, ...params });
|
|
19606
19612
|
}
|
|
19607
19613
|
|
|
19608
|
-
function generateCandidate({
|
|
19609
|
-
maxIterations = 5e3,
|
|
19610
|
-
// cap the processing intensity of the candidate generator
|
|
19611
|
-
valueSortedPairings,
|
|
19612
|
-
// pairings sorted by value from low to high
|
|
19613
|
-
pairingValues,
|
|
19614
|
-
deltaObjects
|
|
19615
|
-
}) {
|
|
19616
|
-
const rankedMatchUpValues = Object.assign(
|
|
19617
|
-
{},
|
|
19618
|
-
...valueSortedPairings.map((rm) => ({ [rm.pairing]: rm.value }))
|
|
19619
|
-
);
|
|
19620
|
-
let candidate = roundCandidate({
|
|
19621
|
-
rankedMatchUpValues,
|
|
19622
|
-
valueSortedPairings,
|
|
19623
|
-
deltaObjects
|
|
19624
|
-
});
|
|
19625
|
-
let deltaCandidate = candidate;
|
|
19626
|
-
const actors = Object.keys(pairingValues);
|
|
19627
|
-
let candidatesCount = 0;
|
|
19628
|
-
let iterations;
|
|
19629
|
-
let opponentCount = actors.length;
|
|
19630
|
-
do {
|
|
19631
|
-
opponentCount -= 1;
|
|
19632
|
-
iterations = actors.length * opponentCount * valueSortedPairings.length / 2;
|
|
19633
|
-
} while (iterations > maxIterations && opponentCount > 2);
|
|
19634
|
-
const stipulatedPairs = [];
|
|
19635
|
-
actors.forEach((actor) => {
|
|
19636
|
-
const participantIdPairings = pairingValues[actor];
|
|
19637
|
-
participantIdPairings.slice(0, opponentCount).forEach((pairing) => {
|
|
19638
|
-
const stipulatedPair = pairingHash(actor, pairing.opponent);
|
|
19639
|
-
if (!stipulatedPairs.includes(stipulatedPair)) {
|
|
19640
|
-
const proposed = roundCandidate({
|
|
19641
|
-
// each roundCandidate starts with stipulated pairings
|
|
19642
|
-
stipulated: [[actor, pairing.opponent]],
|
|
19643
|
-
rankedMatchUpValues,
|
|
19644
|
-
valueSortedPairings,
|
|
19645
|
-
deltaObjects
|
|
19646
|
-
});
|
|
19647
|
-
if (proposed.maxDelta < deltaCandidate.maxDelta)
|
|
19648
|
-
deltaCandidate = proposed;
|
|
19649
|
-
if (proposed.value < candidate.value)
|
|
19650
|
-
candidate = proposed;
|
|
19651
|
-
stipulatedPairs.push(stipulatedPair);
|
|
19652
|
-
candidatesCount += 1;
|
|
19653
|
-
}
|
|
19654
|
-
});
|
|
19655
|
-
});
|
|
19656
|
-
return { candidate, deltaCandidate, candidatesCount, iterations };
|
|
19657
|
-
}
|
|
19658
|
-
function roundCandidate({
|
|
19659
|
-
rankedMatchUpValues,
|
|
19660
|
-
valueSortedPairings,
|
|
19661
|
-
stipulated = [],
|
|
19662
|
-
deltaObjects
|
|
19663
|
-
}) {
|
|
19664
|
-
const roundPlayers = [].concat(...stipulated);
|
|
19665
|
-
const participantIdPairings = [];
|
|
19666
|
-
let candidateValue = 0;
|
|
19667
|
-
stipulated.filter(Boolean).forEach((participantIds) => {
|
|
19668
|
-
const [p1, p2] = participantIds;
|
|
19669
|
-
const pairing = pairingHash(p1, p2);
|
|
19670
|
-
const value = rankedMatchUpValues[pairing];
|
|
19671
|
-
participantIdPairings.push({ participantIds, value });
|
|
19672
|
-
candidateValue += rankedMatchUpValues[pairing];
|
|
19673
|
-
});
|
|
19674
|
-
valueSortedPairings.forEach((rankedPairing) => {
|
|
19675
|
-
const participantIds = rankedPairing.pairing.split("|");
|
|
19676
|
-
const opponentExists = participantIds.reduce(
|
|
19677
|
-
(p, c) => roundPlayers.includes(c) || p,
|
|
19678
|
-
false
|
|
19679
|
-
);
|
|
19680
|
-
if (!opponentExists) {
|
|
19681
|
-
roundPlayers.push(...participantIds);
|
|
19682
|
-
const value = rankedPairing.value;
|
|
19683
|
-
candidateValue += value;
|
|
19684
|
-
participantIdPairings.push({ participantIds, value });
|
|
19685
|
-
}
|
|
19686
|
-
});
|
|
19687
|
-
participantIdPairings.sort((a, b) => a.value - b.value);
|
|
19688
|
-
const maxDelta = participantIdPairings.reduce((p, c) => {
|
|
19689
|
-
const [p1, p2] = c.participantIds;
|
|
19690
|
-
const hash = pairingHash(p1, p2);
|
|
19691
|
-
const delta = deltaObjects[hash];
|
|
19692
|
-
return delta > p ? delta : p;
|
|
19693
|
-
}, 0);
|
|
19694
|
-
return { value: candidateValue, participantIdPairings, maxDelta };
|
|
19695
|
-
}
|
|
19696
|
-
function pairingHash(id1, id2) {
|
|
19697
|
-
return [id1, id2].sort().join("|");
|
|
19698
|
-
}
|
|
19699
|
-
|
|
19700
19614
|
function generateAdHocMatchUps({
|
|
19701
19615
|
participantIdPairings,
|
|
19702
19616
|
addToStructure = true,
|
|
@@ -19714,21 +19628,30 @@ function generateAdHocMatchUps({
|
|
|
19714
19628
|
structureId = drawDefinition.structures?.[0]?.structureId;
|
|
19715
19629
|
if (typeof structureId !== "string")
|
|
19716
19630
|
return { error: MISSING_STRUCTURE_ID };
|
|
19717
|
-
|
|
19631
|
+
const structure = drawDefinition.structures?.find(
|
|
19632
|
+
(structure2) => structure2.structureId === structureId
|
|
19633
|
+
);
|
|
19634
|
+
if (!structure)
|
|
19635
|
+
return { error: STRUCTURE_NOT_FOUND };
|
|
19636
|
+
if (!matchUpsCount) {
|
|
19718
19637
|
const selectedEntries = drawDefinition?.entries?.filter((entry) => {
|
|
19719
19638
|
const entryStatus = entry.entryStatus;
|
|
19720
19639
|
return STRUCTURE_SELECTED_STATUSES.includes(entryStatus);
|
|
19721
19640
|
}) ?? [];
|
|
19722
|
-
|
|
19641
|
+
const roundMatchUpsCount = Math.floor(selectedEntries?.length / 2) || 1;
|
|
19642
|
+
if (newRound) {
|
|
19643
|
+
matchUpsCount = roundMatchUpsCount;
|
|
19644
|
+
} else {
|
|
19645
|
+
const maxRemaining = roundMatchUpsCount - (structure.matchUps?.length || 0);
|
|
19646
|
+
if (maxRemaining > 0)
|
|
19647
|
+
matchUpsCount = maxRemaining;
|
|
19648
|
+
}
|
|
19723
19649
|
}
|
|
19724
19650
|
if (participantIdPairings && !Array.isArray(participantIdPairings) || matchUpsCount && !isConvertableInteger(matchUpsCount) || matchUpIds && !Array.isArray(matchUpIds) || !participantIdPairings && !matchUpsCount) {
|
|
19725
19651
|
return { error: INVALID_VALUES, info: "matchUpsCount or pairings error" };
|
|
19726
19652
|
}
|
|
19727
|
-
const structure = drawDefinition?.structures?.find(
|
|
19728
|
-
(structure2) => structure2.structureId === structureId
|
|
19729
|
-
);
|
|
19730
19653
|
let structureHasRoundPositions;
|
|
19731
|
-
const existingMatchUps = structure
|
|
19654
|
+
const existingMatchUps = structure.matchUps ?? [];
|
|
19732
19655
|
const lastRoundNumber = existingMatchUps?.reduce(
|
|
19733
19656
|
(roundNumber2, matchUp) => {
|
|
19734
19657
|
if (matchUp.roundPosition)
|
|
@@ -19737,12 +19660,12 @@ function generateAdHocMatchUps({
|
|
|
19737
19660
|
},
|
|
19738
19661
|
0
|
|
19739
19662
|
);
|
|
19740
|
-
if (structure
|
|
19663
|
+
if (structure.structures || structureHasRoundPositions || structure.finishingPosition === ROUND_OUTCOME) {
|
|
19741
19664
|
return { error: INVALID_STRUCTURE };
|
|
19742
19665
|
}
|
|
19743
19666
|
if (roundNumber && roundNumber - 1 > (lastRoundNumber || 0))
|
|
19744
19667
|
return { error: INVALID_VALUES, info: "roundNumber error" };
|
|
19745
|
-
const nextRoundNumber = roundNumber ?? (newRound
|
|
19668
|
+
const nextRoundNumber = roundNumber ?? (newRound && (lastRoundNumber ?? 0) + 1 || lastRoundNumber || 1);
|
|
19746
19669
|
participantIdPairings = participantIdPairings ?? generateRange(0, matchUpsCount).map(() => ({
|
|
19747
19670
|
participantIds: [void 0, void 0]
|
|
19748
19671
|
}));
|
|
@@ -19822,9 +19745,311 @@ function addAdHocMatchUps({
|
|
|
19822
19745
|
return { ...SUCCESS };
|
|
19823
19746
|
}
|
|
19824
19747
|
|
|
19825
|
-
|
|
19826
|
-
|
|
19748
|
+
function generateCandidate({
|
|
19749
|
+
maxIterations = 4e3,
|
|
19750
|
+
// cap the processing intensity of the candidate generator
|
|
19751
|
+
valueSortedPairings,
|
|
19752
|
+
// pairings sorted by value from low to high
|
|
19753
|
+
pairingValues,
|
|
19754
|
+
valueObjects,
|
|
19755
|
+
deltaObjects
|
|
19756
|
+
}) {
|
|
19757
|
+
const pairingValueMap = Object.assign(
|
|
19758
|
+
{},
|
|
19759
|
+
...valueSortedPairings.map((rm) => ({ [rm.pairing]: rm.value }))
|
|
19760
|
+
);
|
|
19761
|
+
const actors = Object.keys(pairingValues);
|
|
19762
|
+
let proposedCandidates = [];
|
|
19763
|
+
const initialProposal = roundCandidate({
|
|
19764
|
+
actorsCount: actors.length,
|
|
19765
|
+
valueSortedPairings,
|
|
19766
|
+
pairingValueMap,
|
|
19767
|
+
deltaObjects,
|
|
19768
|
+
valueObjects
|
|
19769
|
+
});
|
|
19770
|
+
const candidateHashes = [candidateHash(initialProposal)];
|
|
19771
|
+
proposedCandidates.push(initialProposal);
|
|
19772
|
+
let lowCandidateValue = initialProposal.value;
|
|
19773
|
+
let deltaCandidate = initialProposal;
|
|
19774
|
+
let candidatesCount = 0;
|
|
19775
|
+
let iterations = 0;
|
|
19776
|
+
let opponentCount = actors.length;
|
|
19777
|
+
let calculatedIterations;
|
|
19778
|
+
do {
|
|
19779
|
+
opponentCount -= 1;
|
|
19780
|
+
calculatedIterations = actors.length * pairingValues[actors[0]].length;
|
|
19781
|
+
} while (calculatedIterations > maxIterations && opponentCount > 5);
|
|
19782
|
+
const stipulatedPairs = [];
|
|
19783
|
+
actors.forEach((actor) => {
|
|
19784
|
+
const participantIdPairings = pairingValues[actor];
|
|
19785
|
+
participantIdPairings.slice(0, opponentCount).forEach((pairing) => {
|
|
19786
|
+
iterations += 1;
|
|
19787
|
+
const stipulatedPair = pairingHash(actor, pairing.opponent);
|
|
19788
|
+
if (!stipulatedPairs.includes(stipulatedPair)) {
|
|
19789
|
+
const proposed = roundCandidate({
|
|
19790
|
+
// each roundCandidate starts with stipulated pairings
|
|
19791
|
+
stipulated: [[actor, pairing.opponent]],
|
|
19792
|
+
actorsCount: actors.length,
|
|
19793
|
+
valueSortedPairings,
|
|
19794
|
+
pairingValueMap,
|
|
19795
|
+
deltaObjects,
|
|
19796
|
+
valueObjects
|
|
19797
|
+
});
|
|
19798
|
+
if (!candidateHashes.includes(candidateHash(proposed))) {
|
|
19799
|
+
candidateHashes.push(candidateHash(proposed));
|
|
19800
|
+
proposedCandidates.push(proposed);
|
|
19801
|
+
const { maxDelta, value } = proposed;
|
|
19802
|
+
if (maxDelta < deltaCandidate.maxDelta)
|
|
19803
|
+
deltaCandidate = proposed;
|
|
19804
|
+
if (value < lowCandidateValue || value === lowCandidateValue && Math.round(Math.random())) {
|
|
19805
|
+
lowCandidateValue = value;
|
|
19806
|
+
}
|
|
19807
|
+
stipulatedPairs.push(stipulatedPair);
|
|
19808
|
+
candidatesCount += 1;
|
|
19809
|
+
}
|
|
19810
|
+
}
|
|
19811
|
+
});
|
|
19812
|
+
proposedCandidates = proposedCandidates.filter(
|
|
19813
|
+
(proposed) => Math.abs(proposed.value - lowCandidateValue) < 5
|
|
19814
|
+
);
|
|
19815
|
+
});
|
|
19816
|
+
proposedCandidates.sort((a, b) => a.maxDiff - b.maxDiff);
|
|
19817
|
+
const candidate = randomPop(proposedCandidates);
|
|
19818
|
+
return {
|
|
19819
|
+
candidatesCount,
|
|
19820
|
+
deltaCandidate,
|
|
19821
|
+
maxIterations,
|
|
19822
|
+
iterations,
|
|
19823
|
+
candidate
|
|
19824
|
+
};
|
|
19825
|
+
}
|
|
19826
|
+
function candidateHash(candidate) {
|
|
19827
|
+
return candidate.participantIdPairings.map(({ participantIds }) => participantIds.sort().join("|")).sort().join("/");
|
|
19828
|
+
}
|
|
19829
|
+
function roundCandidate({
|
|
19830
|
+
valueSortedPairings,
|
|
19831
|
+
stipulated = [],
|
|
19832
|
+
pairingValueMap,
|
|
19833
|
+
deltaObjects,
|
|
19834
|
+
valueObjects,
|
|
19835
|
+
actorsCount
|
|
19836
|
+
}) {
|
|
19837
|
+
const roundPlayers = [].concat(...stipulated);
|
|
19838
|
+
const participantIdPairings = [];
|
|
19839
|
+
let candidateValue = 0;
|
|
19840
|
+
stipulated.filter(Boolean).forEach((participantIds) => {
|
|
19841
|
+
const [p1, p2] = participantIds;
|
|
19842
|
+
const pairing = pairingHash(p1, p2);
|
|
19843
|
+
const value = pairingValueMap[pairing];
|
|
19844
|
+
participantIdPairings.push({ participantIds, value });
|
|
19845
|
+
candidateValue += pairingValueMap[pairing];
|
|
19846
|
+
});
|
|
19847
|
+
const consideredPairings = chunkArray(valueSortedPairings, actorsCount).map(
|
|
19848
|
+
(pairings) => shuffleArray(pairings).map((pairing) => ({
|
|
19849
|
+
...pairing,
|
|
19850
|
+
value: pairing.value + Math.random() * Math.round(Math.random())
|
|
19851
|
+
}))
|
|
19852
|
+
).flat();
|
|
19853
|
+
consideredPairings.forEach((rankedPairing) => {
|
|
19854
|
+
const participantIds = rankedPairing.pairing.split("|");
|
|
19855
|
+
const opponentExists = participantIds.reduce(
|
|
19856
|
+
(p, c) => roundPlayers.includes(c) || p,
|
|
19857
|
+
false
|
|
19858
|
+
);
|
|
19859
|
+
if (!opponentExists) {
|
|
19860
|
+
roundPlayers.push(...participantIds);
|
|
19861
|
+
const value = rankedPairing.value;
|
|
19862
|
+
candidateValue += value;
|
|
19863
|
+
participantIdPairings.push({ participantIds, value });
|
|
19864
|
+
}
|
|
19865
|
+
});
|
|
19866
|
+
participantIdPairings.sort((a, b) => a.value - b.value);
|
|
19867
|
+
const maxDelta = participantIdPairings.reduce((p, c) => {
|
|
19868
|
+
const [p1, p2] = c.participantIds;
|
|
19869
|
+
const hash = pairingHash(p1, p2);
|
|
19870
|
+
const delta = deltaObjects[hash];
|
|
19871
|
+
return delta > p ? delta : p;
|
|
19872
|
+
}, 0);
|
|
19873
|
+
const maxDiff = participantIdPairings.reduce((p, c) => {
|
|
19874
|
+
const [p1, p2] = c.participantIds;
|
|
19875
|
+
const hash = pairingHash(p1, p2);
|
|
19876
|
+
const diff = valueObjects[hash];
|
|
19877
|
+
return diff > p ? diff : p;
|
|
19878
|
+
}, 0);
|
|
19879
|
+
return { value: candidateValue, participantIdPairings, maxDelta, maxDiff };
|
|
19880
|
+
}
|
|
19881
|
+
function pairingHash(id1, id2) {
|
|
19882
|
+
return [id1, id2].sort().join("|");
|
|
19883
|
+
}
|
|
19884
|
+
|
|
19885
|
+
function getPairingsData({ participantIds }) {
|
|
19886
|
+
const possiblePairings = {};
|
|
19887
|
+
const uniquePairings = [];
|
|
19888
|
+
participantIds.forEach((participantId) => {
|
|
19889
|
+
possiblePairings[participantId] = participantIds.filter(
|
|
19890
|
+
(id) => id !== participantId
|
|
19891
|
+
);
|
|
19892
|
+
possiblePairings[participantId].forEach((id) => {
|
|
19893
|
+
const pairing = pairingHash(id, participantId);
|
|
19894
|
+
if (!uniquePairings.includes(pairing))
|
|
19895
|
+
uniquePairings.push(pairing);
|
|
19896
|
+
});
|
|
19897
|
+
});
|
|
19898
|
+
const deltaObjects = Object.assign(
|
|
19899
|
+
{},
|
|
19900
|
+
...uniquePairings.map((pairing) => ({ [pairing]: 0 }))
|
|
19901
|
+
);
|
|
19902
|
+
return { uniquePairings, possiblePairings, deltaObjects };
|
|
19903
|
+
}
|
|
19904
|
+
|
|
19905
|
+
function getEncounters({ matchUps }) {
|
|
19906
|
+
const encounters = [];
|
|
19907
|
+
for (const matchUp of matchUps) {
|
|
19908
|
+
const participantIds = matchUp.sides.map(
|
|
19909
|
+
extractAttributes("participantId")
|
|
19910
|
+
);
|
|
19911
|
+
if (participantIds.length === 2) {
|
|
19912
|
+
const [p1, p2] = participantIds;
|
|
19913
|
+
const pairing = pairingHash(p1, p2);
|
|
19914
|
+
if (!encounters.includes(pairing))
|
|
19915
|
+
encounters.push(pairing);
|
|
19916
|
+
}
|
|
19917
|
+
}
|
|
19918
|
+
return { encounters };
|
|
19919
|
+
}
|
|
19920
|
+
|
|
19921
|
+
function getParticipantPairingValues({
|
|
19922
|
+
possiblePairings,
|
|
19923
|
+
valueObjects
|
|
19924
|
+
}) {
|
|
19925
|
+
const pairingValues = {};
|
|
19926
|
+
for (const participantId of Object.keys(possiblePairings)) {
|
|
19927
|
+
const participantValues = possiblePairings[participantId].map(
|
|
19928
|
+
(opponent) => pairingValue(participantId, opponent)
|
|
19929
|
+
);
|
|
19930
|
+
pairingValues[participantId] = participantValues.sort(
|
|
19931
|
+
(a, b) => a.value - b.value
|
|
19932
|
+
);
|
|
19933
|
+
}
|
|
19934
|
+
function pairingValue(participantId, opponent) {
|
|
19935
|
+
const key = pairingHash(participantId, opponent);
|
|
19936
|
+
return { opponent, value: valueObjects[key] };
|
|
19937
|
+
}
|
|
19938
|
+
return { pairingValues };
|
|
19939
|
+
}
|
|
19940
|
+
|
|
19941
|
+
const ELO = "ELO";
|
|
19942
|
+
const NTRP = "NTRP";
|
|
19943
|
+
const UTR = "UTR";
|
|
19944
|
+
const WTN = "WTN";
|
|
19945
|
+
|
|
19946
|
+
const ratingsParameters = {
|
|
19947
|
+
[ELO]: { range: [0, 3e3], decimalsCount: 0, defaultInitialization: 1500 },
|
|
19948
|
+
[NTRP]: {
|
|
19949
|
+
accessors: ["ntrpRating", "dntrpRatingHundredths"],
|
|
19950
|
+
attributes: { ustaRatingType: "" },
|
|
19951
|
+
accessor: "dntrpRatingHundredths",
|
|
19952
|
+
defaultInitialization: 3,
|
|
19953
|
+
decimalsCount: 1,
|
|
19954
|
+
range: [1, 7]
|
|
19955
|
+
},
|
|
19956
|
+
[UTR]: {
|
|
19957
|
+
defaultInitialization: 6,
|
|
19958
|
+
accessors: ["utrRating"],
|
|
19959
|
+
accessor: "utrRating",
|
|
19960
|
+
decimalsCount: 2,
|
|
19961
|
+
range: [1, 16]
|
|
19962
|
+
},
|
|
19963
|
+
[WTN]: {
|
|
19964
|
+
attributes: { confidence: { generator: true, range: [60, 100] } },
|
|
19965
|
+
accessors: ["wtnRating", "confidence"],
|
|
19966
|
+
defaultInitialization: 23,
|
|
19967
|
+
accessor: "wtnRating",
|
|
19968
|
+
decimalsCount: 2,
|
|
19969
|
+
range: [40, 1]
|
|
19970
|
+
}
|
|
19971
|
+
};
|
|
19972
|
+
|
|
19827
19973
|
const DEFAULT_RATING = 0;
|
|
19974
|
+
function getSideRatings({
|
|
19975
|
+
tournamentParticipants,
|
|
19976
|
+
adHocRatings,
|
|
19977
|
+
eventType,
|
|
19978
|
+
scaleName,
|
|
19979
|
+
pairing
|
|
19980
|
+
}) {
|
|
19981
|
+
const defaultRating = ratingsParameters[scaleName]?.defaultInitialization ?? DEFAULT_RATING;
|
|
19982
|
+
return pairing.split("|").map((participantId) => {
|
|
19983
|
+
if (eventType === DOUBLES) {
|
|
19984
|
+
const individualParticipantIds = tournamentParticipants?.find(
|
|
19985
|
+
(participant) => participant.participantId === participantId
|
|
19986
|
+
)?.individualParticipantIds;
|
|
19987
|
+
return !individualParticipantIds ? defaultRating * 2 : individualParticipantIds?.map(
|
|
19988
|
+
(participantId2) => adHocRatings[participantId2] || defaultRating
|
|
19989
|
+
);
|
|
19990
|
+
} else {
|
|
19991
|
+
return adHocRatings[participantId] || defaultRating;
|
|
19992
|
+
}
|
|
19993
|
+
});
|
|
19994
|
+
}
|
|
19995
|
+
|
|
19996
|
+
function getPairings({
|
|
19997
|
+
tournamentParticipants,
|
|
19998
|
+
adHocRatings = {},
|
|
19999
|
+
possiblePairings,
|
|
20000
|
+
// participant keyed; provides array of possible opponents
|
|
20001
|
+
uniquePairings,
|
|
20002
|
+
// hashes of all possible participantId pairings
|
|
20003
|
+
maxIterations,
|
|
20004
|
+
deltaObjects,
|
|
20005
|
+
// difference in rating between paired participants
|
|
20006
|
+
valueObjects,
|
|
20007
|
+
// calculated value of a pairing of participants, used for sorting pairings
|
|
20008
|
+
eventType,
|
|
20009
|
+
scaleName,
|
|
20010
|
+
salted
|
|
20011
|
+
}) {
|
|
20012
|
+
uniquePairings.forEach((pairing) => {
|
|
20013
|
+
const ratings = getSideRatings({
|
|
20014
|
+
tournamentParticipants,
|
|
20015
|
+
adHocRatings,
|
|
20016
|
+
scaleName,
|
|
20017
|
+
eventType,
|
|
20018
|
+
pairing
|
|
20019
|
+
});
|
|
20020
|
+
const salting = typeof salted === "number" && salted || 0.5;
|
|
20021
|
+
const salt = salted && (Math.round(Math.random()) ? salting : salting * -1) || 0;
|
|
20022
|
+
const ratingsDifference = Math.abs(ratings[0] - ratings[1]) + salt;
|
|
20023
|
+
const pairingDelta = Math.abs(ratings[0] - ratings[1]);
|
|
20024
|
+
deltaObjects[pairing] = pairingDelta;
|
|
20025
|
+
if (!valueObjects[pairing])
|
|
20026
|
+
valueObjects[pairing] = 0;
|
|
20027
|
+
valueObjects[pairing] += ratingsDifference ? Math.pow(ratingsDifference, 2) : 0;
|
|
20028
|
+
});
|
|
20029
|
+
const valueSortedPairings = uniquePairings.map((pairing) => ({ pairing, value: valueObjects[pairing] })).sort((a, b) => a.value - b.value);
|
|
20030
|
+
const { pairingValues } = getParticipantPairingValues({
|
|
20031
|
+
possiblePairings,
|
|
20032
|
+
valueObjects
|
|
20033
|
+
});
|
|
20034
|
+
const { candidate, candidatesCount, deltaCandidate, iterations } = generateCandidate({
|
|
20035
|
+
valueSortedPairings,
|
|
20036
|
+
maxIterations,
|
|
20037
|
+
pairingValues,
|
|
20038
|
+
deltaObjects,
|
|
20039
|
+
valueObjects
|
|
20040
|
+
});
|
|
20041
|
+
const { participantIdPairings } = candidate;
|
|
20042
|
+
return {
|
|
20043
|
+
participantIdPairings,
|
|
20044
|
+
candidatesCount,
|
|
20045
|
+
deltaCandidate,
|
|
20046
|
+
iterations,
|
|
20047
|
+
candidate
|
|
20048
|
+
};
|
|
20049
|
+
}
|
|
20050
|
+
|
|
20051
|
+
const ENCOUNTER_VALUE = 100;
|
|
20052
|
+
const SAME_TEAM_VALUE = 100;
|
|
19828
20053
|
const MAX_ITERATIONS = 5e3;
|
|
19829
20054
|
function generateDrawMaticRound({
|
|
19830
20055
|
maxIterations = MAX_ITERATIONS,
|
|
@@ -19836,9 +20061,11 @@ function generateDrawMaticRound({
|
|
|
19836
20061
|
drawDefinition,
|
|
19837
20062
|
adHocRatings,
|
|
19838
20063
|
structureId,
|
|
20064
|
+
salted = 0.5,
|
|
19839
20065
|
matchUpIds,
|
|
19840
20066
|
eventType,
|
|
19841
|
-
structure
|
|
20067
|
+
structure,
|
|
20068
|
+
scaleName
|
|
19842
20069
|
}) {
|
|
19843
20070
|
if (!drawDefinition)
|
|
19844
20071
|
return { error: MISSING_DRAW_DEFINITION };
|
|
@@ -19887,7 +20114,9 @@ function generateDrawMaticRound({
|
|
|
19887
20114
|
deltaObjects,
|
|
19888
20115
|
valueObjects,
|
|
19889
20116
|
eventType,
|
|
19890
|
-
|
|
20117
|
+
scaleName,
|
|
20118
|
+
structure,
|
|
20119
|
+
salted
|
|
19891
20120
|
};
|
|
19892
20121
|
const { candidatesCount, participantIdPairings, iterations } = getPairings(params);
|
|
19893
20122
|
if (!candidatesCount)
|
|
@@ -19915,114 +20144,6 @@ function generateDrawMaticRound({
|
|
|
19915
20144
|
matchUps
|
|
19916
20145
|
};
|
|
19917
20146
|
}
|
|
19918
|
-
function getSideRatings({
|
|
19919
|
-
tournamentParticipants,
|
|
19920
|
-
adHocRatings,
|
|
19921
|
-
eventType,
|
|
19922
|
-
pairing
|
|
19923
|
-
}) {
|
|
19924
|
-
return pairing.split("|").map((participantId) => {
|
|
19925
|
-
if (eventType === DOUBLES) {
|
|
19926
|
-
const individualParticipantIds = tournamentParticipants?.find(
|
|
19927
|
-
(participant) => participant.participantId === participantId
|
|
19928
|
-
)?.individualParticipantIds;
|
|
19929
|
-
return !individualParticipantIds ? DEFAULT_RATING * 2 : individualParticipantIds?.map(
|
|
19930
|
-
(participantId2) => adHocRatings[participantId2 || DEFAULT_RATING]
|
|
19931
|
-
);
|
|
19932
|
-
} else {
|
|
19933
|
-
return adHocRatings[participantId] || DEFAULT_RATING;
|
|
19934
|
-
}
|
|
19935
|
-
});
|
|
19936
|
-
}
|
|
19937
|
-
function getPairings({
|
|
19938
|
-
tournamentParticipants,
|
|
19939
|
-
adHocRatings = {},
|
|
19940
|
-
possiblePairings,
|
|
19941
|
-
// participant keyed; provides array of possible opponents
|
|
19942
|
-
uniquePairings,
|
|
19943
|
-
// hashes of all possible participantId pairings
|
|
19944
|
-
maxIterations,
|
|
19945
|
-
deltaObjects,
|
|
19946
|
-
// difference in rating between paired participants
|
|
19947
|
-
valueObjects,
|
|
19948
|
-
// calculated value of a pairing of participants, used for sorting pairings
|
|
19949
|
-
eventType
|
|
19950
|
-
}) {
|
|
19951
|
-
uniquePairings.forEach((pairing) => {
|
|
19952
|
-
const ratings = getSideRatings({
|
|
19953
|
-
tournamentParticipants,
|
|
19954
|
-
adHocRatings,
|
|
19955
|
-
eventType,
|
|
19956
|
-
pairing
|
|
19957
|
-
});
|
|
19958
|
-
const ratingsDifference = Math.abs(ratings[0] - ratings[1]) + 1;
|
|
19959
|
-
deltaObjects[pairing] = Math.abs(ratings[0] - ratings[1]);
|
|
19960
|
-
if (!valueObjects[pairing])
|
|
19961
|
-
valueObjects[pairing] = 0;
|
|
19962
|
-
valueObjects[pairing] += Math.pow(ratingsDifference, 2);
|
|
19963
|
-
});
|
|
19964
|
-
const valueSortedPairings = uniquePairings.map((pairing) => ({ pairing, value: valueObjects[pairing] })).sort((a, b) => a.value - b.value);
|
|
19965
|
-
const { pairingValues } = getParticipantPairingValues({
|
|
19966
|
-
possiblePairings,
|
|
19967
|
-
valueObjects
|
|
19968
|
-
});
|
|
19969
|
-
const { candidate, candidatesCount, iterations } = generateCandidate({
|
|
19970
|
-
valueSortedPairings,
|
|
19971
|
-
maxIterations,
|
|
19972
|
-
pairingValues,
|
|
19973
|
-
deltaObjects
|
|
19974
|
-
});
|
|
19975
|
-
const { participantIdPairings } = candidate;
|
|
19976
|
-
return { candidatesCount, participantIdPairings, iterations };
|
|
19977
|
-
}
|
|
19978
|
-
function getPairingsData({ participantIds }) {
|
|
19979
|
-
const possiblePairings = {};
|
|
19980
|
-
const uniquePairings = [];
|
|
19981
|
-
participantIds.forEach((participantId) => {
|
|
19982
|
-
possiblePairings[participantId] = participantIds.filter(
|
|
19983
|
-
(id) => id !== participantId
|
|
19984
|
-
);
|
|
19985
|
-
possiblePairings[participantId].forEach((id) => {
|
|
19986
|
-
const pairing = pairingHash(id, participantId);
|
|
19987
|
-
if (!uniquePairings.includes(pairing))
|
|
19988
|
-
uniquePairings.push(pairing);
|
|
19989
|
-
});
|
|
19990
|
-
});
|
|
19991
|
-
const deltaObjects = Object.assign(
|
|
19992
|
-
{},
|
|
19993
|
-
...uniquePairings.map((pairing) => ({ [pairing]: 0 }))
|
|
19994
|
-
);
|
|
19995
|
-
return { uniquePairings, possiblePairings, deltaObjects };
|
|
19996
|
-
}
|
|
19997
|
-
function getEncounters({ matchUps }) {
|
|
19998
|
-
const encounters = [];
|
|
19999
|
-
for (const matchUp of matchUps) {
|
|
20000
|
-
const participantIds = matchUp.sides.map(getParticipantId);
|
|
20001
|
-
if (participantIds.length === 2) {
|
|
20002
|
-
const [p1, p2] = participantIds;
|
|
20003
|
-
const pairing = pairingHash(p1, p2);
|
|
20004
|
-
if (!encounters.includes(pairing))
|
|
20005
|
-
encounters.push(pairing);
|
|
20006
|
-
}
|
|
20007
|
-
}
|
|
20008
|
-
return { encounters };
|
|
20009
|
-
}
|
|
20010
|
-
function getParticipantPairingValues({ possiblePairings, valueObjects }) {
|
|
20011
|
-
const pairingValues = {};
|
|
20012
|
-
for (const participantId of Object.keys(possiblePairings)) {
|
|
20013
|
-
const participantValues = possiblePairings[participantId].map(
|
|
20014
|
-
(opponent) => pairingValue(participantId, opponent)
|
|
20015
|
-
);
|
|
20016
|
-
pairingValues[participantId] = participantValues.sort(
|
|
20017
|
-
(a, b) => a.value - b.value
|
|
20018
|
-
);
|
|
20019
|
-
}
|
|
20020
|
-
function pairingValue(participantId, opponent) {
|
|
20021
|
-
const key = pairingHash(participantId, opponent);
|
|
20022
|
-
return { opponent, value: valueObjects[key] };
|
|
20023
|
-
}
|
|
20024
|
-
return { pairingValues };
|
|
20025
|
-
}
|
|
20026
20147
|
|
|
20027
20148
|
function generateQualifyingLink({
|
|
20028
20149
|
targetEntryRound = 1,
|
|
@@ -22558,6 +22679,7 @@ function prepareStage(params) {
|
|
|
22558
22679
|
function drawMatic({
|
|
22559
22680
|
tournamentParticipants,
|
|
22560
22681
|
restrictEntryStatus,
|
|
22682
|
+
adHocRatings = {},
|
|
22561
22683
|
tournamentRecord,
|
|
22562
22684
|
generateMatchUps,
|
|
22563
22685
|
addToStructure,
|
|
@@ -22612,12 +22734,16 @@ function drawMatic({
|
|
|
22612
22734
|
if (!structureIsAdHoc)
|
|
22613
22735
|
return { error: INVALID_DRAW_DEFINITION };
|
|
22614
22736
|
tournamentParticipants = tournamentParticipants ?? tournamentRecord.participants ?? [];
|
|
22615
|
-
const adHocRatings = {};
|
|
22616
22737
|
for (const participantId of participantIds ?? []) {
|
|
22617
22738
|
const participant = tournamentParticipants?.find(
|
|
22618
22739
|
(participant2) => participant2.participantId === participantId
|
|
22619
22740
|
);
|
|
22620
|
-
let scaleValue = getScaleValue({
|
|
22741
|
+
let scaleValue = getScaleValue({
|
|
22742
|
+
scaleName: `${scaleName}.${DYNAMIC}`,
|
|
22743
|
+
scaleAccessor,
|
|
22744
|
+
participant,
|
|
22745
|
+
eventType
|
|
22746
|
+
});
|
|
22621
22747
|
if (!scaleValue && scaleName) {
|
|
22622
22748
|
scaleValue = getScaleValue({
|
|
22623
22749
|
scaleAccessor,
|
|
@@ -22626,7 +22752,7 @@ function drawMatic({
|
|
|
22626
22752
|
eventType
|
|
22627
22753
|
});
|
|
22628
22754
|
}
|
|
22629
|
-
if (scaleValue)
|
|
22755
|
+
if (scaleValue && !adHocRatings[participantId])
|
|
22630
22756
|
adHocRatings[participantId] = scaleValue;
|
|
22631
22757
|
}
|
|
22632
22758
|
return generateDrawMaticRound({
|
|
@@ -22644,14 +22770,15 @@ function drawMatic({
|
|
|
22644
22770
|
});
|
|
22645
22771
|
}
|
|
22646
22772
|
function getScaleValue({
|
|
22647
|
-
|
|
22648
|
-
scaleName = "dynamic",
|
|
22773
|
+
scaleType = RATING,
|
|
22649
22774
|
scaleAccessor,
|
|
22650
|
-
participant
|
|
22775
|
+
participant,
|
|
22776
|
+
scaleName,
|
|
22777
|
+
eventType
|
|
22651
22778
|
}) {
|
|
22652
22779
|
const scaleAttributes = {
|
|
22653
22780
|
eventType: eventType || TypeEnum.Singles,
|
|
22654
|
-
scaleType
|
|
22781
|
+
scaleType,
|
|
22655
22782
|
scaleName
|
|
22656
22783
|
};
|
|
22657
22784
|
const result = participant && participantScaleItem({
|