diff --git a/lib/lc/fake_client.ts b/lib/lc/fake_client.ts index 7775e4d..0bb5fb9 100644 --- a/lib/lc/fake_client.ts +++ b/lib/lc/fake_client.ts @@ -5,12 +5,14 @@ import type { } from "./client_interface.ts"; export const FAKE_LC_USERNAME = "fake_lc_username"; +export const FAKE_LC_QUESTION_NUMBER = 0; export const FAKE_LC_QUESTION_NAME = "fake_lc_question_name"; export const FAKE_LC_QUESTION_TITLE = "fake_lc_question_title"; export const FAKE_LC_QUESTION_URL = "fake_lc_question_url"; export const FAKE_LC_QUESTION_DIFFICULTY = "fake_lc_question_difficulty"; export const FAKE_LC_QUESTION_DATE = "2023-07-31"; export const FAKE_LC_QUESTION: LCQuestion = { + number: FAKE_LC_QUESTION_NUMBER, name: FAKE_LC_QUESTION_NAME, title: FAKE_LC_QUESTION_TITLE, url: FAKE_LC_QUESTION_URL, diff --git a/lib/leaderboard/scores.ts b/lib/leaderboard/scores.ts index 3a86483..1496f96 100644 --- a/lib/leaderboard/scores.ts +++ b/lib/leaderboard/scores.ts @@ -143,14 +143,21 @@ export function defaultModifyScore(score: number): number { * formatScores formats the scores of all players in a season. */ export function formatScores(season: api.Season): string { - return Object.entries(season.scores) - .sort(({ 1: scoreA }, { 1: scoreB }) => scoreB - scoreA) - .map(([playerID, score], i) => { - const player = season.players[playerID]; - const formattedScore = String(score).padStart(3, " "); - const formattedSubmissions = formatSubmissions(season, playerID); - const formattedRank = formatRank(i + 1); - return `${formattedScore} ${formattedSubmissions} ${player.lc_username} (${formattedRank})`; + return Object.entries( + Object.groupBy( + Object.entries(season.scores), + ([, score]) => score, + ), + ) + .toSorted((a, b) => b[1]![0][1] - a[1]![0][1]) + .flatMap(([score, entries], i) => { + const formattedScore = score.padStart(3, " "); + return entries?.map(([playerID]) => { + const player = season.players[playerID]; + const formattedSubmissions = formatSubmissions(season, playerID); + const formattedRank = formatRank(i + 1); + return `${formattedScore} ${formattedSubmissions} ${player.lc_username} (${formattedRank})`; + }); }) .join("\n"); } @@ -240,19 +247,19 @@ export function formatRank(rank: number): string { export function formatDifficulty(difficulty?: string): string { switch (difficulty) { case "Easy": { - return "๐ŸŸข"; + return "๐ŸŸฉ"; } case "Medium": { - return "๐ŸŸ "; + return "๐ŸŸง"; } case "Hard": { - return "๐Ÿ”ด"; + return "๐ŸŸฅ"; } default: { - return "ยท"; + return "๐Ÿ”ฒ"; } } } diff --git a/lib/leaderboard/scores_test.ts b/lib/leaderboard/scores_test.ts index d0f3e29..f6bd756 100644 --- a/lib/leaderboard/scores_test.ts +++ b/lib/leaderboard/scores_test.ts @@ -4,8 +4,9 @@ import { calculateScores, makeDefaultCalculateScoresOptions, } from "./scores.ts"; +import type * as api from "lc-dailies/lib/api/types.ts"; -const FAKE_SEASON = { +const FAKE_SEASON: api.Season = { "id": "01H8T4MM00BQHHK7VTTEJE1WAS", "start_date": "Sun, 27 Aug 2023 00:00:00 GMT", "players": { @@ -20,6 +21,7 @@ const FAKE_SEASON = { }, "questions": { "implement-stack-using-queues": { + "number": 225, "name": "implement-stack-using-queues", "date": "2023-08-28", "title": "Implement Stack using Queues", @@ -27,6 +29,7 @@ const FAKE_SEASON = { "url": "https://leetcode.com/problems/implement-stack-using-queues/", }, "counting-bits": { + "number": 338, "name": "counting-bits", "date": "2023-09-01", "title": "Counting Bits", @@ -56,6 +59,7 @@ const FAKE_SEASON = { }, }, }, + scores: {}, }; Deno.test("calculatePlayerScore calculates the score of a player", () => { diff --git a/lib/leaderboard/sync_test.ts b/lib/leaderboard/sync_test.ts index 7c47359..8434b27 100644 --- a/lib/leaderboard/sync_test.ts +++ b/lib/leaderboard/sync_test.ts @@ -1,8 +1,9 @@ import { assertEquals } from "@std/assert"; -import type { LCSubmission } from "lc-dailies/lib/lc/mod.ts"; +import type { LCQuestion, LCSubmission } from "lc-dailies/lib/lc/mod.ts"; import { sync } from "./sync.ts"; +import type * as api from "lc-dailies/lib/api/types.ts"; -const FAKE_UNSYNCED_SEASON = { +const FAKE_UNSYNCED_SEASON: api.Season = { "id": "01H8T4MM00BQHHK7VTTEJE1WAS", "start_date": "Sun, 27 Aug 2023 00:00:00 GMT", "players": { @@ -17,6 +18,7 @@ const FAKE_UNSYNCED_SEASON = { }, "questions": { "implement-stack-using-queues": { + "number": 225, "name": "implement-stack-using-queues", "date": "2023-08-28", "title": "Implement Stack using Queues", @@ -24,6 +26,7 @@ const FAKE_UNSYNCED_SEASON = { "url": "https://leetcode.com/problems/implement-stack-using-queues/", }, "counting-bits": { + "number": 338, "name": "counting-bits", "date": "2023-09-01", "title": "Counting Bits", @@ -56,7 +59,8 @@ const FAKE_UNSYNCED_SEASON = { "scores": {}, }; -const FAKE_QUESTION = { +const FAKE_QUESTION: LCQuestion = { + number: 7, name: "reverse-integer", date: "2023-09-02", title: "Reverse Integer", @@ -64,14 +68,14 @@ const FAKE_QUESTION = { url: "https://leetcode.com/problems/reverse-integer/", }; -const FAKE_SUBMISSION = { +const FAKE_SUBMISSION: LCSubmission = { id: "8008569420", name: "reverse-integer", title: "Reverse Integer", timestamp: "1693627483", }; -const FAKE_SYNCED_SEASON = { +const FAKE_SYNCED_SEASON: api.Season = { "id": "01H8T4MM00BQHHK7VTTEJE1WAS", "start_date": "Sun, 27 Aug 2023 00:00:00 GMT", "players": { @@ -86,6 +90,7 @@ const FAKE_SYNCED_SEASON = { }, "questions": { "implement-stack-using-queues": { + "number": 225, "name": "implement-stack-using-queues", "date": "2023-08-28", "title": "Implement Stack using Queues", @@ -93,6 +98,7 @@ const FAKE_SYNCED_SEASON = { "url": "https://leetcode.com/problems/implement-stack-using-queues/", }, "counting-bits": { + "number": 338, "name": "counting-bits", "date": "2023-09-01", "title": "Counting Bits",