tods-competition-factory 1.7.3 → 1.7.5
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 +15 -3
- package/dist/forge/generate.mjs +356 -226
- package/dist/forge/generate.mjs.map +1 -1
- package/dist/forge/query.mjs +3 -2
- package/dist/forge/query.mjs.map +1 -1
- package/dist/forge/transform.mjs +3 -2
- package/dist/forge/transform.mjs.map +1 -1
- package/dist/index.mjs +302 -185
- package/dist/index.mjs.map +1 -1
- package/dist/tods-competition-factory.development.cjs.js +315 -225
- 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";
|
|
@@ -1575,14 +1576,15 @@ function getScaleValues({ participant }) {
|
|
|
1575
1576
|
for (const itemType of itemTypes) {
|
|
1576
1577
|
const scaleItem = latestScaleItem(itemType);
|
|
1577
1578
|
if (scaleItem) {
|
|
1578
|
-
const [, type, format, scaleName] = scaleItem.itemType.split(".");
|
|
1579
|
+
const [, type, format, scaleName, modifier] = scaleItem.itemType.split(".");
|
|
1580
|
+
const namedScale = modifier ? `${scaleName}.${modifier}` : scaleName;
|
|
1579
1581
|
const scaleType = type === SEEDING && "seedings" || type === RANKING && "rankings" || "ratings";
|
|
1580
1582
|
if (!scales[scaleType][format])
|
|
1581
1583
|
scales[scaleType][format] = [];
|
|
1582
1584
|
scales[scaleType][format].push({
|
|
1583
1585
|
scaleValue: scaleItem.itemValue,
|
|
1584
1586
|
scaleDate: scaleItem.itemDate,
|
|
1585
|
-
scaleName
|
|
1587
|
+
scaleName: namedScale
|
|
1586
1588
|
});
|
|
1587
1589
|
}
|
|
1588
1590
|
}
|
|
@@ -13935,7 +13937,7 @@ function treeMatchUps({
|
|
|
13935
13937
|
uuids
|
|
13936
13938
|
}));
|
|
13937
13939
|
roundNumber++;
|
|
13938
|
-
roundLimit = roundLimit || qualifyingRoundNumber
|
|
13940
|
+
roundLimit = roundLimit || qualifyingRoundNumber;
|
|
13939
13941
|
while (roundNodes.length > 1) {
|
|
13940
13942
|
if (qualifyingPositions && roundNodes.length === qualifyingPositions) {
|
|
13941
13943
|
roundLimit = roundNumber - 1;
|
|
@@ -14092,6 +14094,7 @@ function generateCurtisConsolation(params) {
|
|
|
14092
14094
|
finishingPositionOffset,
|
|
14093
14095
|
structureName = MAIN,
|
|
14094
14096
|
stageSequence = 1,
|
|
14097
|
+
structureNameMap,
|
|
14095
14098
|
staggeredEntry,
|
|
14096
14099
|
stage = MAIN,
|
|
14097
14100
|
matchUpType,
|
|
@@ -14125,8 +14128,9 @@ function generateCurtisConsolation(params) {
|
|
|
14125
14128
|
const consolationItems = feedRoundOffsets.map((roundOffset, index) => {
|
|
14126
14129
|
const stageSequence2 = index + 1;
|
|
14127
14130
|
const { consolationStructure } = consolationFeedStructure({
|
|
14128
|
-
structureId: uuids?.pop(),
|
|
14129
14131
|
idPrefix: idPrefix && `${idPrefix}-c${index}`,
|
|
14132
|
+
structureId: uuids?.pop(),
|
|
14133
|
+
structureNameMap,
|
|
14130
14134
|
stageSequence: stageSequence2,
|
|
14131
14135
|
roundOffset,
|
|
14132
14136
|
matchUpType,
|
|
@@ -14155,9 +14159,9 @@ function generateCurtisConsolation(params) {
|
|
|
14155
14159
|
isMock
|
|
14156
14160
|
});
|
|
14157
14161
|
const playoffStructure = structureTemplate({
|
|
14162
|
+
structureName: structureNameMap?.[PLAY_OFF] || PLAY_OFF,
|
|
14158
14163
|
structureId: uuids?.pop(),
|
|
14159
14164
|
matchUps: playoffMatchUps,
|
|
14160
|
-
structureName: PLAY_OFF,
|
|
14161
14165
|
stageSequence: 2,
|
|
14162
14166
|
stage: PLAY_OFF,
|
|
14163
14167
|
matchUpType
|
|
@@ -14182,6 +14186,7 @@ function generateCurtisConsolation(params) {
|
|
|
14182
14186
|
}
|
|
14183
14187
|
function consolationFeedStructure({
|
|
14184
14188
|
stageSequence = 1,
|
|
14189
|
+
structureNameMap,
|
|
14185
14190
|
roundOffset = 0,
|
|
14186
14191
|
matchUpType,
|
|
14187
14192
|
structureId,
|
|
@@ -14202,7 +14207,8 @@ function consolationFeedStructure({
|
|
|
14202
14207
|
isMock,
|
|
14203
14208
|
uuids
|
|
14204
14209
|
});
|
|
14205
|
-
const
|
|
14210
|
+
const defaultName = `${CONSOLATION} ${index + 1}`;
|
|
14211
|
+
const structureName = structureNameMap?.[defaultName] || defaultName;
|
|
14206
14212
|
const consolationStructure = structureTemplate({
|
|
14207
14213
|
matchUps: consolationMatchUps,
|
|
14208
14214
|
stage: CONSOLATION,
|
|
@@ -14487,6 +14493,7 @@ function processPlayoffGroups({
|
|
|
14487
14493
|
}
|
|
14488
14494
|
const params = {
|
|
14489
14495
|
structureId: playoffGroup.structureId ?? uuids?.pop(),
|
|
14496
|
+
structureNameMap: playoffGroup.structureNameMap,
|
|
14490
14497
|
structureName: playoffGroup.structureName,
|
|
14491
14498
|
idPrefix: idPrefix && `${idPrefix}-po`,
|
|
14492
14499
|
appliedPolicies: policyDefinitions,
|
|
@@ -19605,98 +19612,6 @@ function generateVoluntaryConsolation(params) {
|
|
|
19605
19612
|
return generateVoluntaryConsolation$1({ participants: tournamentParticipants, ...params });
|
|
19606
19613
|
}
|
|
19607
19614
|
|
|
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
19615
|
function generateAdHocMatchUps({
|
|
19701
19616
|
participantIdPairings,
|
|
19702
19617
|
addToStructure = true,
|
|
@@ -19831,11 +19746,315 @@ function addAdHocMatchUps({
|
|
|
19831
19746
|
return { ...SUCCESS };
|
|
19832
19747
|
}
|
|
19833
19748
|
|
|
19834
|
-
|
|
19835
|
-
|
|
19749
|
+
function generateCandidate({
|
|
19750
|
+
maxIterations = 4e3,
|
|
19751
|
+
// cap the processing intensity of the candidate generator
|
|
19752
|
+
valueSortedPairings,
|
|
19753
|
+
// pairings sorted by value from low to high
|
|
19754
|
+
pairingValues,
|
|
19755
|
+
valueObjects,
|
|
19756
|
+
deltaObjects
|
|
19757
|
+
}) {
|
|
19758
|
+
const pairingValueMap = Object.assign(
|
|
19759
|
+
{},
|
|
19760
|
+
...valueSortedPairings.map((rm) => ({ [rm.pairing]: rm.value }))
|
|
19761
|
+
);
|
|
19762
|
+
const actors = Object.keys(pairingValues);
|
|
19763
|
+
let proposedCandidates = [];
|
|
19764
|
+
const initialProposal = roundCandidate({
|
|
19765
|
+
actorsCount: actors.length,
|
|
19766
|
+
valueSortedPairings,
|
|
19767
|
+
pairingValueMap,
|
|
19768
|
+
deltaObjects,
|
|
19769
|
+
valueObjects
|
|
19770
|
+
});
|
|
19771
|
+
const candidateHashes = [candidateHash(initialProposal)];
|
|
19772
|
+
proposedCandidates.push(initialProposal);
|
|
19773
|
+
let lowCandidateValue = initialProposal.value;
|
|
19774
|
+
let deltaCandidate = initialProposal;
|
|
19775
|
+
let candidatesCount = 0;
|
|
19776
|
+
let iterations = 0;
|
|
19777
|
+
let opponentCount = actors.length;
|
|
19778
|
+
let calculatedIterations;
|
|
19779
|
+
do {
|
|
19780
|
+
opponentCount -= 1;
|
|
19781
|
+
calculatedIterations = actors.length * pairingValues[actors[0]].length;
|
|
19782
|
+
} while (calculatedIterations > maxIterations && opponentCount > 5);
|
|
19783
|
+
const stipulatedPairs = [];
|
|
19784
|
+
actors.forEach((actor) => {
|
|
19785
|
+
const participantIdPairings = pairingValues[actor];
|
|
19786
|
+
participantIdPairings.slice(0, opponentCount).forEach((pairing) => {
|
|
19787
|
+
iterations += 1;
|
|
19788
|
+
const stipulatedPair = pairingHash(actor, pairing.opponent);
|
|
19789
|
+
if (!stipulatedPairs.includes(stipulatedPair)) {
|
|
19790
|
+
const proposed = roundCandidate({
|
|
19791
|
+
// each roundCandidate starts with stipulated pairings
|
|
19792
|
+
stipulated: [[actor, pairing.opponent]],
|
|
19793
|
+
actorsCount: actors.length,
|
|
19794
|
+
valueSortedPairings,
|
|
19795
|
+
pairingValueMap,
|
|
19796
|
+
deltaObjects,
|
|
19797
|
+
valueObjects
|
|
19798
|
+
});
|
|
19799
|
+
if (!candidateHashes.includes(candidateHash(proposed))) {
|
|
19800
|
+
candidateHashes.push(candidateHash(proposed));
|
|
19801
|
+
proposedCandidates.push(proposed);
|
|
19802
|
+
const { maxDelta, value } = proposed;
|
|
19803
|
+
if (maxDelta < deltaCandidate.maxDelta)
|
|
19804
|
+
deltaCandidate = proposed;
|
|
19805
|
+
if (value < lowCandidateValue || value === lowCandidateValue && Math.round(Math.random())) {
|
|
19806
|
+
lowCandidateValue = value;
|
|
19807
|
+
}
|
|
19808
|
+
stipulatedPairs.push(stipulatedPair);
|
|
19809
|
+
candidatesCount += 1;
|
|
19810
|
+
}
|
|
19811
|
+
}
|
|
19812
|
+
});
|
|
19813
|
+
proposedCandidates = proposedCandidates.filter(
|
|
19814
|
+
(proposed) => Math.abs(proposed.value - lowCandidateValue) < 5
|
|
19815
|
+
);
|
|
19816
|
+
});
|
|
19817
|
+
proposedCandidates.sort((a, b) => a.maxDiff - b.maxDiff);
|
|
19818
|
+
const candidate = randomPop(proposedCandidates);
|
|
19819
|
+
return {
|
|
19820
|
+
candidatesCount,
|
|
19821
|
+
deltaCandidate,
|
|
19822
|
+
maxIterations,
|
|
19823
|
+
iterations,
|
|
19824
|
+
candidate
|
|
19825
|
+
};
|
|
19826
|
+
}
|
|
19827
|
+
function candidateHash(candidate) {
|
|
19828
|
+
return candidate.participantIdPairings.map(({ participantIds }) => participantIds.sort().join("|")).sort().join("/");
|
|
19829
|
+
}
|
|
19830
|
+
function roundCandidate({
|
|
19831
|
+
valueSortedPairings,
|
|
19832
|
+
stipulated = [],
|
|
19833
|
+
pairingValueMap,
|
|
19834
|
+
deltaObjects,
|
|
19835
|
+
valueObjects,
|
|
19836
|
+
actorsCount
|
|
19837
|
+
}) {
|
|
19838
|
+
const roundPlayers = [].concat(...stipulated);
|
|
19839
|
+
const participantIdPairings = [];
|
|
19840
|
+
let candidateValue = 0;
|
|
19841
|
+
stipulated.filter(Boolean).forEach((participantIds) => {
|
|
19842
|
+
const [p1, p2] = participantIds;
|
|
19843
|
+
const pairing = pairingHash(p1, p2);
|
|
19844
|
+
const value = pairingValueMap[pairing];
|
|
19845
|
+
participantIdPairings.push({ participantIds, value });
|
|
19846
|
+
candidateValue += pairingValueMap[pairing];
|
|
19847
|
+
});
|
|
19848
|
+
const consideredPairings = chunkArray(valueSortedPairings, actorsCount).map(
|
|
19849
|
+
(pairings) => shuffleArray(pairings).map((pairing) => ({
|
|
19850
|
+
...pairing,
|
|
19851
|
+
value: pairing.value + Math.random() * Math.round(Math.random())
|
|
19852
|
+
}))
|
|
19853
|
+
).flat();
|
|
19854
|
+
consideredPairings.forEach((rankedPairing) => {
|
|
19855
|
+
const participantIds = rankedPairing.pairing.split("|");
|
|
19856
|
+
const opponentExists = participantIds.reduce(
|
|
19857
|
+
(p, c) => roundPlayers.includes(c) || p,
|
|
19858
|
+
false
|
|
19859
|
+
);
|
|
19860
|
+
if (!opponentExists) {
|
|
19861
|
+
roundPlayers.push(...participantIds);
|
|
19862
|
+
const value = rankedPairing.value;
|
|
19863
|
+
candidateValue += value;
|
|
19864
|
+
participantIdPairings.push({ participantIds, value });
|
|
19865
|
+
}
|
|
19866
|
+
});
|
|
19867
|
+
participantIdPairings.sort((a, b) => a.value - b.value);
|
|
19868
|
+
const maxDelta = participantIdPairings.reduce((p, c) => {
|
|
19869
|
+
const [p1, p2] = c.participantIds;
|
|
19870
|
+
const hash = pairingHash(p1, p2);
|
|
19871
|
+
const delta = deltaObjects[hash];
|
|
19872
|
+
return delta > p ? delta : p;
|
|
19873
|
+
}, 0);
|
|
19874
|
+
const maxDiff = participantIdPairings.reduce((p, c) => {
|
|
19875
|
+
const [p1, p2] = c.participantIds;
|
|
19876
|
+
const hash = pairingHash(p1, p2);
|
|
19877
|
+
const diff = valueObjects[hash];
|
|
19878
|
+
return diff > p ? diff : p;
|
|
19879
|
+
}, 0);
|
|
19880
|
+
return { value: candidateValue, participantIdPairings, maxDelta, maxDiff };
|
|
19881
|
+
}
|
|
19882
|
+
function pairingHash(id1, id2) {
|
|
19883
|
+
return [id1, id2].sort().join("|");
|
|
19884
|
+
}
|
|
19885
|
+
|
|
19886
|
+
function getPairingsData({ participantIds }) {
|
|
19887
|
+
const possiblePairings = {};
|
|
19888
|
+
const uniquePairings = [];
|
|
19889
|
+
participantIds.forEach((participantId) => {
|
|
19890
|
+
possiblePairings[participantId] = participantIds.filter(
|
|
19891
|
+
(id) => id !== participantId
|
|
19892
|
+
);
|
|
19893
|
+
possiblePairings[participantId].forEach((id) => {
|
|
19894
|
+
const pairing = pairingHash(id, participantId);
|
|
19895
|
+
if (!uniquePairings.includes(pairing))
|
|
19896
|
+
uniquePairings.push(pairing);
|
|
19897
|
+
});
|
|
19898
|
+
});
|
|
19899
|
+
const deltaObjects = Object.assign(
|
|
19900
|
+
{},
|
|
19901
|
+
...uniquePairings.map((pairing) => ({ [pairing]: 0 }))
|
|
19902
|
+
);
|
|
19903
|
+
return { uniquePairings, possiblePairings, deltaObjects };
|
|
19904
|
+
}
|
|
19905
|
+
|
|
19906
|
+
function getEncounters({ matchUps }) {
|
|
19907
|
+
const encounters = [];
|
|
19908
|
+
for (const matchUp of matchUps) {
|
|
19909
|
+
const participantIds = matchUp.sides.map(
|
|
19910
|
+
extractAttributes("participantId")
|
|
19911
|
+
);
|
|
19912
|
+
if (participantIds.length === 2) {
|
|
19913
|
+
const [p1, p2] = participantIds;
|
|
19914
|
+
const pairing = pairingHash(p1, p2);
|
|
19915
|
+
if (!encounters.includes(pairing))
|
|
19916
|
+
encounters.push(pairing);
|
|
19917
|
+
}
|
|
19918
|
+
}
|
|
19919
|
+
return { encounters };
|
|
19920
|
+
}
|
|
19921
|
+
|
|
19922
|
+
function getParticipantPairingValues({
|
|
19923
|
+
possiblePairings,
|
|
19924
|
+
valueObjects
|
|
19925
|
+
}) {
|
|
19926
|
+
const pairingValues = {};
|
|
19927
|
+
for (const participantId of Object.keys(possiblePairings)) {
|
|
19928
|
+
const participantValues = possiblePairings[participantId].map(
|
|
19929
|
+
(opponent) => pairingValue(participantId, opponent)
|
|
19930
|
+
);
|
|
19931
|
+
pairingValues[participantId] = participantValues.sort(
|
|
19932
|
+
(a, b) => a.value - b.value
|
|
19933
|
+
);
|
|
19934
|
+
}
|
|
19935
|
+
function pairingValue(participantId, opponent) {
|
|
19936
|
+
const key = pairingHash(participantId, opponent);
|
|
19937
|
+
return { opponent, value: valueObjects[key] };
|
|
19938
|
+
}
|
|
19939
|
+
return { pairingValues };
|
|
19940
|
+
}
|
|
19941
|
+
|
|
19942
|
+
const ELO = "ELO";
|
|
19943
|
+
const NTRP = "NTRP";
|
|
19944
|
+
const UTR = "UTR";
|
|
19945
|
+
const WTN = "WTN";
|
|
19946
|
+
|
|
19947
|
+
const ratingsParameters = {
|
|
19948
|
+
[ELO]: { range: [0, 3e3], decimalsCount: 0, defaultInitialization: 1500 },
|
|
19949
|
+
[NTRP]: {
|
|
19950
|
+
accessors: ["ntrpRating", "dntrpRatingHundredths"],
|
|
19951
|
+
attributes: { ustaRatingType: "" },
|
|
19952
|
+
accessor: "dntrpRatingHundredths",
|
|
19953
|
+
defaultInitialization: 3,
|
|
19954
|
+
decimalsCount: 1,
|
|
19955
|
+
range: [1, 7]
|
|
19956
|
+
},
|
|
19957
|
+
[UTR]: {
|
|
19958
|
+
defaultInitialization: 6,
|
|
19959
|
+
accessors: ["utrRating"],
|
|
19960
|
+
accessor: "utrRating",
|
|
19961
|
+
decimalsCount: 2,
|
|
19962
|
+
range: [1, 16]
|
|
19963
|
+
},
|
|
19964
|
+
[WTN]: {
|
|
19965
|
+
attributes: { confidence: { generator: true, range: [60, 100] } },
|
|
19966
|
+
accessors: ["wtnRating", "confidence"],
|
|
19967
|
+
defaultInitialization: 23,
|
|
19968
|
+
accessor: "wtnRating",
|
|
19969
|
+
decimalsCount: 2,
|
|
19970
|
+
range: [40, 1]
|
|
19971
|
+
}
|
|
19972
|
+
};
|
|
19973
|
+
|
|
19836
19974
|
const DEFAULT_RATING = 0;
|
|
19837
|
-
|
|
19975
|
+
function getSideRatings({
|
|
19976
|
+
tournamentParticipants,
|
|
19977
|
+
adHocRatings,
|
|
19978
|
+
eventType,
|
|
19979
|
+
scaleName,
|
|
19980
|
+
pairing
|
|
19981
|
+
}) {
|
|
19982
|
+
const defaultRating = ratingsParameters[scaleName]?.defaultInitialization ?? DEFAULT_RATING;
|
|
19983
|
+
return pairing.split("|").map((participantId) => {
|
|
19984
|
+
if (eventType === DOUBLES) {
|
|
19985
|
+
const individualParticipantIds = tournamentParticipants?.find(
|
|
19986
|
+
(participant) => participant.participantId === participantId
|
|
19987
|
+
)?.individualParticipantIds;
|
|
19988
|
+
return !individualParticipantIds ? defaultRating * 2 : individualParticipantIds?.map(
|
|
19989
|
+
(participantId2) => adHocRatings[participantId2] || defaultRating
|
|
19990
|
+
);
|
|
19991
|
+
} else {
|
|
19992
|
+
return adHocRatings[participantId] || defaultRating;
|
|
19993
|
+
}
|
|
19994
|
+
});
|
|
19995
|
+
}
|
|
19996
|
+
|
|
19997
|
+
function getPairings({
|
|
19998
|
+
tournamentParticipants,
|
|
19999
|
+
adHocRatings = {},
|
|
20000
|
+
possiblePairings,
|
|
20001
|
+
// participant keyed; provides array of possible opponents
|
|
20002
|
+
uniquePairings,
|
|
20003
|
+
// hashes of all possible participantId pairings
|
|
20004
|
+
maxIterations,
|
|
20005
|
+
deltaObjects,
|
|
20006
|
+
// difference in rating between paired participants
|
|
20007
|
+
valueObjects,
|
|
20008
|
+
// calculated value of a pairing of participants, used for sorting pairings
|
|
20009
|
+
eventType,
|
|
20010
|
+
scaleName,
|
|
20011
|
+
salted
|
|
20012
|
+
}) {
|
|
20013
|
+
uniquePairings.forEach((pairing) => {
|
|
20014
|
+
const ratings = getSideRatings({
|
|
20015
|
+
tournamentParticipants,
|
|
20016
|
+
adHocRatings,
|
|
20017
|
+
scaleName,
|
|
20018
|
+
eventType,
|
|
20019
|
+
pairing
|
|
20020
|
+
});
|
|
20021
|
+
const salting = typeof salted === "number" && salted || 0.5;
|
|
20022
|
+
const salt = salted && (Math.round(Math.random()) ? salting : salting * -1) || 0;
|
|
20023
|
+
const ratingsDifference = Math.abs(ratings[0] - ratings[1]) + salt;
|
|
20024
|
+
const pairingDelta = Math.abs(ratings[0] - ratings[1]);
|
|
20025
|
+
deltaObjects[pairing] = pairingDelta;
|
|
20026
|
+
if (!valueObjects[pairing])
|
|
20027
|
+
valueObjects[pairing] = 0;
|
|
20028
|
+
valueObjects[pairing] += ratingsDifference ? Math.pow(ratingsDifference, 2) : 0;
|
|
20029
|
+
});
|
|
20030
|
+
const valueSortedPairings = uniquePairings.map((pairing) => ({ pairing, value: valueObjects[pairing] })).sort((a, b) => a.value - b.value);
|
|
20031
|
+
const { pairingValues } = getParticipantPairingValues({
|
|
20032
|
+
possiblePairings,
|
|
20033
|
+
valueObjects
|
|
20034
|
+
});
|
|
20035
|
+
const { candidate, candidatesCount, deltaCandidate, iterations } = generateCandidate({
|
|
20036
|
+
valueSortedPairings,
|
|
20037
|
+
maxIterations,
|
|
20038
|
+
pairingValues,
|
|
20039
|
+
deltaObjects,
|
|
20040
|
+
valueObjects
|
|
20041
|
+
});
|
|
20042
|
+
const { participantIdPairings } = candidate;
|
|
20043
|
+
return {
|
|
20044
|
+
participantIdPairings,
|
|
20045
|
+
candidatesCount,
|
|
20046
|
+
deltaCandidate,
|
|
20047
|
+
iterations,
|
|
20048
|
+
candidate
|
|
20049
|
+
};
|
|
20050
|
+
}
|
|
20051
|
+
|
|
20052
|
+
const ENCOUNTER_VALUE = 100;
|
|
20053
|
+
const SAME_TEAM_VALUE = 100;
|
|
20054
|
+
const MAX_ITERATIONS = 4e3;
|
|
19838
20055
|
function generateDrawMaticRound({
|
|
20056
|
+
encounterValue = ENCOUNTER_VALUE,
|
|
20057
|
+
sameTeamValue = SAME_TEAM_VALUE,
|
|
19839
20058
|
maxIterations = MAX_ITERATIONS,
|
|
19840
20059
|
generateMatchUps = true,
|
|
19841
20060
|
tournamentParticipants,
|
|
@@ -19845,9 +20064,11 @@ function generateDrawMaticRound({
|
|
|
19845
20064
|
drawDefinition,
|
|
19846
20065
|
adHocRatings,
|
|
19847
20066
|
structureId,
|
|
20067
|
+
salted = 0.5,
|
|
19848
20068
|
matchUpIds,
|
|
19849
20069
|
eventType,
|
|
19850
|
-
structure
|
|
20070
|
+
structure,
|
|
20071
|
+
scaleName
|
|
19851
20072
|
}) {
|
|
19852
20073
|
if (!drawDefinition)
|
|
19853
20074
|
return { error: MISSING_DRAW_DEFINITION };
|
|
@@ -19866,7 +20087,7 @@ function generateDrawMaticRound({
|
|
|
19866
20087
|
for (const pairing of encounters) {
|
|
19867
20088
|
if (!valueObjects[pairing])
|
|
19868
20089
|
valueObjects[pairing] = 0;
|
|
19869
|
-
valueObjects[pairing] +=
|
|
20090
|
+
valueObjects[pairing] += encounterValue;
|
|
19870
20091
|
}
|
|
19871
20092
|
const teamParticipants = tournamentParticipants?.filter(
|
|
19872
20093
|
({ participantType }) => participantType === TEAM
|
|
@@ -19878,7 +20099,7 @@ function generateDrawMaticRound({
|
|
|
19878
20099
|
for (const pairing of uniquePairings2) {
|
|
19879
20100
|
if (!valueObjects[pairing])
|
|
19880
20101
|
valueObjects[pairing] = 0;
|
|
19881
|
-
valueObjects[pairing] +=
|
|
20102
|
+
valueObjects[pairing] += sameTeamValue;
|
|
19882
20103
|
}
|
|
19883
20104
|
}
|
|
19884
20105
|
}
|
|
@@ -19896,9 +20117,11 @@ function generateDrawMaticRound({
|
|
|
19896
20117
|
deltaObjects,
|
|
19897
20118
|
valueObjects,
|
|
19898
20119
|
eventType,
|
|
19899
|
-
|
|
20120
|
+
scaleName,
|
|
20121
|
+
structure,
|
|
20122
|
+
salted
|
|
19900
20123
|
};
|
|
19901
|
-
const { candidatesCount, participantIdPairings, iterations } = getPairings(params);
|
|
20124
|
+
const { candidatesCount, participantIdPairings, iterations, candidate } = getPairings(params);
|
|
19902
20125
|
if (!candidatesCount)
|
|
19903
20126
|
return { error: NO_CANDIDATES };
|
|
19904
20127
|
let matchUps;
|
|
@@ -19916,122 +20139,17 @@ function generateDrawMaticRound({
|
|
|
19916
20139
|
return result;
|
|
19917
20140
|
matchUps = result.matchUps;
|
|
19918
20141
|
}
|
|
20142
|
+
const { maxDelta, maxDiff } = candidate;
|
|
19919
20143
|
return {
|
|
19920
20144
|
...SUCCESS,
|
|
19921
20145
|
participantIdPairings,
|
|
19922
20146
|
candidatesCount,
|
|
19923
20147
|
iterations,
|
|
19924
|
-
matchUps
|
|
20148
|
+
matchUps,
|
|
20149
|
+
maxDelta,
|
|
20150
|
+
maxDiff
|
|
19925
20151
|
};
|
|
19926
20152
|
}
|
|
19927
|
-
function getSideRatings({
|
|
19928
|
-
tournamentParticipants,
|
|
19929
|
-
adHocRatings,
|
|
19930
|
-
eventType,
|
|
19931
|
-
pairing
|
|
19932
|
-
}) {
|
|
19933
|
-
return pairing.split("|").map((participantId) => {
|
|
19934
|
-
if (eventType === DOUBLES) {
|
|
19935
|
-
const individualParticipantIds = tournamentParticipants?.find(
|
|
19936
|
-
(participant) => participant.participantId === participantId
|
|
19937
|
-
)?.individualParticipantIds;
|
|
19938
|
-
return !individualParticipantIds ? DEFAULT_RATING * 2 : individualParticipantIds?.map(
|
|
19939
|
-
(participantId2) => adHocRatings[participantId2 || DEFAULT_RATING]
|
|
19940
|
-
);
|
|
19941
|
-
} else {
|
|
19942
|
-
return adHocRatings[participantId] || DEFAULT_RATING;
|
|
19943
|
-
}
|
|
19944
|
-
});
|
|
19945
|
-
}
|
|
19946
|
-
function getPairings({
|
|
19947
|
-
tournamentParticipants,
|
|
19948
|
-
adHocRatings = {},
|
|
19949
|
-
possiblePairings,
|
|
19950
|
-
// participant keyed; provides array of possible opponents
|
|
19951
|
-
uniquePairings,
|
|
19952
|
-
// hashes of all possible participantId pairings
|
|
19953
|
-
maxIterations,
|
|
19954
|
-
deltaObjects,
|
|
19955
|
-
// difference in rating between paired participants
|
|
19956
|
-
valueObjects,
|
|
19957
|
-
// calculated value of a pairing of participants, used for sorting pairings
|
|
19958
|
-
eventType
|
|
19959
|
-
}) {
|
|
19960
|
-
uniquePairings.forEach((pairing) => {
|
|
19961
|
-
const ratings = getSideRatings({
|
|
19962
|
-
tournamentParticipants,
|
|
19963
|
-
adHocRatings,
|
|
19964
|
-
eventType,
|
|
19965
|
-
pairing
|
|
19966
|
-
});
|
|
19967
|
-
const ratingsDifference = Math.abs(ratings[0] - ratings[1]) + 1;
|
|
19968
|
-
deltaObjects[pairing] = Math.abs(ratings[0] - ratings[1]);
|
|
19969
|
-
if (!valueObjects[pairing])
|
|
19970
|
-
valueObjects[pairing] = 0;
|
|
19971
|
-
valueObjects[pairing] += Math.pow(ratingsDifference, 2);
|
|
19972
|
-
});
|
|
19973
|
-
const valueSortedPairings = uniquePairings.map((pairing) => ({ pairing, value: valueObjects[pairing] })).sort((a, b) => a.value - b.value);
|
|
19974
|
-
const { pairingValues } = getParticipantPairingValues({
|
|
19975
|
-
possiblePairings,
|
|
19976
|
-
valueObjects
|
|
19977
|
-
});
|
|
19978
|
-
const { candidate, candidatesCount, iterations } = generateCandidate({
|
|
19979
|
-
valueSortedPairings,
|
|
19980
|
-
maxIterations,
|
|
19981
|
-
pairingValues,
|
|
19982
|
-
deltaObjects
|
|
19983
|
-
});
|
|
19984
|
-
const { participantIdPairings } = candidate;
|
|
19985
|
-
return { candidatesCount, participantIdPairings, iterations };
|
|
19986
|
-
}
|
|
19987
|
-
function getPairingsData({ participantIds }) {
|
|
19988
|
-
const possiblePairings = {};
|
|
19989
|
-
const uniquePairings = [];
|
|
19990
|
-
participantIds.forEach((participantId) => {
|
|
19991
|
-
possiblePairings[participantId] = participantIds.filter(
|
|
19992
|
-
(id) => id !== participantId
|
|
19993
|
-
);
|
|
19994
|
-
possiblePairings[participantId].forEach((id) => {
|
|
19995
|
-
const pairing = pairingHash(id, participantId);
|
|
19996
|
-
if (!uniquePairings.includes(pairing))
|
|
19997
|
-
uniquePairings.push(pairing);
|
|
19998
|
-
});
|
|
19999
|
-
});
|
|
20000
|
-
const deltaObjects = Object.assign(
|
|
20001
|
-
{},
|
|
20002
|
-
...uniquePairings.map((pairing) => ({ [pairing]: 0 }))
|
|
20003
|
-
);
|
|
20004
|
-
return { uniquePairings, possiblePairings, deltaObjects };
|
|
20005
|
-
}
|
|
20006
|
-
function getEncounters({ matchUps }) {
|
|
20007
|
-
const encounters = [];
|
|
20008
|
-
for (const matchUp of matchUps) {
|
|
20009
|
-
const participantIds = matchUp.sides.map(getParticipantId);
|
|
20010
|
-
if (participantIds.length === 2) {
|
|
20011
|
-
const [p1, p2] = participantIds;
|
|
20012
|
-
const pairing = pairingHash(p1, p2);
|
|
20013
|
-
if (!encounters.includes(pairing))
|
|
20014
|
-
encounters.push(pairing);
|
|
20015
|
-
}
|
|
20016
|
-
}
|
|
20017
|
-
return { encounters };
|
|
20018
|
-
}
|
|
20019
|
-
function getParticipantPairingValues({ possiblePairings, valueObjects }) {
|
|
20020
|
-
const pairingValues = {};
|
|
20021
|
-
for (const participantId of Object.keys(possiblePairings)) {
|
|
20022
|
-
const participantValues = possiblePairings[participantId].map(
|
|
20023
|
-
(opponent) => pairingValue(participantId, opponent)
|
|
20024
|
-
);
|
|
20025
|
-
pairingValues[participantId] = participantValues.sort(
|
|
20026
|
-
(a, b) => a.value - b.value
|
|
20027
|
-
);
|
|
20028
|
-
}
|
|
20029
|
-
function pairingValue(participantId, opponent) {
|
|
20030
|
-
const key = pairingHash(participantId, opponent);
|
|
20031
|
-
return { opponent, value: valueObjects[key] };
|
|
20032
|
-
}
|
|
20033
|
-
return { pairingValues };
|
|
20034
|
-
}
|
|
20035
20153
|
|
|
20036
20154
|
function generateQualifyingLink({
|
|
20037
20155
|
targetEntryRound = 1,
|
|
@@ -22567,10 +22685,13 @@ function prepareStage(params) {
|
|
|
22567
22685
|
function drawMatic({
|
|
22568
22686
|
tournamentParticipants,
|
|
22569
22687
|
restrictEntryStatus,
|
|
22570
|
-
|
|
22688
|
+
adHocRatings = {},
|
|
22571
22689
|
generateMatchUps,
|
|
22690
|
+
tournamentRecord,
|
|
22572
22691
|
addToStructure,
|
|
22573
22692
|
participantIds,
|
|
22693
|
+
encounterValue,
|
|
22694
|
+
sameTeamValue,
|
|
22574
22695
|
drawDefinition,
|
|
22575
22696
|
scaleAccessor,
|
|
22576
22697
|
maxIterations,
|
|
@@ -22579,6 +22700,7 @@ function drawMatic({
|
|
|
22579
22700
|
scaleName,
|
|
22580
22701
|
// custom rating name to seed dynamic ratings
|
|
22581
22702
|
eventType,
|
|
22703
|
+
salted,
|
|
22582
22704
|
event
|
|
22583
22705
|
}) {
|
|
22584
22706
|
if (typeof drawDefinition !== "object" || drawDefinition.drawType && drawDefinition.drawType !== AD_HOC) {
|
|
@@ -22621,12 +22743,16 @@ function drawMatic({
|
|
|
22621
22743
|
if (!structureIsAdHoc)
|
|
22622
22744
|
return { error: INVALID_DRAW_DEFINITION };
|
|
22623
22745
|
tournamentParticipants = tournamentParticipants ?? tournamentRecord.participants ?? [];
|
|
22624
|
-
const adHocRatings = {};
|
|
22625
22746
|
for (const participantId of participantIds ?? []) {
|
|
22626
22747
|
const participant = tournamentParticipants?.find(
|
|
22627
22748
|
(participant2) => participant2.participantId === participantId
|
|
22628
22749
|
);
|
|
22629
|
-
let scaleValue = getScaleValue({
|
|
22750
|
+
let scaleValue = getScaleValue({
|
|
22751
|
+
scaleName: `${scaleName}.${DYNAMIC}`,
|
|
22752
|
+
scaleAccessor,
|
|
22753
|
+
participant,
|
|
22754
|
+
eventType
|
|
22755
|
+
});
|
|
22630
22756
|
if (!scaleValue && scaleName) {
|
|
22631
22757
|
scaleValue = getScaleValue({
|
|
22632
22758
|
scaleAccessor,
|
|
@@ -22635,32 +22761,36 @@ function drawMatic({
|
|
|
22635
22761
|
eventType
|
|
22636
22762
|
});
|
|
22637
22763
|
}
|
|
22638
|
-
if (scaleValue)
|
|
22764
|
+
if (scaleValue && !adHocRatings[participantId])
|
|
22639
22765
|
adHocRatings[participantId] = scaleValue;
|
|
22640
22766
|
}
|
|
22641
22767
|
return generateDrawMaticRound({
|
|
22642
22768
|
tournamentParticipants,
|
|
22643
|
-
tournamentRecord,
|
|
22644
22769
|
generateMatchUps,
|
|
22645
|
-
|
|
22770
|
+
tournamentRecord,
|
|
22646
22771
|
addToStructure,
|
|
22772
|
+
participantIds,
|
|
22773
|
+
encounterValue,
|
|
22774
|
+
sameTeamValue,
|
|
22647
22775
|
drawDefinition,
|
|
22648
22776
|
maxIterations,
|
|
22649
22777
|
adHocRatings,
|
|
22650
22778
|
matchUpIds,
|
|
22651
22779
|
structure,
|
|
22652
|
-
eventType
|
|
22780
|
+
eventType,
|
|
22781
|
+
salted
|
|
22653
22782
|
});
|
|
22654
22783
|
}
|
|
22655
22784
|
function getScaleValue({
|
|
22656
|
-
|
|
22657
|
-
scaleName = "dynamic",
|
|
22785
|
+
scaleType = RATING,
|
|
22658
22786
|
scaleAccessor,
|
|
22659
|
-
participant
|
|
22787
|
+
participant,
|
|
22788
|
+
scaleName,
|
|
22789
|
+
eventType
|
|
22660
22790
|
}) {
|
|
22661
22791
|
const scaleAttributes = {
|
|
22662
22792
|
eventType: eventType || TypeEnum.Singles,
|
|
22663
|
-
scaleType
|
|
22793
|
+
scaleType,
|
|
22664
22794
|
scaleName
|
|
22665
22795
|
};
|
|
22666
22796
|
const result = participant && participantScaleItem({
|