From 099f788d0f270e9d65c4c6ebbed2c2aaf7b57797 Mon Sep 17 00:00:00 2001 From: zkldi Date: Fri, 28 May 2021 09:02:18 +0100 Subject: [PATCH] remove todos in game=specific-tests --- .../game-specific-stats.test.ts | 81 +++++++++++++++++-- .../calculated-data/game-specific-stats.ts | 41 +++++----- 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/server/src/lib/score-import/framework/calculated-data/game-specific-stats.test.ts b/server/src/lib/score-import/framework/calculated-data/game-specific-stats.test.ts index 2c0f74428..8647ee051 100644 --- a/server/src/lib/score-import/framework/calculated-data/game-specific-stats.test.ts +++ b/server/src/lib/score-import/framework/calculated-data/game-specific-stats.test.ts @@ -1,5 +1,5 @@ import t from "tap"; -import { CloseMongoConnection } from "../../../../external/mongo/db"; +import db, { CloseMongoConnection } from "../../../../external/mongo/db"; import { AnyChartDocument, Difficulties, Lamps, ScoreDocument } from "kamaitachi-common"; import { CalculateBPI, @@ -14,6 +14,11 @@ import { import CreateLogCtx from "../../../logger/logger"; import { isApproximately } from "../../../../test-utils/asserts"; import { DryScore } from "../common/types"; +import { + GetKTDataJSON, + Testing511SPA, + TestingIIDXSPDryScore, +} from "../../../../test-utils/test-data"; t.test("#CalculateBPI", (t) => { t.test("AA BPI tests", (t) => { @@ -127,7 +132,7 @@ t.test("#CalculateKESDC", (t) => { t.end(); }); -const mockLogger = CreateLogCtx(__filename); +const logger = CreateLogCtx(__filename); t.test("#CalculateMFCP", (t) => { function TestMFCP( @@ -145,7 +150,7 @@ t.test("#CalculateMFCP", (t) => { difficulty, levelNum, } as AnyChartDocument, - mockLogger + logger ); } @@ -240,9 +245,71 @@ t.test("#CalculateMFCP", (t) => { t.end(); }); -t.todo("#CalculateCHUNITHMRating"); -t.todo("#CalculateVF5"); -t.todo("#CalculateVF4"); -t.todo("#KaidenPercentile"); +const bbkk = GetKTDataJSON("./kamaitachi/chunithm-bbkk-chart.json"); + +// unit testing a mathematical function is a square-round-hole problem. +t.test("#CalculateCHUNITHMRating", (t) => { + // cutoffs + t.equal(CalculateCHUNITHMRating({ scoreData: { score: 1_010_000 } } as DryScore, bbkk), 5.0); + t.equal(CalculateCHUNITHMRating({ scoreData: { score: 1_005_000 } } as DryScore, bbkk), 4.5); + t.equal(CalculateCHUNITHMRating({ scoreData: { score: 1_000_000 } } as DryScore, bbkk), 4); + t.equal(CalculateCHUNITHMRating({ scoreData: { score: 975_000 } } as DryScore, bbkk), 3); + t.equal(CalculateCHUNITHMRating({ scoreData: { score: 925_000 } } as DryScore, bbkk), 0); + t.equal(CalculateCHUNITHMRating({ scoreData: { score: 900_000 } } as DryScore, bbkk), 0); + t.equal(CalculateCHUNITHMRating({ scoreData: { score: 800_000 } } as DryScore, bbkk), 0); + t.equal(CalculateCHUNITHMRating({ scoreData: { score: 0 } } as DryScore, bbkk), 0); + + // inbetweens + t.equal(CalculateCHUNITHMRating({ scoreData: { score: 987_000 } } as DryScore, bbkk), 3.48); + + t.end(); +}); + +// i plucked random assertions from bemaniwiki +// see https://bemaniwiki.com/index.php?SOUND%20VOLTEX%20VIVID%20WAVE/VOLFORCE +t.test("#CalculateVF5", (t) => { + t.equal(CalculateVF5("AAA", "CLEAR", 97, 10, logger), 0.19); + t.equal(CalculateVF5("A", "CLEAR", 90, 15, logger), 0.23); + t.equal(CalculateVF5("AAA+", "CLEAR", 98, 19, logger), 0.37); + t.equal(CalculateVF5("S", "PERFECT ULTIMATE CHAIN", 100, 20, logger), 0.46); + t.equal(CalculateVF5("B", "FAILED", 85, 20, logger), 0.14); + t.equal(CalculateVF5("D", "FAILED", 0, 20, logger), 0); + t.equal(CalculateVF5("S", "PERFECT ULTIMATE CHAIN", 100, 0, logger), 0); + t.equal(CalculateVF5("INVALID GRADE" as any, "PERFECT ULTIMATE CHAIN", 100, 0, logger), null); + t.equal(CalculateVF5("S", "INVALID LAMP" as any, 100, 0, logger), null); + + t.end(); +}); + +t.test("#CalculateVF4", (t) => { + t.equal(CalculateVF4("INVALID GRADE" as any, 100, 0, logger), null); + t.equal(CalculateVF4("D", 0, 20, logger), 0); + t.equal(CalculateVF4("S", 100, 0, logger), 0); + t.equal(CalculateVF4("S", 100, 20, logger), 525); + t.equal(CalculateVF4("AA", 93, 16, logger), 379); + + t.end(); +}); + +t.test("#KaidenPercentile", async (t) => { + await db["iidx-eam-scores"].insert( + [100, 200, 300, 400, 1000, 2000, 3000, 4000].map((e) => ({ + chartID: Testing511SPA.chartID, + score: e, + lamp: "EASY CLEAR", + ranking: 0, // ignore + })) + ); + + const res = await KaidenPercentile(TestingIIDXSPDryScore, Testing511SPA); + t.equal(res, 50); + + await db["iidx-eam-scores"].remove({}); + const res2 = await KaidenPercentile(TestingIIDXSPDryScore, Testing511SPA); + + t.equal(res2, null); + + t.end(); +}); t.teardown(CloseMongoConnection); diff --git a/server/src/lib/score-import/framework/calculated-data/game-specific-stats.ts b/server/src/lib/score-import/framework/calculated-data/game-specific-stats.ts index ceeb19f34..8f7a43348 100644 --- a/server/src/lib/score-import/framework/calculated-data/game-specific-stats.ts +++ b/server/src/lib/score-import/framework/calculated-data/game-specific-stats.ts @@ -12,20 +12,20 @@ export function CalculateCHUNITHMRating(dryScore: DryScore, chartData: AnyChartD let val = 0; - if (score >= 1007500) { + if (score >= 1_007_500) { val = levelBase + 200; - } else if (score >= 1005000) { - val = levelBase + 150 + ((score - 1005000) * 10) / 500; - } else if (score >= 1000000) { - val = levelBase + 100 + ((score - 1000000) * 5) / 500; - } else if (score >= 975000) { - val = levelBase + ((score - 975000) * 2) / 500; - } else if (score >= 925000) { - val = levelBase - 300 + ((score - 925000) * 3) / 500; - } else if (score >= 900000) { - val = levelBase - 500 + ((score - 900000) * 4) / 500; - } else if (score >= 800000) { - val = (levelBase - 500) / 2 + ((score - 800000) * ((levelBase - 500) / 2)) / 100000; + } else if (score >= 1_005_000) { + val = levelBase + 150 + ((score - 1_005_000) * 10) / 500; + } else if (score >= 1_000_000) { + val = levelBase + 100 + ((score - 1_000_000) * 5) / 100; + } else if (score >= 975_000) { + val = levelBase + ((score - 975_000) * 2) / 500; + } else if (score >= 925_000) { + val = levelBase - 300 + ((score - 925_000) * 3) / 500; + } else if (score >= 900_000) { + val = levelBase - 500 + ((score - 900_000) * 4) / 500; + } else if (score >= 800_000) { + val = (levelBase - 500) / 2 + ((score - 800_000) * ((levelBase - 500) / 2)) / 100_000; } return Math.max(Math.floor(val) / 100, 0); @@ -204,11 +204,10 @@ const VF5LampCoefficients = { export function CalculateVF4( grade: Grades["sdvx:Single"], per: number, - chartData: AnyChartDocument, + levelNum: number, logger: KtLogger ) { const multiplier = 25; - const level = chartData.levelNum; const gradeCoefficient = VF4GradeCoefficients[grade]; @@ -218,11 +217,11 @@ export function CalculateVF4( } const percent = per / 100; - if (!level || !percent) { + if (!levelNum || !percent) { return 0; } - return Math.floor(multiplier * (level + 1) * percent * gradeCoefficient); + return Math.floor(multiplier * (levelNum + 1) * percent * gradeCoefficient); } // WARNING: @@ -232,11 +231,9 @@ export function CalculateVF5( grade: Grades["sdvx:Single"], lamp: Lamps["sdvx:Single"], per: number, - chartData: AnyChartDocument, + levelNum: number, logger: KtLogger ) { - const level = chartData.levelNum; - const gradeCoefficient = VF5GradeCoefficients[grade]; const lampCoefficient = VF5LampCoefficients[lamp]; @@ -250,11 +247,11 @@ export function CalculateVF5( } const percent = per / 100; - if (!level || !percent) { + if (!levelNum || !percent) { return 0; } - return Math.floor(level * 2 * percent * gradeCoefficient * lampCoefficient) / 100; + return Math.floor(levelNum * 2 * percent * gradeCoefficient * lampCoefficient) / 100; } // function CalculateJubility(