Sort performance stats panel by dialect and level#232
Conversation
Implement custom sorting comparator for dialect-level stats in game statistics panel, ordering dialects by 四縣 -> 海陸 -> 大埔 -> 饒平 -> 詔安, and levels by 基礎級 -> 初級 -> 中級 -> 中高級 -> 高級 -> 教典. Features robust substring-based parsing supporting both short and long names. Co-authored-by: Aiuanyu <93833368+Aiuanyu@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
Deploying hakspring with
|
| Latest commit: |
3e70283
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c2678f6f.hakspring.pages.dev |
| Branch Preview URL: | https://jules-10727692522866028451-4.hakspring.pages.dev |
There was a problem hiding this comment.
Code Review
This pull request updates the version of game-ui.js in index.html and refactors the sorting logic for levels in game-ui.js to sort by dialect and level order instead of total counts. The reviewer suggested optimizing this sorting logic by moving the order arrays and parsing helper function outside of the comparator callback, and caching the parsed results to prevent redundant allocations and string scanning.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| const sortedLevels = Object.entries(data.levels).sort((a, b) => { | ||
| const lvlA = a[0]; | ||
| const lvlB = b[0]; | ||
| const dialectOrder = ['四', '海', '大', '平', '安']; | ||
| const levelOrder = ['基', '初', '中', '中高', '高', '教典']; | ||
|
|
||
| const parseLevel = (lvl) => { | ||
| let dialect = ''; | ||
| let level = ''; | ||
|
|
||
| // Find dialect by searching for inclusion of any dialect character | ||
| for (const d of dialectOrder) { | ||
| if (lvl.includes(d)) { | ||
| dialect = d; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| // Find level by searching for inclusion of level keywords | ||
| if (lvl.includes('教典')) { | ||
| level = '教典'; | ||
| } else { | ||
| // Check '中高' before '中' to avoid partial matching of '中' first | ||
| const levelKeywords = ['基', '初', '中高', '中', '高']; | ||
| for (const l of levelKeywords) { | ||
| if (lvl.includes(l)) { | ||
| level = l; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| return { dialect, level }; | ||
| }; | ||
|
|
||
| const aInfo = parseLevel(lvlA); | ||
| const bInfo = parseLevel(lvlB); | ||
|
|
||
| let aDialectIdx = dialectOrder.indexOf(aInfo.dialect); | ||
| let bDialectIdx = dialectOrder.indexOf(bInfo.dialect); | ||
| if (aDialectIdx === -1) aDialectIdx = 999; | ||
| if (bDialectIdx === -1) bDialectIdx = 999; | ||
|
|
||
| if (aDialectIdx !== bDialectIdx) { | ||
| return aDialectIdx - bDialectIdx; | ||
| } | ||
|
|
||
| let aLevelIdx = levelOrder.indexOf(aInfo.level); | ||
| let bLevelIdx = levelOrder.indexOf(bInfo.level); | ||
| if (aLevelIdx === -1) aLevelIdx = 999; | ||
| if (bLevelIdx === -1) bLevelIdx = 999; | ||
|
|
||
| if (aLevelIdx !== bLevelIdx) { | ||
| return aLevelIdx - bLevelIdx; | ||
| } | ||
|
|
||
| return lvlA.localeCompare(lvlB); | ||
| }); |
There was a problem hiding this comment.
Defining dialectOrder, levelOrder, and the helper function parseLevel inside the sort comparator callback causes them to be re-created on every single comparison. Since sorting is an
Additionally, we can cache the parsed results of parseLevel to avoid redundant string scanning for the same keys during the sort process.
const dialectOrder = ['四', '海', '大', '平', '安'];
const levelOrder = ['基', '初', '中', '中高', '高', '教典'];
const parseCache = {};
const parseLevel = (lvl) => {
if (parseCache[lvl]) return parseCache[lvl];
let dialect = '';
let level = '';
// Find dialect by searching for inclusion of any dialect character
for (const d of dialectOrder) {
if (lvl.includes(d)) {
dialect = d;
break;
}
}
// Find level by searching for inclusion of level keywords
if (lvl.includes('教典')) {
level = '教典';
} else {
// Check '中高' before '中' to avoid partial matching of '中' first
const levelKeywords = ['基', '初', '中高', '中', '高'];
for (const l of levelKeywords) {
if (lvl.includes(l)) {
level = l;
break;
}
}
}
const result = { dialect, level };
parseCache[lvl] = result;
return result;
};
const sortedLevels = Object.entries(data.levels).sort((a, b) => {
const lvlA = a[0];
const lvlB = b[0];
const aInfo = parseLevel(lvlA);
const bInfo = parseLevel(lvlB);
let aDialectIdx = dialectOrder.indexOf(aInfo.dialect);
let bDialectIdx = dialectOrder.indexOf(bInfo.dialect);
if (aDialectIdx === -1) aDialectIdx = 999;
if (bDialectIdx === -1) bDialectIdx = 999;
if (aDialectIdx !== bDialectIdx) {
return aDialectIdx - bDialectIdx;
}
let aLevelIdx = levelOrder.indexOf(aInfo.level);
let bLevelIdx = levelOrder.indexOf(bInfo.level);
if (aLevelIdx === -1) aLevelIdx = 999;
if (bLevelIdx === -1) bLevelIdx = 999;
if (aLevelIdx !== bLevelIdx) {
return aLevelIdx - bLevelIdx;
}
return lvlA.localeCompare(lvlB);
});
Review of PR #232 — Sort performance stats panel by dialect and levelVerified the sort logic against A few minor, non-blocking notes:
No functional bugs found; the fallback |
Sorted performance stats panel dialect-level distribution by dialect order (四縣 -> 海陸 -> 大埔 -> 饒平 -> 詔安) and level difficulty order (基礎級 -> 初級 -> 中級 -> 中高級 -> 高級 -> 教典). Included cache busting version bump.
Fixes #231
PR created automatically by Jules for task 10727692522866028451 started by @Aiuanyu