tods-competition-factory 1.7.3 → 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 +332 -214
- package/dist/forge/generate.mjs.map +1 -1
- package/dist/forge/query.mjs.map +1 -1
- package/dist/forge/transform.mjs.map +1 -1
- package/dist/index.mjs +278 -173
- package/dist/index.mjs.map +1 -1
- package/dist/tods-competition-factory.development.cjs.js +301 -212
- 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.d.ts
CHANGED
|
@@ -1406,8 +1406,9 @@ type GenerateDrawMaticRoundArgs = {
|
|
|
1406
1406
|
};
|
|
1407
1407
|
restrictEntryStatus?: boolean;
|
|
1408
1408
|
drawDefinition: DrawDefinition;
|
|
1409
|
-
generateMatchUps?: boolean;
|
|
1410
1409
|
tournamentRecord: Tournament;
|
|
1410
|
+
generateMatchUps?: boolean;
|
|
1411
|
+
salted?: number | boolean;
|
|
1411
1412
|
participantIds?: string[];
|
|
1412
1413
|
addToStructure?: boolean;
|
|
1413
1414
|
maxIterations?: number;
|
|
@@ -1415,9 +1416,10 @@ type GenerateDrawMaticRoundArgs = {
|
|
|
1415
1416
|
structure?: Structure;
|
|
1416
1417
|
structureId?: string;
|
|
1417
1418
|
eventType?: TypeEnum;
|
|
1419
|
+
scaleName?: string;
|
|
1418
1420
|
drawId?: string;
|
|
1419
1421
|
};
|
|
1420
|
-
declare function generateDrawMaticRound({ maxIterations, generateMatchUps, tournamentParticipants, tournamentRecord, participantIds, addToStructure, drawDefinition, adHocRatings, structureId, matchUpIds, eventType, structure, }: GenerateDrawMaticRoundArgs): ResultType | {
|
|
1422
|
+
declare function generateDrawMaticRound({ maxIterations, generateMatchUps, tournamentParticipants, tournamentRecord, participantIds, addToStructure, drawDefinition, adHocRatings, structureId, salted, matchUpIds, eventType, structure, scaleName, }: GenerateDrawMaticRoundArgs): ResultType | {
|
|
1421
1423
|
participantIdPairings: string[][];
|
|
1422
1424
|
candidatesCount: number;
|
|
1423
1425
|
matchUps: MatchUp[];
|
|
@@ -1427,6 +1429,9 @@ declare function generateDrawMaticRound({ maxIterations, generateMatchUps, tourn
|
|
|
1427
1429
|
|
|
1428
1430
|
type DrawMaticArgs = {
|
|
1429
1431
|
tournamentParticipants?: HydratedParticipant[];
|
|
1432
|
+
adHocRatings?: {
|
|
1433
|
+
[key: string]: number;
|
|
1434
|
+
};
|
|
1430
1435
|
restrictEntryStatus?: boolean;
|
|
1431
1436
|
drawDefinition?: DrawDefinition;
|
|
1432
1437
|
tournamentRecord: Tournament;
|
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";
|
|
@@ -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,
|
|
@@ -19831,9 +19745,311 @@ function addAdHocMatchUps({
|
|
|
19831
19745
|
return { ...SUCCESS };
|
|
19832
19746
|
}
|
|
19833
19747
|
|
|
19834
|
-
|
|
19835
|
-
|
|
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
|
+
|
|
19836
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;
|
|
19837
20053
|
const MAX_ITERATIONS = 5e3;
|
|
19838
20054
|
function generateDrawMaticRound({
|
|
19839
20055
|
maxIterations = MAX_ITERATIONS,
|
|
@@ -19845,9 +20061,11 @@ function generateDrawMaticRound({
|
|
|
19845
20061
|
drawDefinition,
|
|
19846
20062
|
adHocRatings,
|
|
19847
20063
|
structureId,
|
|
20064
|
+
salted = 0.5,
|
|
19848
20065
|
matchUpIds,
|
|
19849
20066
|
eventType,
|
|
19850
|
-
structure
|
|
20067
|
+
structure,
|
|
20068
|
+
scaleName
|
|
19851
20069
|
}) {
|
|
19852
20070
|
if (!drawDefinition)
|
|
19853
20071
|
return { error: MISSING_DRAW_DEFINITION };
|
|
@@ -19896,7 +20114,9 @@ function generateDrawMaticRound({
|
|
|
19896
20114
|
deltaObjects,
|
|
19897
20115
|
valueObjects,
|
|
19898
20116
|
eventType,
|
|
19899
|
-
|
|
20117
|
+
scaleName,
|
|
20118
|
+
structure,
|
|
20119
|
+
salted
|
|
19900
20120
|
};
|
|
19901
20121
|
const { candidatesCount, participantIdPairings, iterations } = getPairings(params);
|
|
19902
20122
|
if (!candidatesCount)
|
|
@@ -19924,114 +20144,6 @@ function generateDrawMaticRound({
|
|
|
19924
20144
|
matchUps
|
|
19925
20145
|
};
|
|
19926
20146
|
}
|
|
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
20147
|
|
|
20036
20148
|
function generateQualifyingLink({
|
|
20037
20149
|
targetEntryRound = 1,
|
|
@@ -22567,6 +22679,7 @@ function prepareStage(params) {
|
|
|
22567
22679
|
function drawMatic({
|
|
22568
22680
|
tournamentParticipants,
|
|
22569
22681
|
restrictEntryStatus,
|
|
22682
|
+
adHocRatings = {},
|
|
22570
22683
|
tournamentRecord,
|
|
22571
22684
|
generateMatchUps,
|
|
22572
22685
|
addToStructure,
|
|
@@ -22621,12 +22734,16 @@ function drawMatic({
|
|
|
22621
22734
|
if (!structureIsAdHoc)
|
|
22622
22735
|
return { error: INVALID_DRAW_DEFINITION };
|
|
22623
22736
|
tournamentParticipants = tournamentParticipants ?? tournamentRecord.participants ?? [];
|
|
22624
|
-
const adHocRatings = {};
|
|
22625
22737
|
for (const participantId of participantIds ?? []) {
|
|
22626
22738
|
const participant = tournamentParticipants?.find(
|
|
22627
22739
|
(participant2) => participant2.participantId === participantId
|
|
22628
22740
|
);
|
|
22629
|
-
let scaleValue = getScaleValue({
|
|
22741
|
+
let scaleValue = getScaleValue({
|
|
22742
|
+
scaleName: `${scaleName}.${DYNAMIC}`,
|
|
22743
|
+
scaleAccessor,
|
|
22744
|
+
participant,
|
|
22745
|
+
eventType
|
|
22746
|
+
});
|
|
22630
22747
|
if (!scaleValue && scaleName) {
|
|
22631
22748
|
scaleValue = getScaleValue({
|
|
22632
22749
|
scaleAccessor,
|
|
@@ -22635,7 +22752,7 @@ function drawMatic({
|
|
|
22635
22752
|
eventType
|
|
22636
22753
|
});
|
|
22637
22754
|
}
|
|
22638
|
-
if (scaleValue)
|
|
22755
|
+
if (scaleValue && !adHocRatings[participantId])
|
|
22639
22756
|
adHocRatings[participantId] = scaleValue;
|
|
22640
22757
|
}
|
|
22641
22758
|
return generateDrawMaticRound({
|
|
@@ -22653,14 +22770,15 @@ function drawMatic({
|
|
|
22653
22770
|
});
|
|
22654
22771
|
}
|
|
22655
22772
|
function getScaleValue({
|
|
22656
|
-
|
|
22657
|
-
scaleName = "dynamic",
|
|
22773
|
+
scaleType = RATING,
|
|
22658
22774
|
scaleAccessor,
|
|
22659
|
-
participant
|
|
22775
|
+
participant,
|
|
22776
|
+
scaleName,
|
|
22777
|
+
eventType
|
|
22660
22778
|
}) {
|
|
22661
22779
|
const scaleAttributes = {
|
|
22662
22780
|
eventType: eventType || TypeEnum.Singles,
|
|
22663
|
-
scaleType
|
|
22781
|
+
scaleType,
|
|
22664
22782
|
scaleName
|
|
22665
22783
|
};
|
|
22666
22784
|
const result = participant && participantScaleItem({
|