UNPKG

rg-stats

Version:

A library for calculating various rhythm game stats.

857 lines (817 loc) 32.9 kB
import t from "tap"; import { TestCase } from "../test-utils/test-case"; import { ThrowsToSnapshot } from "../test-utils/throw-snapshot"; import { calculateVF4, calculateVF5, calculateVF6, inverseVF4, inverseVF5, inverseVF6, SDVXLamps, } from "./volforce"; t.test("VF4 Tests", (t) => { function VF4TestCase(level: number, expectedVF4: number, score: number) { return { level, expectedVF4, score }; } // As always, a bunch of test data ripped from bemaniwiki. const VF4ExampleData = [ VF4TestCase(1, 42, 9_000_000), VF4TestCase(1, 43, 9_100_000), VF4TestCase(1, 43, 9_200_000), VF4TestCase(1, 44, 9_300_000), VF4TestCase(1, 45, 9_400_000), VF4TestCase(1, 46, 9_500_000), VF4TestCase(1, 46, 9_600_000), VF4TestCase(1, 47, 9_700_000), VF4TestCase(1, 47, 9_750_000), VF4TestCase(1, 48, 9_800_000), VF4TestCase(1, 48, 9_850_000), VF4TestCase(1, 49, 9_900_000), VF4TestCase(1, 49, 9_950_000), VF4TestCase(1, 49, 9_990_000), VF4TestCase(1, 50, 10_000_000), VF4TestCase(2, 64, 9_000_000), VF4TestCase(2, 64, 9_100_000), VF4TestCase(2, 65, 9_200_000), VF4TestCase(2, 66, 9_300_000), VF4TestCase(2, 67, 9_400_000), VF4TestCase(2, 69, 9_500_000), VF4TestCase(2, 69, 9_600_000), VF4TestCase(2, 71, 9_700_000), VF4TestCase(2, 71, 9_750_000), VF4TestCase(2, 72, 9_800_000), VF4TestCase(2, 73, 9_850_000), VF4TestCase(2, 74, 9_900_000), VF4TestCase(2, 74, 9_950_000), VF4TestCase(2, 74, 9_990_000), VF4TestCase(2, 75, 10_000_000), VF4TestCase(3, 85, 9_000_000), VF4TestCase(3, 86, 9_100_000), VF4TestCase(3, 87, 9_200_000), VF4TestCase(3, 89, 9_300_000), VF4TestCase(3, 90, 9_400_000), VF4TestCase(3, 92, 9_500_000), VF4TestCase(3, 93, 9_600_000), VF4TestCase(3, 95, 9_700_000), VF4TestCase(3, 95, 9_750_000), VF4TestCase(3, 97, 9_800_000), VF4TestCase(3, 97, 9_850_000), VF4TestCase(3, 99, 9_900_000), VF4TestCase(3, 99, 9_950_000), VF4TestCase(3, 99, 9_990_000), VF4TestCase(3, 100, 10_000_000), VF4TestCase(4, 106, 9_000_000), VF4TestCase(4, 108, 9_100_000), VF4TestCase(4, 109, 9_200_000), VF4TestCase(4, 111, 9_300_000), VF4TestCase(4, 112, 9_400_000), VF4TestCase(4, 115, 9_500_000), VF4TestCase(4, 116, 9_600_000), VF4TestCase(4, 118, 9_700_000), VF4TestCase(4, 119, 9_750_000), VF4TestCase(4, 121, 9_800_000), VF4TestCase(4, 121, 9_850_000), VF4TestCase(4, 123, 9_900_000), VF4TestCase(4, 124, 9_950_000), VF4TestCase(4, 124, 9_990_000), VF4TestCase(4, 125, 10_000_000), VF4TestCase(5, 128, 9_000_000), VF4TestCase(5, 129, 9_100_000), VF4TestCase(5, 131, 9_200_000), VF4TestCase(5, 133, 9_300_000), VF4TestCase(5, 135, 9_400_000), VF4TestCase(5, 138, 9_500_000), VF4TestCase(5, 139, 9_600_000), VF4TestCase(5, 142, 9_700_000), VF4TestCase(5, 143, 9_750_000), VF4TestCase(5, 145, 9_800_000), VF4TestCase(5, 146, 9_850_000), VF4TestCase(5, 148, 9_900_000), VF4TestCase(5, 149, 9_950_000), VF4TestCase(5, 149, 9_990_000), VF4TestCase(5, 150, 10_000_000), VF4TestCase(6, 149, 9_000_000), VF4TestCase(6, 151, 9_100_000), VF4TestCase(6, 152, 9_200_000), VF4TestCase(6, 156, 9_300_000), VF4TestCase(6, 157, 9_400_000), VF4TestCase(6, 161, 9_500_000), VF4TestCase(6, 162, 9_600_000), VF4TestCase(6, 166, 9_700_000), VF4TestCase(6, 167, 9_750_000), VF4TestCase(6, 169, 9_800_000), VF4TestCase(6, 170, 9_850_000), VF4TestCase(6, 173, 9_900_000), VF4TestCase(6, 174, 9_950_000), VF4TestCase(6, 174, 9_990_000), VF4TestCase(6, 175, 10_000_000), VF4TestCase(7, 171, 9_000_000), VF4TestCase(7, 172, 9_100_000), VF4TestCase(7, 174, 9_200_000), VF4TestCase(7, 178, 9_300_000), VF4TestCase(7, 180, 9_400_000), VF4TestCase(7, 184, 9_500_000), VF4TestCase(7, 186, 9_600_000), VF4TestCase(7, 190, 9_700_000), VF4TestCase(7, 191, 9_750_000), VF4TestCase(7, 194, 9_800_000), VF4TestCase(7, 195, 9_850_000), VF4TestCase(7, 198, 9_900_000), VF4TestCase(7, 199, 9_950_000), VF4TestCase(7, 199, 9_990_000), VF4TestCase(7, 200, 10_000_000), VF4TestCase(8, 192, 9_000_000), VF4TestCase(8, 194, 9_100_000), VF4TestCase(8, 196, 9_200_000), VF4TestCase(8, 200, 9_300_000), VF4TestCase(8, 203, 9_400_000), VF4TestCase(8, 207, 9_500_000), VF4TestCase(8, 209, 9_600_000), VF4TestCase(8, 213, 9_700_000), VF4TestCase(8, 214, 9_750_000), VF4TestCase(8, 218, 9_800_000), VF4TestCase(8, 219, 9_850_000), VF4TestCase(8, 222, 9_900_000), VF4TestCase(8, 223, 9_950_000), VF4TestCase(8, 224, 9_990_000), VF4TestCase(8, 225, 10_000_000), VF4TestCase(9, 213, 9_000_000), VF4TestCase(9, 216, 9_100_000), VF4TestCase(9, 218, 9_200_000), VF4TestCase(9, 223, 9_300_000), VF4TestCase(9, 225, 9_400_000), VF4TestCase(9, 230, 9_500_000), VF4TestCase(9, 232, 9_600_000), VF4TestCase(9, 237, 9_700_000), VF4TestCase(9, 238, 9_750_000), VF4TestCase(9, 242, 9_800_000), VF4TestCase(9, 243, 9_850_000), VF4TestCase(9, 247, 9_900_000), VF4TestCase(9, 248, 9_950_000), VF4TestCase(9, 249, 9_990_000), VF4TestCase(9, 250, 10_000_000), VF4TestCase(10, 235, 9_000_000), VF4TestCase(10, 237, 9_100_000), VF4TestCase(10, 240, 9_200_000), VF4TestCase(10, 245, 9_300_000), VF4TestCase(10, 248, 9_400_000), VF4TestCase(10, 253, 9_500_000), VF4TestCase(10, 256, 9_600_000), VF4TestCase(10, 261, 9_700_000), VF4TestCase(10, 262, 9_750_000), VF4TestCase(10, 266, 9_800_000), VF4TestCase(10, 268, 9_850_000), VF4TestCase(10, 272, 9_900_000), VF4TestCase(10, 273, 9_950_000), VF4TestCase(10, 274, 9_990_000), VF4TestCase(10, 275, 10_000_000), VF4TestCase(11, 256, 9_000_000), VF4TestCase(11, 259, 9_100_000), VF4TestCase(11, 262, 9_200_000), VF4TestCase(11, 267, 9_300_000), VF4TestCase(11, 270, 9_400_000), VF4TestCase(11, 276, 9_500_000), VF4TestCase(11, 279, 9_600_000), VF4TestCase(11, 285, 9_700_000), VF4TestCase(11, 286, 9_750_000), VF4TestCase(11, 291, 9_800_000), VF4TestCase(11, 292, 9_850_000), VF4TestCase(11, 297, 9_900_000), VF4TestCase(11, 298, 9_950_000), VF4TestCase(11, 299, 9_990_000), VF4TestCase(11, 300, 10_000_000), VF4TestCase(12, 277, 9_000_000), VF4TestCase(12, 280, 9_100_000), VF4TestCase(12, 284, 9_200_000), VF4TestCase(12, 290, 9_300_000), VF4TestCase(12, 293, 9_400_000), VF4TestCase(12, 299, 9_500_000), VF4TestCase(12, 302, 9_600_000), VF4TestCase(12, 308, 9_700_000), VF4TestCase(12, 310, 9_750_000), VF4TestCase(12, 315, 9_800_000), VF4TestCase(12, 316, 9_850_000), VF4TestCase(12, 321, 9_900_000), VF4TestCase(12, 323, 9_950_000), VF4TestCase(12, 324, 9_990_000), VF4TestCase(12, 325, 10_000_000), VF4TestCase(13, 299, 9_000_000), VF4TestCase(13, 302, 9_100_000), VF4TestCase(13, 305, 9_200_000), VF4TestCase(13, 312, 9_300_000), VF4TestCase(13, 315, 9_400_000), VF4TestCase(13, 322, 9_500_000), VF4TestCase(13, 325, 9_600_000), VF4TestCase(13, 332, 9_700_000), VF4TestCase(13, 334, 9_750_000), VF4TestCase(13, 339, 9_800_000), VF4TestCase(13, 341, 9_850_000), VF4TestCase(13, 346, 9_900_000), VF4TestCase(13, 348, 9_950_000), VF4TestCase(13, 349, 9_990_000), VF4TestCase(13, 350, 10_000_000), VF4TestCase(14, 320, 9_000_000), VF4TestCase(14, 324, 9_100_000), VF4TestCase(14, 327, 9_200_000), VF4TestCase(14, 334, 9_300_000), VF4TestCase(14, 338, 9_400_000), VF4TestCase(14, 345, 9_500_000), VF4TestCase(14, 349, 9_600_000), VF4TestCase(14, 356, 9_700_000), VF4TestCase(14, 358, 9_750_000), VF4TestCase(14, 363, 9_800_000), VF4TestCase(14, 365, 9_850_000), VF4TestCase(14, 371, 9_900_000), VF4TestCase(14, 373, 9_950_000), VF4TestCase(14, 374, 9_990_000), VF4TestCase(14, 375, 10_000_000), VF4TestCase(15, 342, 9_000_000), VF4TestCase(15, 345, 9_100_000), VF4TestCase(15, 349, 9_200_000), VF4TestCase(15, 357, 9_300_000), VF4TestCase(15, 360, 9_400_000), VF4TestCase(15, 368, 9_500_000), VF4TestCase(15, 372, 9_600_000), VF4TestCase(15, 380, 9_700_000), VF4TestCase(15, 382, 9_750_000), VF4TestCase(15, 388, 9_800_000), VF4TestCase(15, 390, 9_850_000), VF4TestCase(15, 396, 9_900_000), VF4TestCase(15, 398, 9_950_000), VF4TestCase(15, 399, 9_990_000), VF4TestCase(15, 400, 10_000_000), VF4TestCase(16, 363, 9_000_000), VF4TestCase(16, 367, 9_100_000), VF4TestCase(16, 371, 9_200_000), VF4TestCase(16, 379, 9_300_000), VF4TestCase(16, 383, 9_400_000), VF4TestCase(16, 391, 9_500_000), VF4TestCase(16, 395, 9_600_000), VF4TestCase(16, 404, 9_700_000), VF4TestCase(16, 406, 9_750_000), VF4TestCase(16, 412, 9_800_000), VF4TestCase(16, 414, 9_850_000), VF4TestCase(16, 420, 9_900_000), VF4TestCase(16, 422, 9_950_000), VF4TestCase(16, 424, 9_990_000), VF4TestCase(16, 425, 10_000_000), VF4TestCase(17, 384, 9_000_000), VF4TestCase(17, 389, 9_100_000), VF4TestCase(17, 393, 9_200_000), VF4TestCase(17, 401, 9_300_000), VF4TestCase(17, 406, 9_400_000), VF4TestCase(17, 414, 9_500_000), VF4TestCase(17, 419, 9_600_000), VF4TestCase(17, 427, 9_700_000), VF4TestCase(17, 429, 9_750_000), VF4TestCase(17, 436, 9_800_000), VF4TestCase(17, 438, 9_850_000), VF4TestCase(17, 445, 9_900_000), VF4TestCase(17, 447, 9_950_000), VF4TestCase(17, 449, 9_990_000), VF4TestCase(17, 450, 10_000_000), VF4TestCase(18, 406, 9_000_000), VF4TestCase(18, 410, 9_100_000), VF4TestCase(18, 415, 9_200_000), VF4TestCase(18, 424, 9_300_000), VF4TestCase(18, 428, 9_400_000), VF4TestCase(18, 437, 9_500_000), VF4TestCase(18, 442, 9_600_000), VF4TestCase(18, 451, 9_700_000), VF4TestCase(18, 453, 9_750_000), VF4TestCase(18, 460, 9_800_000), VF4TestCase(18, 463, 9_850_000), VF4TestCase(18, 470, 9_900_000), VF4TestCase(18, 472, 9_950_000), VF4TestCase(18, 474, 9_990_000), VF4TestCase(18, 475, 10_000_000), VF4TestCase(19, 427, 9_000_000), VF4TestCase(19, 432, 9_100_000), VF4TestCase(19, 437, 9_200_000), VF4TestCase(19, 446, 9_300_000), VF4TestCase(19, 451, 9_400_000), VF4TestCase(19, 460, 9_500_000), VF4TestCase(19, 465, 9_600_000), VF4TestCase(19, 475, 9_700_000), VF4TestCase(19, 477, 9_750_000), VF4TestCase(19, 485, 9_800_000), VF4TestCase(19, 487, 9_850_000), VF4TestCase(19, 495, 9_900_000), VF4TestCase(19, 497, 9_950_000), VF4TestCase(19, 499, 9_990_000), VF4TestCase(19, 500, 10_000_000), VF4TestCase(20, 448, 9_000_000), VF4TestCase(20, 453, 9_100_000), VF4TestCase(20, 458, 9_200_000), VF4TestCase(20, 468, 9_300_000), VF4TestCase(20, 473, 9_400_000), VF4TestCase(20, 483, 9_500_000), VF4TestCase(20, 488, 9_600_000), VF4TestCase(20, 499, 9_700_000), VF4TestCase(20, 501, 9_750_000), VF4TestCase(20, 509, 9_800_000), VF4TestCase(20, 511, 9_850_000), VF4TestCase(20, 519, 9_900_000), VF4TestCase(20, 522, 9_950_000), VF4TestCase(20, 524, 9_990_000), VF4TestCase(20, 525, 10_000_000), ]; for (const data of VF4ExampleData) { t.equal( calculateVF4(data.score, data.level), data.expectedVF4, `${data.score} on a level ${data.level} chart should be worth ${data.expectedVF4} VF4.` ); } t.end(); }); t.test("VF4 Validation Tests", (t) => { ThrowsToSnapshot( t, () => calculateVF4(10_000_001, 20), "Should throw if score is greater than 10 million." ); ThrowsToSnapshot(t, () => calculateVF4(-1, 20), "Should throw if score is negative."); ThrowsToSnapshot( t, () => inverseVF4(9_000, 20), "Should throw if the VF4 requested as an inversion is impossible." ); t.end(); }); t.test("InverseVF4 Tests", (t) => { // The test data I've nabbed from bemaniwiki picks cutoff points rather than // the smallest possible value needed to get the vf4. // I've reprocessed all of this data, though. Should be good. const testData = [ { vf4: 42, level: 1, expectedScore: 8936170 }, { vf4: 43, level: 1, expectedScore: 9052632 }, { vf4: 44, level: 1, expectedScore: 9263158 }, { vf4: 45, level: 1, expectedScore: 9375000 }, { vf4: 46, level: 1, expectedScore: 9500000 }, { vf4: 47, level: 1, expectedScore: 9690722 }, { vf4: 48, level: 1, expectedScore: 9795918 }, { vf4: 49, level: 1, expectedScore: 9898990 }, { vf4: 50, level: 1, expectedScore: 10000000 }, { vf4: 64, level: 2, expectedScore: 9000000 }, { vf4: 65, level: 2, expectedScore: 9122807 }, { vf4: 66, level: 2, expectedScore: 9263158 }, { vf4: 67, level: 2, expectedScore: 9305556 }, { vf4: 69, level: 2, expectedScore: 9500000 }, { vf4: 71, level: 2, expectedScore: 9700000 }, { vf4: 71, level: 2, expectedScore: 9700000 }, { vf4: 72, level: 2, expectedScore: 9795918 }, { vf4: 73, level: 2, expectedScore: 9831650 }, { vf4: 74, level: 2, expectedScore: 9900000 }, { vf4: 75, level: 2, expectedScore: 10000000 }, { vf4: 85, level: 3, expectedScore: 9000000 }, { vf4: 86, level: 3, expectedScore: 9052632 }, { vf4: 87, level: 3, expectedScore: 9157895 }, { vf4: 89, level: 3, expectedScore: 9300000 }, { vf4: 90, level: 3, expectedScore: 9375000 }, { vf4: 92, level: 3, expectedScore: 9500000 }, { vf4: 93, level: 3, expectedScore: 9587629 }, { vf4: 95, level: 3, expectedScore: 9700000 }, { vf4: 97, level: 3, expectedScore: 9800000 }, { vf4: 97, level: 3, expectedScore: 9800000 }, { vf4: 99, level: 3, expectedScore: 9900000 }, { vf4: 100, level: 3, expectedScore: 10000000 }, { vf4: 106, level: 4, expectedScore: 9000000 }, { vf4: 108, level: 4, expectedScore: 9094737 }, { vf4: 109, level: 4, expectedScore: 9178947 }, { vf4: 111, level: 4, expectedScore: 9300000 }, { vf4: 112, level: 4, expectedScore: 9333333 }, { vf4: 115, level: 4, expectedScore: 9500000 }, { vf4: 116, level: 4, expectedScore: 9567010 }, { vf4: 118, level: 4, expectedScore: 9700000 }, { vf4: 119, level: 4, expectedScore: 9714286 }, { vf4: 121, level: 4, expectedScore: 9800000 }, { vf4: 121, level: 4, expectedScore: 9800000 }, { vf4: 123, level: 4, expectedScore: 9900000 }, { vf4: 124, level: 4, expectedScore: 9920000 }, { vf4: 125, level: 4, expectedScore: 10000000 }, { vf4: 128, level: 5, expectedScore: 9000000 }, { vf4: 129, level: 5, expectedScore: 9052632 }, { vf4: 131, level: 5, expectedScore: 9192982 }, { vf4: 133, level: 5, expectedScore: 9300000 }, { vf4: 135, level: 5, expectedScore: 9375000 }, { vf4: 138, level: 5, expectedScore: 9500000 }, { vf4: 139, level: 5, expectedScore: 9553265 }, { vf4: 142, level: 5, expectedScore: 9700000 }, { vf4: 143, level: 5, expectedScore: 9727891 }, { vf4: 145, level: 5, expectedScore: 9800000 }, { vf4: 146, level: 5, expectedScore: 9831650 }, { vf4: 148, level: 5, expectedScore: 9900000 }, { vf4: 149, level: 5, expectedScore: 9933333 }, { vf4: 150, level: 5, expectedScore: 10000000 }, { vf4: 149, level: 6, expectedScore: 9000000 }, { vf4: 151, level: 6, expectedScore: 9082707 }, { vf4: 152, level: 6, expectedScore: 9142857 }, { vf4: 156, level: 6, expectedScore: 9300000 }, { vf4: 157, level: 6, expectedScore: 9345238 }, { vf4: 161, level: 6, expectedScore: 9500000 }, { vf4: 162, level: 6, expectedScore: 9543446 }, { vf4: 166, level: 6, expectedScore: 9700000 }, { vf4: 167, level: 6, expectedScore: 9737609 }, { vf4: 169, level: 6, expectedScore: 9800000 }, { vf4: 170, level: 6, expectedScore: 9812410 }, { vf4: 173, level: 6, expectedScore: 9900000 }, { vf4: 174, level: 6, expectedScore: 9942857 }, { vf4: 175, level: 6, expectedScore: 10000000 }, { vf4: 171, level: 7, expectedScore: 9000000 }, { vf4: 172, level: 7, expectedScore: 9052632 }, { vf4: 174, level: 7, expectedScore: 9157895 }, { vf4: 178, level: 7, expectedScore: 9300000 }, { vf4: 180, level: 7, expectedScore: 9375000 }, { vf4: 184, level: 7, expectedScore: 9500000 }, { vf4: 186, level: 7, expectedScore: 9587629 }, { vf4: 190, level: 7, expectedScore: 9700000 }, { vf4: 191, level: 7, expectedScore: 9744898 }, { vf4: 194, level: 7, expectedScore: 9800000 }, { vf4: 195, level: 7, expectedScore: 9848485 }, { vf4: 198, level: 7, expectedScore: 9900000 }, { vf4: 199, level: 7, expectedScore: 9950000 }, { vf4: 200, level: 7, expectedScore: 10000000 }, { vf4: 192, level: 8, expectedScore: 9000000 }, { vf4: 194, level: 8, expectedScore: 9076023 }, { vf4: 196, level: 8, expectedScore: 9169591 }, { vf4: 200, level: 8, expectedScore: 9300000 }, { vf4: 203, level: 8, expectedScore: 9398148 }, { vf4: 207, level: 8, expectedScore: 9500000 }, { vf4: 209, level: 8, expectedScore: 9576174 }, { vf4: 213, level: 8, expectedScore: 9700000 }, { vf4: 214, level: 8, expectedScore: 9705215 }, { vf4: 218, level: 8, expectedScore: 9800000 }, { vf4: 219, level: 8, expectedScore: 9831650 }, { vf4: 222, level: 8, expectedScore: 9900000 }, { vf4: 223, level: 8, expectedScore: 9911111 }, { vf4: 224, level: 8, expectedScore: 9955556 }, { vf4: 225, level: 8, expectedScore: 10000000 }, { vf4: 213, level: 9, expectedScore: 9000000 }, { vf4: 216, level: 9, expectedScore: 9094737 }, { vf4: 218, level: 9, expectedScore: 9178947 }, { vf4: 223, level: 9, expectedScore: 9300000 }, { vf4: 225, level: 9, expectedScore: 9375000 }, { vf4: 230, level: 9, expectedScore: 9500000 }, { vf4: 232, level: 9, expectedScore: 9567010 }, { vf4: 237, level: 9, expectedScore: 9700000 }, { vf4: 238, level: 9, expectedScore: 9714286 }, { vf4: 242, level: 9, expectedScore: 9800000 }, { vf4: 243, level: 9, expectedScore: 9818182 }, { vf4: 247, level: 9, expectedScore: 9900000 }, { vf4: 248, level: 9, expectedScore: 9920000 }, { vf4: 249, level: 9, expectedScore: 9960000 }, { vf4: 250, level: 9, expectedScore: 10000000 }, { vf4: 235, level: 10, expectedScore: 9000000 }, { vf4: 237, level: 10, expectedScore: 9071770 }, { vf4: 240, level: 10, expectedScore: 9186603 }, { vf4: 245, level: 10, expectedScore: 9300000 }, { vf4: 248, level: 10, expectedScore: 9393939 }, { vf4: 253, level: 10, expectedScore: 9500000 }, { vf4: 256, level: 10, expectedScore: 9597001 }, { vf4: 261, level: 10, expectedScore: 9700000 }, { vf4: 262, level: 10, expectedScore: 9721707 }, { vf4: 266, level: 10, expectedScore: 9800000 }, { vf4: 268, level: 10, expectedScore: 9843893 }, { vf4: 272, level: 10, expectedScore: 9900000 }, { vf4: 273, level: 10, expectedScore: 9927273 }, { vf4: 274, level: 10, expectedScore: 9963636 }, { vf4: 275, level: 10, expectedScore: 10000000 }, { vf4: 256, level: 11, expectedScore: 9000000 }, { vf4: 259, level: 11, expectedScore: 9087719 }, { vf4: 262, level: 11, expectedScore: 9192982 }, { vf4: 267, level: 11, expectedScore: 9300000 }, { vf4: 270, level: 11, expectedScore: 9375000 }, { vf4: 276, level: 11, expectedScore: 9500000 }, { vf4: 279, level: 11, expectedScore: 9587629 }, { vf4: 285, level: 11, expectedScore: 9700000 }, { vf4: 286, level: 11, expectedScore: 9727891 }, { vf4: 291, level: 11, expectedScore: 9800000 }, { vf4: 292, level: 11, expectedScore: 9831650 }, { vf4: 297, level: 11, expectedScore: 9900000 }, { vf4: 298, level: 11, expectedScore: 9933333 }, { vf4: 299, level: 11, expectedScore: 9966667 }, { vf4: 300, level: 11, expectedScore: 10000000 }, { vf4: 277, level: 12, expectedScore: 9000000 }, { vf4: 280, level: 12, expectedScore: 9068826 }, { vf4: 284, level: 12, expectedScore: 9198381 }, { vf4: 290, level: 12, expectedScore: 9300000 }, { vf4: 293, level: 12, expectedScore: 9391026 }, { vf4: 299, level: 12, expectedScore: 9500000 }, { vf4: 302, level: 12, expectedScore: 9579699 }, { vf4: 308, level: 12, expectedScore: 9700000 }, { vf4: 310, level: 12, expectedScore: 9733124 }, { vf4: 315, level: 12, expectedScore: 9800000 }, { vf4: 316, level: 12, expectedScore: 9821290 }, { vf4: 321, level: 12, expectedScore: 9900000 }, { vf4: 323, level: 12, expectedScore: 9938462 }, { vf4: 324, level: 12, expectedScore: 9969231 }, { vf4: 325, level: 12, expectedScore: 10000000 }, { vf4: 299, level: 13, expectedScore: 9000000 }, { vf4: 302, level: 13, expectedScore: 9082707 }, { vf4: 305, level: 13, expectedScore: 9172932 }, { vf4: 312, level: 13, expectedScore: 9300000 }, { vf4: 315, level: 13, expectedScore: 9375000 }, { vf4: 322, level: 13, expectedScore: 9500000 }, { vf4: 325, level: 13, expectedScore: 9572901 }, { vf4: 332, level: 13, expectedScore: 9700000 }, { vf4: 334, level: 13, expectedScore: 9737609 }, { vf4: 339, level: 13, expectedScore: 9800000 }, { vf4: 341, level: 13, expectedScore: 9841270 }, { vf4: 346, level: 13, expectedScore: 9900000 }, { vf4: 348, level: 13, expectedScore: 9942857 }, { vf4: 349, level: 13, expectedScore: 9971429 }, { vf4: 350, level: 13, expectedScore: 10000000 }, { vf4: 320, level: 14, expectedScore: 9000000 }, { vf4: 324, level: 14, expectedScore: 9094737 }, { vf4: 327, level: 14, expectedScore: 9178947 }, { vf4: 334, level: 14, expectedScore: 9300000 }, { vf4: 338, level: 14, expectedScore: 9388889 }, { vf4: 345, level: 14, expectedScore: 9500000 }, { vf4: 349, level: 14, expectedScore: 9594502 }, { vf4: 356, level: 14, expectedScore: 9700000 }, { vf4: 358, level: 14, expectedScore: 9741497 }, { vf4: 363, level: 14, expectedScore: 9800000 }, { vf4: 365, level: 14, expectedScore: 9831650 }, { vf4: 371, level: 14, expectedScore: 9900000 }, { vf4: 373, level: 14, expectedScore: 9946667 }, { vf4: 374, level: 14, expectedScore: 9973333 }, { vf4: 375, level: 14, expectedScore: 10000000 }, { vf4: 342, level: 15, expectedScore: 9000000 }, { vf4: 345, level: 15, expectedScore: 9078947 }, { vf4: 349, level: 15, expectedScore: 9184211 }, { vf4: 357, level: 15, expectedScore: 9300000 }, { vf4: 360, level: 15, expectedScore: 9375000 }, { vf4: 368, level: 15, expectedScore: 9500000 }, { vf4: 372, level: 15, expectedScore: 9587629 }, { vf4: 380, level: 15, expectedScore: 9700000 }, { vf4: 382, level: 15, expectedScore: 9744898 }, { vf4: 388, level: 15, expectedScore: 9800000 }, { vf4: 390, level: 15, expectedScore: 9848485 }, { vf4: 396, level: 15, expectedScore: 9900000 }, { vf4: 398, level: 15, expectedScore: 9950000 }, { vf4: 399, level: 15, expectedScore: 9975000 }, { vf4: 400, level: 15, expectedScore: 10000000 }, { vf4: 363, level: 16, expectedScore: 9000000 }, { vf4: 367, level: 16, expectedScore: 9089783 }, { vf4: 371, level: 16, expectedScore: 9188854 }, { vf4: 379, level: 16, expectedScore: 9300000 }, { vf4: 383, level: 16, expectedScore: 9387255 }, { vf4: 391, level: 16, expectedScore: 9500000 }, { vf4: 395, level: 16, expectedScore: 9581565 }, { vf4: 404, level: 16, expectedScore: 9700000 }, { vf4: 406, level: 16, expectedScore: 9747899 }, { vf4: 412, level: 16, expectedScore: 9800000 }, { vf4: 414, level: 16, expectedScore: 9839572 }, { vf4: 420, level: 16, expectedScore: 9900000 }, { vf4: 422, level: 16, expectedScore: 9929412 }, { vf4: 424, level: 16, expectedScore: 9976471 }, { vf4: 425, level: 16, expectedScore: 10000000 }, { vf4: 384, level: 17, expectedScore: 9000000 }, { vf4: 389, level: 17, expectedScore: 9099415 }, { vf4: 393, level: 17, expectedScore: 9192982 }, { vf4: 401, level: 17, expectedScore: 9300000 }, { vf4: 406, level: 17, expectedScore: 9398148 }, { vf4: 414, level: 17, expectedScore: 9500000 }, { vf4: 419, level: 17, expectedScore: 9599084 }, { vf4: 427, level: 17, expectedScore: 9700000 }, { vf4: 429, level: 17, expectedScore: 9727891 }, { vf4: 436, level: 17, expectedScore: 9800000 }, { vf4: 438, level: 17, expectedScore: 9831650 }, { vf4: 445, level: 17, expectedScore: 9900000 }, { vf4: 447, level: 17, expectedScore: 9933333 }, { vf4: 449, level: 17, expectedScore: 9977778 }, { vf4: 450, level: 17, expectedScore: 10000000 }, { vf4: 406, level: 18, expectedScore: 9000000 }, { vf4: 410, level: 18, expectedScore: 9085873 }, { vf4: 415, level: 18, expectedScore: 9196676 }, { vf4: 424, level: 18, expectedScore: 9300000 }, { vf4: 428, level: 18, expectedScore: 9385965 }, { vf4: 437, level: 18, expectedScore: 9500000 }, { vf4: 442, level: 18, expectedScore: 9593055 }, { vf4: 451, level: 18, expectedScore: 9700000 }, { vf4: 453, level: 18, expectedScore: 9731472 }, { vf4: 460, level: 18, expectedScore: 9800000 }, { vf4: 463, level: 18, expectedScore: 9845827 }, { vf4: 470, level: 18, expectedScore: 9900000 }, { vf4: 472, level: 18, expectedScore: 9936842 }, { vf4: 474, level: 18, expectedScore: 9978947 }, { vf4: 475, level: 18, expectedScore: 10000000 }, { vf4: 427, level: 19, expectedScore: 9000000 }, { vf4: 432, level: 19, expectedScore: 9094737 }, { vf4: 437, level: 19, expectedScore: 9200000 }, { vf4: 446, level: 19, expectedScore: 9300000 }, { vf4: 451, level: 19, expectedScore: 9395833 }, { vf4: 460, level: 19, expectedScore: 9500000 }, { vf4: 465, level: 19, expectedScore: 9587629 }, { vf4: 475, level: 19, expectedScore: 9700000 }, { vf4: 477, level: 19, expectedScore: 9734694 }, { vf4: 485, level: 19, expectedScore: 9800000 }, { vf4: 487, level: 19, expectedScore: 9838384 }, { vf4: 495, level: 19, expectedScore: 9900000 }, { vf4: 497, level: 19, expectedScore: 9940000 }, { vf4: 499, level: 19, expectedScore: 9980000 }, { vf4: 500, level: 19, expectedScore: 10000000 }, { vf4: 448, level: 20, expectedScore: 9000000 }, { vf4: 453, level: 20, expectedScore: 9082707 }, { vf4: 458, level: 20, expectedScore: 9182957 }, { vf4: 468, level: 20, expectedScore: 9300000 }, { vf4: 473, level: 20, expectedScore: 9384921 }, { vf4: 483, level: 20, expectedScore: 9500000 }, { vf4: 488, level: 20, expectedScore: 9582720 }, { vf4: 499, level: 20, expectedScore: 9700000 }, { vf4: 501, level: 20, expectedScore: 9737609 }, { vf4: 509, level: 20, expectedScore: 9800000 }, { vf4: 511, level: 20, expectedScore: 9831650 }, { vf4: 519, level: 20, expectedScore: 9900000 }, { vf4: 522, level: 20, expectedScore: 9942857 }, { vf4: 524, level: 20, expectedScore: 9980952 }, { vf4: 525, level: 20, expectedScore: 10000000 }, ]; for (const data of testData) { t.equal( inverseVF4(data.vf4, data.level), data.expectedScore, `${data.vf4} VF4 on a level ${data.level} chart should be given by ${data.expectedScore} score.` ); } t.end(); }); t.test("VF5 Tests", (t) => { function VF5TestCase( level: number, score: number, lamp: SDVXLamps, expectedVF5: number ): TestCase { return (t) => { const vf5 = calculateVF5(score, lamp, level); t.equal( vf5, expectedVF5, `${score} on a level ${level} chart with lamp ${lamp} should be worth ${expectedVF5} VF5. (Got ${vf5})` ); }; } // No test data from bemaniwiki this time, so I just tore out some examples // myself. const VF5ExampleData = [ VF5TestCase(20, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.46), VF5TestCase(19, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.43), VF5TestCase(18, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.41), VF5TestCase(17, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.39), VF5TestCase(16, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.36), VF5TestCase(15, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.34), VF5TestCase(14, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.32), VF5TestCase(13, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.3), VF5TestCase(12, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.27), VF5TestCase(11, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.25), VF5TestCase(10, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.23), VF5TestCase(9, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.2), VF5TestCase(8, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.18), VF5TestCase(7, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.16), VF5TestCase(6, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.13), VF5TestCase(5, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.11), VF5TestCase(4, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.09), VF5TestCase(3, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.06), VF5TestCase(2, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.04), VF5TestCase(1, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.02), VF5TestCase(18, 9_700_000, "ULTIMATE CHAIN", 0.36), VF5TestCase(13, 9_700_000, "ULTIMATE CHAIN", 0.26), VF5TestCase(19, 9_500_000, "EXCESSIVE CLEAR", 0.35), VF5TestCase(19, 9_500_000, "CLEAR", 0.35), VF5TestCase(19, 9_500_000, "FAILED", 0.17), // The library used to return 0.28 for this case because of FloorToNDP(x, 2): // 0.29 * 100 = 28.999999999999996 VF5TestCase(16, 9_500_000, "CLEAR", 0.29), ]; for (const testCase of VF5ExampleData) { testCase(t); } t.end(); }); t.test("InverseVF5 Tests", (t) => { function InvVF5TestCase( level: number, vf5: number, lamp: Exclude<SDVXLamps, "PERFECT ULTIMATE CHAIN">, expectedScore: number ): TestCase { return (t) => { const score = inverseVF5(vf5, lamp, level); t.equal( score, expectedScore, `${vf5} VF5 on a level ${level} chart with lamp ${lamp} should be inverted to ${expectedScore}. (Got ${score})` ); }; } const testCases = [ InvVF5TestCase(20, 0.4, "CLEAR", 9_803_922), InvVF5TestCase(20, 0.4, "EXCESSIVE CLEAR", 9_800_000), InvVF5TestCase(13, 0.12, "CLEAR", 5_769_231), InvVF5TestCase(13, 0.12, "FAILED", 9_516_257), InvVF5TestCase(18, 0.31, "ULTIMATE CHAIN", 9_012_152), ]; for (const testCase of testCases) { testCase(t); } ThrowsToSnapshot( t, () => inverseVF5(900, "FAILED", 1), "Should throw if the volforce is impossible to achieve with this lamp/level." ); t.end(); }); t.test("VF6 Tests", (t) => { function VF6TestCase( level: number, score: number, lamp: SDVXLamps, expectedVF6: number ): TestCase { return (t) => { const vf6 = calculateVF6(score, lamp, level); t.equal( vf6, expectedVF6, `${score} on a level ${level} chart with lamp ${lamp} should be worth ${expectedVF6} VF6. (Got ${vf6})` ); }; } // No test data from bemaniwiki again. const VF5ExampleData = [ VF6TestCase(20, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.462), VF6TestCase(19, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.438), VF6TestCase(18, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.415), VF6TestCase(17, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.392), VF6TestCase(16, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.369), VF6TestCase(15, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.346), VF6TestCase(14, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.323), VF6TestCase(13, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.3), VF6TestCase(12, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.277), VF6TestCase(11, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.254), VF6TestCase(10, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.231), VF6TestCase(9, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.207), VF6TestCase(8, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.184), VF6TestCase(7, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.161), VF6TestCase(6, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.138), VF6TestCase(5, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.115), VF6TestCase(4, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.092), VF6TestCase(3, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.069), VF6TestCase(2, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.046), VF6TestCase(1, 10_000_000, "PERFECT ULTIMATE CHAIN", 0.023), VF6TestCase(18, 9_700_000, "ULTIMATE CHAIN", 0.366), VF6TestCase(13, 9_700_000, "ULTIMATE CHAIN", 0.264), // note: You can see the point of VF6 quite clearly here as EXC actually // differentiates Volforce values here -- unlike in VF5 where these would be // marked as the same. VF6TestCase(19, 9_500_000, "EXCESSIVE CLEAR", 0.357), VF6TestCase(18, 9_923_042, "MAXXIVE CLEAR", 0.390), VF6TestCase(19, 9_500_000, "CLEAR", 0.35), VF6TestCase(19, 9_500_000, "FAILED", 0.175), VF6TestCase(20, 5_000_000, "FAILED", 0.08), VF6TestCase(20, 7_000_000, "FAILED", 0.114), VF6TestCase(20, 8_000_000, "FAILED", 0.136), VF6TestCase(20, 8_700_000, "FAILED", 0.153), ]; for (const testCase of VF5ExampleData) { testCase(t); } t.end(); }); t.test("InverseVF6 Tests", (t) => { function InvVF6TestCase( level: number, vf6: number, lamp: Exclude<SDVXLamps, "PERFECT ULTIMATE CHAIN">, expectedScore: number ): TestCase { return (t) => { const score = inverseVF6(vf6, lamp, level); t.equal( score, expectedScore, `${vf6} VF6 on a level ${level} chart with lamp ${lamp} should be inverted to ${expectedScore}. (Got ${score})` ); }; } const testCases = [ InvVF6TestCase(20, 0.413, "CLEAR", 9_900_000), InvVF6TestCase(20, 0.232, "MAXXIVE CLEAR", 6_971_154), InvVF6TestCase(20, 0.421, "EXCESSIVE CLEAR", 9_900_000), InvVF6TestCase(13, 0.121, "CLEAR", 5_817_308), InvVF6TestCase(13, 0.121, "FAILED", 9_595_559), InvVF6TestCase(18, 0.31, "ULTIMATE CHAIN", 9_012_152), ]; for (const testCase of testCases) { testCase(t); } ThrowsToSnapshot( t, () => inverseVF6(900, "FAILED", 1), "Should throw if the volforce is impossible to achieve with this lamp/level." ); t.end(); });