feat: Scoreboard: Ranking, Matrix, Event Log and Score Graph 1.01
This commit is contained in:
@@ -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', () => {
|
||||
|
||||
Reference in New Issue
Block a user