From 755951607d0bd89abdc410d12c0ca4d3a635aed2 Mon Sep 17 00:00:00 2001 From: zk Date: Wed, 17 Jun 2026 23:29:59 +0100 Subject: [PATCH] fix: fucking finally fix delta cells (#1683) --- typescript/client/src/lib/games/bms-pms.tsx | 18 ++++-------- typescript/client/src/lib/games/iidx.tsx | 16 +++-------- typescript/common/src/utils/util.ts | 32 ++++++++++++++++++++- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/typescript/client/src/lib/games/bms-pms.tsx b/typescript/client/src/lib/games/bms-pms.tsx index 2e2d6d56e..95142c754 100644 --- a/typescript/client/src/lib/games/bms-pms.tsx +++ b/typescript/client/src/lib/games/bms-pms.tsx @@ -6,7 +6,7 @@ import { GetEnumColour } from "#lib/game-implementations"; import { type GameClientImplementation } from "#lib/types"; import { IsNullish } from "#util/misc"; import { NumericSOV } from "#util/sorts"; -import { COLOUR_SET, type GamesForGroup, IIDXLIKE_GBOUNDARIES } from "tachi-common"; +import { COLOUR_SET, type GamesForGroup, RawIIDXGradeBoundaries } from "tachi-common"; import { FormatSieglindeBMS } from "tachi-common/config/game-support/bms"; import { bgc, CreateRatingSys } from "./_util"; @@ -67,7 +67,7 @@ const BASE_IMPL: GameClientImplementation = { ["Deltas", "Deltas", NumericSOV((x) => x.scoreData.percent)], ["Lamp", "Lamp", NumericSOV((x) => x.scoreData.enumIndexes.lamp)], ], - scoreCoreCells: ({ sc }) => ( + scoreCoreCells: ({ sc, chart }) => ( <> = { score={sc.scoreData.score} /> { - const max = Math.floor(sc.scoreData.score / (sc.scoreData.percent / 100)); - - const v = (deltaPercent / 100) * max; - - // i don't know if this is correct - // it's just really hard to work out. - return Math.round(v).toFixed(0); - }} + formatNumFn={(n) => Math.floor(n / 18).toString()} grade={sc.scoreData.grade} - gradeBoundaries={IIDXLIKE_GBOUNDARIES} - value={sc.scoreData.percent} + gradeBoundaries={RawIIDXGradeBoundaries(chart.data.notecount)} + value={sc.scoreData.score * 18} /> diff --git a/typescript/client/src/lib/games/iidx.tsx b/typescript/client/src/lib/games/iidx.tsx index 63a48a2b8..851d10e14 100644 --- a/typescript/client/src/lib/games/iidx.tsx +++ b/typescript/client/src/lib/games/iidx.tsx @@ -7,7 +7,7 @@ import { GetEnumColour } from "#lib/game-implementations"; import { type GameClientImplementation } from "#lib/types"; import { ChangeOpacity } from "#util/color-opacity"; import { NumericSOV } from "#util/sorts"; -import { COLOUR_SET, type GamesForGroup, IIDX_LAMPS, IIDXLIKE_GBOUNDARIES } from "tachi-common"; +import { COLOUR_SET, type GamesForGroup, IIDX_LAMPS, RawIIDXGradeBoundaries } from "tachi-common"; import { bgc, CreateRatingSys } from "./_util"; @@ -97,18 +97,10 @@ const IIDXCoreCells: GameClientImplementation["scoreCoreC score={sc.scoreData.score} /> { - const max = Math.floor(sc.scoreData.score / (sc.scoreData.percent / 100)); - - const v = (deltaPercent / 100) * max; - - // i don't know if this is correct - // it's just really hard to work out. - return Math.round(v).toFixed(0); - }} + formatNumFn={(n) => Math.floor(n / 18).toString()} grade={sc.scoreData.grade} - gradeBoundaries={IIDXLIKE_GBOUNDARIES} - value={sc.scoreData.percent} + gradeBoundaries={RawIIDXGradeBoundaries(chart.data.notecount)} + value={sc.scoreData.score * 18} /> diff --git a/typescript/common/src/utils/util.ts b/typescript/common/src/utils/util.ts index 1339b2d9d..d0891888a 100644 --- a/typescript/common/src/utils/util.ts +++ b/typescript/common/src/utils/util.ts @@ -1,7 +1,6 @@ import type { PrudenceError, ValidSchemaValue } from "prudence"; import type { ZodObject } from "zod"; -import type { GradeBoundary, IIDXLikes } from "../constants/grade-boundaries"; import type { BMSCourseDocument, BMSGames, @@ -22,6 +21,11 @@ import type { } from "../types/metrics"; import { ALL_GAMES, GameToGameGroup, GetGameConfig, GetGameGroupConfig } from "../config/config"; +import { + type GradeBoundary, + type IIDXLikes, + MakeGradeBoundaries, +} from "../constants/grade-boundaries"; /** * Stick this in the "default" branch of switch exprs to statically typecheck that your @@ -454,6 +458,32 @@ export function IIDXLikeGetGrade( return "F"; } +/** + * Computes exact integer EX-score grade boundaries for a given IIDX-like notecount. + * + * These mirror the integer arithmetic in IIDXLikeGetGrade and avoid the + * floating-point rounding errors that arise from working through percent-space + * when the grade denominators are ninths (or eighteenths for MAX-). + */ +export function RawIIDXGradeBoundaries( + notecount: integer, +): Array>> { + const max = notecount * 2; + + return MakeGradeBoundaries>({ + F: 0, + E: max * 4, + D: max * 6, + C: max * 8, + B: max * 10, + A: max * 12, + AA: max * 14, + AAA: max * 16, + "MAX-": max * 17, + MAX: max * 18, + }); +} + export function EnumIndexToValue< TGame extends V3Game, EV extends ExtractEnumMetricNames,