Skip to content

Commit 08506dd

Browse files
feat: add function for qualifier progression
1 parent 4df9f7b commit 08506dd

File tree

3 files changed

+165
-1
lines changed

3 files changed

+165
-1
lines changed

src/assemblies/governors/drawsGovernor/mutate.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export { removeDrawPositionAssignment } from '@Mutate/drawDefinitions/removeDraw
1111
export { automatedPlayoffPositioning } from '@Mutate/drawDefinitions/automatedPlayoffPositioning';
1212
export { modifySeedAssignment } from '@Mutate/drawDefinitions/entryGovernor/modifySeedAssignment';
1313
export { qualifierDrawPositionAssignment } from '@Mutate/matchUps/drawPositions/positionQualifier';
14+
export { qualifierProgression } from '@Mutate/drawDefinitions/positionGovernor/qualifierProgression';
1415
export { setStructureOrder } from '@Mutate/drawDefinitions/structureGovernor/setStructureOrder';
1516
export { attachQualifyingStructure } from '@Mutate/drawDefinitions/attachQualifyingStructure';
1617
export { renameStructures } from '@Mutate/drawDefinitions/structureGovernor/renameStructures';
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { findDrawDefinition } from '@Acquire/findDrawDefinition';
2+
import { findEvent } from '@Acquire/findEvent';
3+
import { findExtension } from '@Acquire/findExtension';
4+
import { findStructure } from '@Acquire/findStructure';
5+
import { qualifierDrawPositionAssignment } from '@Assemblies/governors/drawsGovernor';
6+
import { POSITION, QUALIFYING, WINNER } from '@Constants/drawDefinitionConstants';
7+
import { TALLY } from '@Constants/extensionConstants';
8+
import { BYE } from '@Constants/matchUpStatusConstants';
9+
import { POLICY_TYPE_POSITION_ACTIONS } from '@Constants/policyConstants';
10+
import { SUCCESS } from '@Constants/resultConstants';
11+
import { decorateResult } from '@Functions/global/decorateResult';
12+
import { getPositionAssignments, structureAssignedDrawPositions } from '@Query/drawDefinition/positionsGetter';
13+
import { isCompletedStructure } from '@Query/drawDefinition/structureActions';
14+
import { getAppliedPolicies } from '@Query/extensions/getAppliedPolicies';
15+
import { getAllStructureMatchUps } from '@Query/matchUps/getAllStructureMatchUps';
16+
import { getSourceStructureIdsAndRelevantLinks } from '@Query/structure/getSourceStructureIdsAndRelevantLinks';
17+
import { randomPop } from '@Tools/arrays';
18+
import { definedAttributes } from '@Tools/definedAttributes';
19+
import { ResultType } from '@Types/factoryTypes';
20+
import { DrawDefinition, Event, Structure, Tournament } from '@Types/tournamentTypes';
21+
22+
interface QualifierProgressionArgs {
23+
drawId: string;
24+
eventId: string;
25+
mainStructureId: string;
26+
tournamentRecord: Tournament;
27+
}
28+
29+
export function qualifierProgression({
30+
drawId,
31+
eventId,
32+
mainStructureId,
33+
tournamentRecord,
34+
}: QualifierProgressionArgs): ResultType {
35+
const qualifyingParticipantIds: string[] = [];
36+
37+
const drawDefinition = findDrawDefinition({ tournamentRecord, drawId })?.drawDefinition ?? ({} as DrawDefinition);
38+
const event = findEvent({ tournamentRecord, eventId })?.event ?? ({} as Event);
39+
const structure = findStructure({ drawDefinition, structureId: mainStructureId })?.structure ?? ({} as Structure);
40+
41+
const appliedPolicies =
42+
getAppliedPolicies({
43+
tournamentRecord,
44+
drawDefinition,
45+
structure,
46+
event,
47+
}).appliedPolicies ?? {};
48+
49+
const policy = appliedPolicies[POLICY_TYPE_POSITION_ACTIONS];
50+
const requireCompletedStructures = policy?.requireCompletedStructures;
51+
52+
const { qualifierPositions, positionAssignments } = structureAssignedDrawPositions({ structure });
53+
54+
if (!qualifierPositions.length) return decorateResult({ result: { error: 'NO_QUALIFIER_POSITIONS' } }); // update with error constant
55+
56+
const assignedParticipantIds = positionAssignments.map((assignment) => assignment.participantId).filter(Boolean);
57+
58+
const { relevantLinks: eliminationSourceLinks } =
59+
getSourceStructureIdsAndRelevantLinks({
60+
linkType: WINNER, // WINNER of qualifying structures will traverse link
61+
drawDefinition,
62+
structureId: structure.structureId,
63+
}) || {};
64+
65+
const { relevantLinks: roundRobinSourceLinks } =
66+
getSourceStructureIdsAndRelevantLinks({
67+
linkType: POSITION, // link will define how many finishingPositions traverse the link
68+
drawDefinition,
69+
structureId: structure.structureId,
70+
}) || {};
71+
72+
for (const sourceLink of eliminationSourceLinks) {
73+
const structure = drawDefinition.structures?.find(
74+
(structure) => structure.structureId === sourceLink.source.structureId,
75+
);
76+
if (structure?.stage !== QUALIFYING) continue;
77+
78+
const structureCompleted = isCompletedStructure({
79+
structureId: sourceLink.source.structureId,
80+
drawDefinition,
81+
});
82+
83+
if (!requireCompletedStructures || structureCompleted) {
84+
const qualifyingRoundNumber = structure.qualifyingRoundNumber;
85+
const { matchUps } = getAllStructureMatchUps({
86+
matchUpFilters: {
87+
...(qualifyingRoundNumber && {
88+
roundNumbers: [qualifyingRoundNumber],
89+
}),
90+
hasWinningSide: true,
91+
},
92+
afterRecoveryTimes: false,
93+
inContext: true,
94+
structure,
95+
});
96+
97+
for (const matchUp of matchUps) {
98+
const winningSide = matchUp.sides.find((side) => side?.sideNumber === matchUp.winningSide);
99+
const relevantSide = matchUp.matchUpStatus === BYE && matchUp.sides?.find(({ participantId }) => participantId);
100+
101+
if (winningSide || relevantSide) {
102+
const { participantId } = winningSide || relevantSide || {};
103+
if (participantId && !assignedParticipantIds.includes(participantId)) {
104+
qualifyingParticipantIds.push(participantId);
105+
}
106+
}
107+
}
108+
}
109+
}
110+
111+
for (const sourceLink of roundRobinSourceLinks) {
112+
const structure = drawDefinition?.structures?.find(
113+
(structure) => structure.structureId === sourceLink.source.structureId,
114+
);
115+
if (structure?.stage !== QUALIFYING) continue;
116+
117+
const structureCompleted = isCompletedStructure({
118+
structureId: sourceLink.source.structureId,
119+
drawDefinition,
120+
});
121+
122+
if (!requireCompletedStructures || structureCompleted) {
123+
const { positionAssignments } = getPositionAssignments({ structure });
124+
const relevantParticipantIds: any =
125+
positionAssignments
126+
?.map((assignment) => {
127+
const participantId = assignment.participantId;
128+
const results = findExtension({
129+
element: assignment,
130+
name: TALLY,
131+
}).extension?.value;
132+
133+
return results ? { participantId, groupOrder: results?.groupOrder } : {};
134+
})
135+
.filter(
136+
({ groupOrder, participantId }) => groupOrder === 1 && !assignedParticipantIds.includes(participantId),
137+
)
138+
.map(({ participantId }) => participantId) ?? [];
139+
140+
if (relevantParticipantIds) qualifyingParticipantIds.push(...relevantParticipantIds);
141+
}
142+
}
143+
144+
if (!qualifyingParticipantIds.length) return decorateResult({ result: { error: 'NO_QUALIFIERS_FOUND' } }); // update with error constant
145+
146+
qualifierPositions.forEach((position) => {
147+
const randomParticipantId = randomPop(qualifyingParticipantIds);
148+
randomParticipantId &&
149+
qualifierDrawPositionAssignment({
150+
qualifyingParticipantId: randomParticipantId,
151+
tournamentRecord,
152+
drawDefinition,
153+
drawPosition: position.drawPosition,
154+
structureId: structure.structureId,
155+
});
156+
});
157+
158+
return decorateResult({
159+
result: definedAttributes({
160+
...SUCCESS,
161+
}),
162+
});
163+
}

src/query/structure/getSourceStructureIdsAndRelevantLinks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { findStructure } from '@Acquire/findStructure';
55
type GetSourceStructureDetailArgs = {
66
drawDefinition: DrawDefinition;
77
finishingPosition?: string;
8-
targetRoundNumber: number;
8+
targetRoundNumber?: number;
99
structureId: string;
1010
linkType: string;
1111
};

0 commit comments

Comments
 (0)