AI Implementation feature(911): Scoreboard: Ranking, Matrix, Event Log and Score Graph 1.01 (#54)

This commit was merged in pull request #54.
This commit is contained in:
2026-07-23 06:03:13 +00:00
parent 4273662211
commit a39a7daee8
7 changed files with 365 additions and 56 deletions
+88
View File
@@ -8,6 +8,7 @@ import {
RankingRow,
applyRankingSort,
applySolveToGraph,
assignUniquePlayerColors,
dedupEventLogBySolveId,
formatSolveDateTime,
mutateMatrixFromSolve,
@@ -25,6 +26,52 @@ describe('stablePlayerColorIndex', () => {
});
});
describe('assignUniquePlayerColors', () => {
const ids = [
'PlayerA',
'PlayerB',
'PlayerC',
'Player04',
'Player05',
'Player06',
'Player07',
'Player08',
'Player09',
'Player10',
];
it('gives the documented colliding id set 10 distinct palette colors', () => {
const rows: RankingRow[] = ids.map((playerId) => ({
rank: 0,
playerId,
playerName: playerId,
solvedCount: 1,
points: 0,
colorIndex: stablePlayerColorIndex(playerId),
}));
const unique = assignUniquePlayerColors(rows, (r) => r.colorIndex);
expect(unique.length).toBe(ids.length);
const paletteHits = new Set(unique.map((r) => PLAYER_COLOR_PALETTE[r.colorIndex]));
expect(paletteHits.size).toBe(PLAYER_COLOR_PALETTE.length);
unique.forEach((r) => {
expect(r.colorIndex).toBeGreaterThanOrEqual(0);
expect(r.colorIndex).toBeLessThan(PLAYER_COLOR_PALETTE.length);
});
});
it('keeps the hashed index when there is no collision', () => {
const rows: RankingRow[] = [
{ rank: 0, playerId: 'p1', playerName: 'p1', solvedCount: 1, points: 10, colorIndex: stablePlayerColorIndex('p1') },
{ rank: 0, playerId: 'p2', playerName: 'p2', solvedCount: 1, points: 5, colorIndex: stablePlayerColorIndex('p2') },
];
const hashed1 = rows[0].colorIndex;
const hashed2 = rows[1].colorIndex;
const unique = assignUniquePlayerColors(rows, (r) => r.colorIndex);
expect(unique[0].colorIndex).toBe(hashed1);
expect(unique[1].colorIndex).toBe(hashed2);
});
});
describe('applyRankingSort', () => {
it('produces competition ranks with zero-pt rows at the bottom', () => {
const rows: RankingRow[] = [
@@ -114,6 +161,47 @@ describe('applySolveToGraph', () => {
);
expect(next.series).toEqual([]);
});
it('yields 10 unique polyline colors for the documented colliding id set', () => {
const ids = [
'PlayerA',
'PlayerB',
'PlayerC',
'Player04',
'Player05',
'Player06',
'Player07',
'Player08',
'Player09',
'Player10',
];
const start = '2025-01-01T00:00:00.000Z';
const end = '2025-01-02T00:00:00.000Z';
let view: any = null;
ids.forEach((playerId, idx) => {
const awarded = 100 - idx * 5;
view = applySolveToGraph(
view,
{
challengeId: `c${idx}`,
challengeName: `ch${idx}`,
categoryAbbreviation: 'CRY',
playerId,
playerName: playerId,
awardedPoints: awarded,
rankBonus: 0,
awardedAtUtc: `2025-01-01T01:00:0${idx}.000Z`,
position: idx + 1,
},
start,
end,
'2025-01-01T12:00:00.000Z',
);
});
expect(view.series.length).toBe(10);
const paletteHits = new Set(view.series.map((s: any) => PLAYER_COLOR_PALETTE[s.colorIndex]));
expect(paletteHits.size).toBe(10);
});
});
describe('mutateMatrixFromSolve', () => {