fix: 토너먼트 예선 8명 기록을 보존
This commit is contained in:
@@ -71,6 +71,13 @@ const zParticipant = z.object({
|
|||||||
gl: z.number().int().optional(),
|
gl: z.number().int().optional(),
|
||||||
seedRank: z.number().int().optional(),
|
seedRank: z.number().int().optional(),
|
||||||
finalRank: z.number().int().optional(),
|
finalRank: z.number().int().optional(),
|
||||||
|
preliminaryGroupId: z.number().int().min(0).max(7).optional(),
|
||||||
|
preliminaryGroupNo: z.number().int().min(0).max(7).optional(),
|
||||||
|
preliminaryRank: z.number().int().min(1).max(8).optional(),
|
||||||
|
preliminaryWin: z.number().int().min(0).optional(),
|
||||||
|
preliminaryDraw: z.number().int().min(0).optional(),
|
||||||
|
preliminaryLose: z.number().int().min(0).optional(),
|
||||||
|
preliminaryGl: z.number().int().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const zMatch = z.object({
|
const zMatch = z.object({
|
||||||
|
|||||||
@@ -34,6 +34,13 @@ export interface TournamentParticipantEntry {
|
|||||||
gl?: number;
|
gl?: number;
|
||||||
seedRank?: number;
|
seedRank?: number;
|
||||||
finalRank?: number;
|
finalRank?: number;
|
||||||
|
preliminaryGroupId?: number;
|
||||||
|
preliminaryGroupNo?: number;
|
||||||
|
preliminaryRank?: number;
|
||||||
|
preliminaryWin?: number;
|
||||||
|
preliminaryDraw?: number;
|
||||||
|
preliminaryLose?: number;
|
||||||
|
preliminaryGl?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TournamentMatchEntry {
|
export interface TournamentMatchEntry {
|
||||||
|
|||||||
@@ -186,6 +186,8 @@ export const applyPreBattleStage = async (
|
|||||||
gl: 0,
|
gl: 0,
|
||||||
seedRank: 0,
|
seedRank: 0,
|
||||||
finalRank: 0,
|
finalRank: 0,
|
||||||
|
preliminaryGroupId: entry.groupId,
|
||||||
|
preliminaryGroupNo: entry.groupNo,
|
||||||
}));
|
}));
|
||||||
await store.setParticipants(grouped);
|
await store.setParticipants(grouped);
|
||||||
const nextState: TournamentState = {
|
const nextState: TournamentState = {
|
||||||
@@ -244,10 +246,17 @@ export const applyPreBattleStage = async (
|
|||||||
for (let groupId = 0; groupId < 8; groupId += 1) {
|
for (let groupId = 0; groupId < 8; groupId += 1) {
|
||||||
const groupEntries = ranked.filter((entry) => entry.groupId === groupId);
|
const groupEntries = ranked.filter((entry) => entry.groupId === groupId);
|
||||||
const ordered = sortByRanking(groupEntries);
|
const ordered = sortByRanking(groupEntries);
|
||||||
ordered.slice(0, 4).forEach((entry, idx) => {
|
ordered.forEach((entry, idx) => {
|
||||||
const target = ranked.find((item) => item.id === entry.id);
|
const target = ranked.find((item) => item.id === entry.id);
|
||||||
if (target) {
|
if (target) {
|
||||||
target.seedRank = idx + 1;
|
target.preliminaryGroupId = groupId;
|
||||||
|
target.preliminaryGroupNo = entry.groupNo;
|
||||||
|
target.preliminaryRank = idx + 1;
|
||||||
|
target.preliminaryWin = entry.win ?? 0;
|
||||||
|
target.preliminaryDraw = entry.draw ?? 0;
|
||||||
|
target.preliminaryLose = entry.lose ?? 0;
|
||||||
|
target.preliminaryGl = entry.gl ?? 0;
|
||||||
|
target.seedRank = idx < 4 ? idx + 1 : 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,17 +195,20 @@ export const assignManualApplicantGroup = (options: {
|
|||||||
extraSeed: `manual-group:${options.current.map((entry) => entry.id).join('-')}:${openGroupIds.join('-')}`,
|
extraSeed: `manual-group:${options.current.map((entry) => entry.id).join('-')}:${openGroupIds.join('-')}`,
|
||||||
});
|
});
|
||||||
const groupId = rng.choice(openGroupIds);
|
const groupId = rng.choice(openGroupIds);
|
||||||
|
const groupNo = groupCounts[groupId] ?? 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...options.applicant,
|
...options.applicant,
|
||||||
groupId,
|
groupId,
|
||||||
groupNo: groupCounts[groupId] ?? 0,
|
groupNo,
|
||||||
win: 0,
|
win: 0,
|
||||||
draw: 0,
|
draw: 0,
|
||||||
lose: 0,
|
lose: 0,
|
||||||
gl: 0,
|
gl: 0,
|
||||||
seedRank: 0,
|
seedRank: 0,
|
||||||
finalRank: 0,
|
finalRank: 0,
|
||||||
|
preliminaryGroupId: groupId,
|
||||||
|
preliminaryGroupNo: groupNo,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ describe('tournament router permissions and mutations', () => {
|
|||||||
expect(results.filter((result) => result.status === 'rejected')).toHaveLength(1);
|
expect(results.filter((result) => result.status === 'rejected')).toHaveLength(1);
|
||||||
const summary = await caller.tournament.getBettingSummary();
|
const summary = await caller.tournament.getBettingSummary();
|
||||||
expect(summary.myAmount).toBe(600);
|
expect(summary.myAmount).toBe(600);
|
||||||
|
expect(Object.values(summary.myTotals)).toEqual([600]);
|
||||||
expect(summary.totalAmount).toBe(600);
|
expect(summary.totalAmount).toBe(600);
|
||||||
expect(transport.gold.get(general.id)).toBe(2_400);
|
expect(transport.gold.get(general.id)).toBe(2_400);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -246,8 +246,9 @@ describe('tournament worker schedule compatibility', () => {
|
|||||||
groupNo,
|
groupNo,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
const groupCounts = Array.from({ length: 8 }, (_, groupId) =>
|
const groupCounts = Array.from(
|
||||||
current.filter((entry) => entry.groupId === groupId).length
|
{ length: 8 },
|
||||||
|
(_, groupId) => current.filter((entry) => entry.groupId === groupId).length
|
||||||
);
|
);
|
||||||
const openGroupId = groupCounts.findIndex((count) => count === 7);
|
const openGroupId = groupCounts.findIndex((count) => count === 7);
|
||||||
expect(openGroupId).toBeGreaterThanOrEqual(0);
|
expect(openGroupId).toBeGreaterThanOrEqual(0);
|
||||||
@@ -267,7 +268,16 @@ describe('tournament worker schedule compatibility', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(applicant).toMatchObject({ groupId: openGroupId, groupNo: 7, win: 0, draw: 0, lose: 0, gl: 0 });
|
expect(applicant).toMatchObject({
|
||||||
|
groupId: openGroupId,
|
||||||
|
groupNo: 7,
|
||||||
|
preliminaryGroupId: openGroupId,
|
||||||
|
preliminaryGroupNo: 7,
|
||||||
|
win: 0,
|
||||||
|
draw: 0,
|
||||||
|
lose: 0,
|
||||||
|
gl: 0,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('catches up from the stored schedule instead of discarding elapsed legacy phases', () => {
|
it('catches up from the stored schedule instead of discarding elapsed legacy phases', () => {
|
||||||
@@ -334,6 +344,7 @@ describe('tournament worker (in-memory)', () => {
|
|||||||
expect(entries.map((entry) => entry.groupNo).sort((a, b) => Number(a) - Number(b))).toEqual([
|
expect(entries.map((entry) => entry.groupNo).sort((a, b) => Number(a) - Number(b))).toEqual([
|
||||||
0, 1, 2, 3, 4, 5, 6, 7,
|
0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
]);
|
]);
|
||||||
|
expect(entries.every((entry) => entry.preliminaryGroupId === groupId)).toBe(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -648,14 +659,30 @@ describe('tournament worker (in-memory)', () => {
|
|||||||
expect(participants.find((entry) => entry.id === 1)).toMatchObject({ groupId: expect.any(Number) });
|
expect(participants.find((entry) => entry.id === 1)).toMatchObject({ groupId: expect.any(Number) });
|
||||||
expect(participants.find((entry) => entry.id === 1001)).toMatchObject({ groupId: expect.any(Number) });
|
expect(participants.find((entry) => entry.id === 1001)).toMatchObject({ groupId: expect.any(Number) });
|
||||||
expect(
|
expect(
|
||||||
Array.from({ length: 8 }, (_, groupId) =>
|
Array.from({ length: 8 }, (_, groupId) => participants.filter((entry) => entry.groupId === groupId).length)
|
||||||
participants.filter((entry) => entry.groupId === groupId).length
|
|
||||||
)
|
|
||||||
).toEqual(Array.from({ length: 8 }, () => 8));
|
).toEqual(Array.from({ length: 8 }, () => 8));
|
||||||
|
|
||||||
await store.setState(afterJoin);
|
await store.setState(afterJoin);
|
||||||
const finalState = await runTournamentToCompletion({ store, prisma, baseSeed: 'seed' });
|
const finalState = await runTournamentToCompletion({ store, prisma, baseSeed: 'seed' });
|
||||||
|
const finalParticipants = await store.getParticipants();
|
||||||
expect(finalState.stage).toBe(0);
|
expect(finalState.stage).toBe(0);
|
||||||
expect(finalState.winnerId).toBeDefined();
|
expect(finalState.winnerId).toBeDefined();
|
||||||
|
for (let groupId = 0; groupId < 8; groupId += 1) {
|
||||||
|
const preliminaryEntries = finalParticipants
|
||||||
|
.filter((entry) => entry.preliminaryGroupId === groupId)
|
||||||
|
.sort((lhs, rhs) => (lhs.preliminaryRank ?? 99) - (rhs.preliminaryRank ?? 99));
|
||||||
|
expect(preliminaryEntries).toHaveLength(8);
|
||||||
|
expect(preliminaryEntries.map((entry) => entry.preliminaryRank)).toEqual([1, 2, 3, 4, 5, 6, 7, 8]);
|
||||||
|
expect(
|
||||||
|
preliminaryEntries.every(
|
||||||
|
(entry) =>
|
||||||
|
entry.preliminaryGroupNo !== undefined &&
|
||||||
|
entry.preliminaryWin !== undefined &&
|
||||||
|
entry.preliminaryDraw !== undefined &&
|
||||||
|
entry.preliminaryLose !== undefined &&
|
||||||
|
entry.preliminaryGl !== undefined
|
||||||
|
)
|
||||||
|
).toBe(true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user