mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-04 04:48:15 +03:00
Complete overhaul
This commit is contained in:
+2
-1
@@ -20,7 +20,8 @@
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"bracketSpacing": true,
|
||||
"endOfLine": "auto"
|
||||
"endOfLine": "auto",
|
||||
"useTabs": true
|
||||
}],
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/no-unused-expressions": "error",
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
/node_modules
|
||||
/.vscode
|
||||
|
||||
.nyc_output
|
||||
.nyc_output
|
||||
coverage
|
||||
+40
-26
@@ -1,27 +1,41 @@
|
||||
{
|
||||
"name": "tachi-common",
|
||||
"version": "0.1.0",
|
||||
"description": "Common Types & Stuff for Tachi",
|
||||
"main": "js/index.js",
|
||||
"scripts": {
|
||||
"test": "tap",
|
||||
"build": "tsc"
|
||||
},
|
||||
"author": "zkldi",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/tap": "^15.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.19.0",
|
||||
"@typescript-eslint/parser": "^4.19.0",
|
||||
"eslint": "^7.22.0",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"prettier": "^2.2.1",
|
||||
"ts-node": "^10.0.0",
|
||||
"typescript": "^4.3.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"monk": "^7.3.3",
|
||||
"tap": "^15.0.9"
|
||||
}
|
||||
}
|
||||
"name": "tachi-common",
|
||||
"version": "0.1.0",
|
||||
"description": "Common Types & Stuff for Tachi",
|
||||
"main": "js/index.js",
|
||||
"scripts": {
|
||||
"test": "tap",
|
||||
"build": "tsc"
|
||||
},
|
||||
"author": "zkldi",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/tap": "^15.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.19.0",
|
||||
"@typescript-eslint/parser": "^4.19.0",
|
||||
"eslint": "^7.22.0",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"prettier": "^2.2.1",
|
||||
"ts-node": "^10.0.0",
|
||||
"typescript": "^4.3.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"monk": "^7.3.3",
|
||||
"tap": "^15.0.9"
|
||||
},
|
||||
"nyc": {
|
||||
"reporter": [
|
||||
"html",
|
||||
"lcov"
|
||||
],
|
||||
"all": true,
|
||||
"include": [
|
||||
"src/*/!(test-utils)/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"src/**/*.test.ts",
|
||||
"src/external/mongo/schemas.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,23 +3,23 @@ import { GetGameConfig, GetGamePTConfig } from "./config";
|
||||
import { allSupportedGames } from "./static-config";
|
||||
|
||||
t.test("#GetGameConfig", (t) => {
|
||||
t.plan(allSupportedGames.length);
|
||||
t.plan(allSupportedGames.length);
|
||||
|
||||
for (const game of allSupportedGames) {
|
||||
t.equal(GetGameConfig(game).internalName, game);
|
||||
}
|
||||
for (const game of allSupportedGames) {
|
||||
t.equal(GetGameConfig(game).internalName, game);
|
||||
}
|
||||
});
|
||||
|
||||
// i have no idea why this one doesn't need t.end()
|
||||
// and this one does
|
||||
t.test("#GetGamePTConfig", (t) => {
|
||||
for (const game of allSupportedGames) {
|
||||
const gameConfig = GetGameConfig(game);
|
||||
for (const game of allSupportedGames) {
|
||||
const gameConfig = GetGameConfig(game);
|
||||
|
||||
for (const playtype of gameConfig.validPlaytypes) {
|
||||
t.equal(GetGamePTConfig(game, playtype).idString, `${game}:${playtype}`);
|
||||
}
|
||||
}
|
||||
for (const playtype of gameConfig.validPlaytypes) {
|
||||
t.equal(GetGamePTConfig(game, playtype).idString, `${game}:${playtype}`);
|
||||
}
|
||||
}
|
||||
|
||||
t.end();
|
||||
t.end();
|
||||
});
|
||||
|
||||
+933
-933
File diff suppressed because it is too large
Load Diff
@@ -1,89 +1,89 @@
|
||||
import { FileUploadImportTypes, IRImportTypes, APIImportTypes, ImportTypes, Game } from "..";
|
||||
|
||||
export const fileImportTypes: FileUploadImportTypes[] = [
|
||||
"file/eamusement-iidx-csv",
|
||||
"file/batch-manual",
|
||||
"file/solid-state-squad",
|
||||
"file/mer-iidx",
|
||||
"file/pli-iidx-csv",
|
||||
"file/eamusement-iidx-csv",
|
||||
"file/batch-manual",
|
||||
"file/solid-state-squad",
|
||||
"file/mer-iidx",
|
||||
"file/pli-iidx-csv",
|
||||
];
|
||||
|
||||
export const irImportTypes: IRImportTypes[] = [
|
||||
"ir/direct-manual",
|
||||
"ir/barbatos",
|
||||
"ir/fervidex",
|
||||
"ir/fervidex-static",
|
||||
"ir/beatoraja",
|
||||
"ir/chunitachi",
|
||||
"ir/usc",
|
||||
"ir/direct-manual",
|
||||
"ir/barbatos",
|
||||
"ir/fervidex",
|
||||
"ir/fervidex-static",
|
||||
"ir/beatoraja",
|
||||
"ir/chunitachi",
|
||||
"ir/usc",
|
||||
];
|
||||
|
||||
export const apiImportTypes: APIImportTypes[] = [
|
||||
"api/arc-iidx",
|
||||
"api/arc-sdvx",
|
||||
"api/arc-ddr",
|
||||
"api/eag-iidx",
|
||||
"api/eag-sdvx",
|
||||
"api/flo-iidx",
|
||||
"api/flo-sdvx",
|
||||
"api/arc-iidx",
|
||||
"api/arc-sdvx",
|
||||
"api/arc-ddr",
|
||||
"api/eag-iidx",
|
||||
"api/eag-sdvx",
|
||||
"api/flo-iidx",
|
||||
"api/flo-sdvx",
|
||||
];
|
||||
|
||||
export const allImportTypes: ImportTypes[] = [
|
||||
...fileImportTypes,
|
||||
...irImportTypes,
|
||||
...apiImportTypes,
|
||||
...fileImportTypes,
|
||||
...irImportTypes,
|
||||
...apiImportTypes,
|
||||
];
|
||||
|
||||
export const allSupportedGames: Game[] = [
|
||||
"iidx",
|
||||
"museca",
|
||||
"maimai",
|
||||
// "jubeat",
|
||||
// "popn",
|
||||
"sdvx",
|
||||
"ddr",
|
||||
"bms",
|
||||
"chunithm",
|
||||
"gitadora",
|
||||
"usc",
|
||||
"iidx",
|
||||
"museca",
|
||||
"maimai",
|
||||
// "jubeat",
|
||||
// "popn",
|
||||
"sdvx",
|
||||
"ddr",
|
||||
"bms",
|
||||
"chunithm",
|
||||
"gitadora",
|
||||
"usc",
|
||||
];
|
||||
|
||||
export interface ServerConfig {
|
||||
name: string;
|
||||
supportedGames: Game[];
|
||||
supportedImportTypes: ImportTypes[];
|
||||
name: string;
|
||||
supportedGames: Game[];
|
||||
supportedImportTypes: ImportTypes[];
|
||||
}
|
||||
|
||||
export const KTCHI_CONFIG: ServerConfig = {
|
||||
name: "Kamaitachi",
|
||||
supportedGames: ["iidx", "gitadora", "chunithm", "maimai", "museca", "sdvx"],
|
||||
supportedImportTypes: [
|
||||
"api/arc-iidx",
|
||||
"api/arc-sdvx",
|
||||
"api/arc-ddr",
|
||||
"api/eag-iidx",
|
||||
"api/eag-sdvx",
|
||||
"api/flo-iidx",
|
||||
"api/flo-sdvx",
|
||||
"ir/direct-manual",
|
||||
"ir/fervidex",
|
||||
"ir/fervidex-static",
|
||||
"ir/chunitachi",
|
||||
"file/eamusement-iidx-csv",
|
||||
"file/solid-state-squad",
|
||||
"file/mer-iidx",
|
||||
"file/pli-iidx-csv",
|
||||
],
|
||||
name: "Kamaitachi",
|
||||
supportedGames: ["iidx", "gitadora", "chunithm", "maimai", "museca", "sdvx"],
|
||||
supportedImportTypes: [
|
||||
"api/arc-iidx",
|
||||
"api/arc-sdvx",
|
||||
"api/arc-ddr",
|
||||
"api/eag-iidx",
|
||||
"api/eag-sdvx",
|
||||
"api/flo-iidx",
|
||||
"api/flo-sdvx",
|
||||
"ir/direct-manual",
|
||||
"ir/fervidex",
|
||||
"ir/fervidex-static",
|
||||
"ir/chunitachi",
|
||||
"file/eamusement-iidx-csv",
|
||||
"file/solid-state-squad",
|
||||
"file/mer-iidx",
|
||||
"file/pli-iidx-csv",
|
||||
],
|
||||
};
|
||||
|
||||
export const BTCHI_CONFIG: ServerConfig = {
|
||||
name: "Bokutachi",
|
||||
supportedGames: ["usc", "bms"],
|
||||
supportedImportTypes: ["ir/beatoraja", "ir/usc", "ir/direct-manual", "file/batch-manual"],
|
||||
name: "Bokutachi",
|
||||
supportedGames: ["usc", "bms"],
|
||||
supportedImportTypes: ["ir/beatoraja", "ir/usc", "ir/direct-manual", "file/batch-manual"],
|
||||
};
|
||||
|
||||
export const OMNI_CONFIG: ServerConfig = {
|
||||
name: "Omnitachi",
|
||||
supportedGames: allSupportedGames,
|
||||
supportedImportTypes: allImportTypes,
|
||||
name: "Omnitachi",
|
||||
supportedGames: allSupportedGames,
|
||||
supportedImportTypes: allImportTypes,
|
||||
};
|
||||
|
||||
+155
-155
@@ -4,191 +4,191 @@
|
||||
import { IDStrings, integer } from "./types";
|
||||
|
||||
export interface ClassInfo {
|
||||
display: string;
|
||||
mouseover: string | null;
|
||||
display: string;
|
||||
mouseover: string | null;
|
||||
}
|
||||
|
||||
function c(d: string, m: string) {
|
||||
return { display: d, mouseover: m };
|
||||
return { display: d, mouseover: m };
|
||||
}
|
||||
|
||||
function n(d: string) {
|
||||
return { display: d, mouseover: null };
|
||||
return { display: d, mouseover: null };
|
||||
}
|
||||
|
||||
export const IIDXDans: ClassInfo[] = [
|
||||
c("七級", "7th Kyu"),
|
||||
c("六級", "6th Kyu"),
|
||||
c("五級", "5th Kyu"),
|
||||
c("四級", "4th Kyu"),
|
||||
c("三級", "3rd Kyu"),
|
||||
c("二級", "2nd Kyu"),
|
||||
c("一級", "1st Kyu"),
|
||||
c("初段", "1st Dan"),
|
||||
c("二段", "2nd Dan"),
|
||||
c("三段", "3rd Dan"),
|
||||
c("四段", "4th Dan"),
|
||||
c("五段", "5th Dan"),
|
||||
c("六段", "6th Dan"),
|
||||
c("七段", "7th Dan"),
|
||||
c("八段", "8th Dan"),
|
||||
c("九段", "9th Dan"),
|
||||
c("十段", "10th Dan"),
|
||||
c("中伝", "Chuuden"),
|
||||
c("皆伝", "Kaiden"),
|
||||
c("七級", "7th Kyu"),
|
||||
c("六級", "6th Kyu"),
|
||||
c("五級", "5th Kyu"),
|
||||
c("四級", "4th Kyu"),
|
||||
c("三級", "3rd Kyu"),
|
||||
c("二級", "2nd Kyu"),
|
||||
c("一級", "1st Kyu"),
|
||||
c("初段", "1st Dan"),
|
||||
c("二段", "2nd Dan"),
|
||||
c("三段", "3rd Dan"),
|
||||
c("四段", "4th Dan"),
|
||||
c("五段", "5th Dan"),
|
||||
c("六段", "6th Dan"),
|
||||
c("七段", "7th Dan"),
|
||||
c("八段", "8th Dan"),
|
||||
c("九段", "9th Dan"),
|
||||
c("十段", "10th Dan"),
|
||||
c("中伝", "Chuuden"),
|
||||
c("皆伝", "Kaiden"),
|
||||
];
|
||||
|
||||
export const GitadoraColours: ClassInfo[] = [
|
||||
c("白", "White"),
|
||||
c("橙", "Orange"),
|
||||
c("橙グラ", "Orange Gradient"),
|
||||
c("黄", "Yellow"),
|
||||
c("黄グラ", "Yellow Gradient"),
|
||||
c("緑", "Green"),
|
||||
c("緑グラ", "Green Gradient"),
|
||||
c("青", "Blue"),
|
||||
c("青グラ", "Blue Gradient"),
|
||||
c("紫", "Purple"),
|
||||
c("紫グラ", "Purple Gradient"),
|
||||
c("赤", "Red"),
|
||||
c("赤グラ", "Red Gradient"),
|
||||
c("銅", "Bronze"),
|
||||
c("銀", "Silver"),
|
||||
c("金", "Gold"),
|
||||
c("虹", "Rainbow"),
|
||||
c("白", "White"),
|
||||
c("橙", "Orange"),
|
||||
c("橙グラ", "Orange Gradient"),
|
||||
c("黄", "Yellow"),
|
||||
c("黄グラ", "Yellow Gradient"),
|
||||
c("緑", "Green"),
|
||||
c("緑グラ", "Green Gradient"),
|
||||
c("青", "Blue"),
|
||||
c("青グラ", "Blue Gradient"),
|
||||
c("紫", "Purple"),
|
||||
c("紫グラ", "Purple Gradient"),
|
||||
c("赤", "Red"),
|
||||
c("赤グラ", "Red Gradient"),
|
||||
c("銅", "Bronze"),
|
||||
c("銀", "Silver"),
|
||||
c("金", "Gold"),
|
||||
c("虹", "Rainbow"),
|
||||
];
|
||||
|
||||
export const BMSGenocideDans: ClassInfo[] = [
|
||||
c("☆1", "Normal 1st Dan"),
|
||||
c("☆2", "Normal 2nd Dan"),
|
||||
c("☆3", "Normal 3rd Dan"),
|
||||
c("☆4", "Normal 4th Dan"),
|
||||
c("☆5", "Normal 5th Dan"),
|
||||
c("☆6", "Normal 6th Dan"),
|
||||
c("☆7", "Normal 7th Dan"),
|
||||
c("☆8", "Normal 8th Dan"),
|
||||
c("☆9", "Normal 9th Dan"),
|
||||
c("☆10", "Normal 10th Dan"),
|
||||
c("★1", "Insane 1st Dan"),
|
||||
c("★2", "Insane 2nd Dan"),
|
||||
c("★3", "Insane 3rd Dan"),
|
||||
c("★4", "Insane 4th Dan"),
|
||||
c("★5", "Insane 5th Dan"),
|
||||
c("★6", "Insane 6th Dan"),
|
||||
c("★7", "Insane 7th Dan"),
|
||||
c("★8", "Insane 8th Dan"),
|
||||
c("★9", "Insane 9th Dan"),
|
||||
c("★10", "Insane 10th Dan"),
|
||||
c("★★", "Insane Kaiden"),
|
||||
c("(^^)", "Overjoy"),
|
||||
c("☆1", "Normal 1st Dan"),
|
||||
c("☆2", "Normal 2nd Dan"),
|
||||
c("☆3", "Normal 3rd Dan"),
|
||||
c("☆4", "Normal 4th Dan"),
|
||||
c("☆5", "Normal 5th Dan"),
|
||||
c("☆6", "Normal 6th Dan"),
|
||||
c("☆7", "Normal 7th Dan"),
|
||||
c("☆8", "Normal 8th Dan"),
|
||||
c("☆9", "Normal 9th Dan"),
|
||||
c("☆10", "Normal 10th Dan"),
|
||||
c("★1", "Insane 1st Dan"),
|
||||
c("★2", "Insane 2nd Dan"),
|
||||
c("★3", "Insane 3rd Dan"),
|
||||
c("★4", "Insane 4th Dan"),
|
||||
c("★5", "Insane 5th Dan"),
|
||||
c("★6", "Insane 6th Dan"),
|
||||
c("★7", "Insane 7th Dan"),
|
||||
c("★8", "Insane 8th Dan"),
|
||||
c("★9", "Insane 9th Dan"),
|
||||
c("★10", "Insane 10th Dan"),
|
||||
c("★★", "Insane Kaiden"),
|
||||
c("(^^)", "Overjoy"),
|
||||
];
|
||||
|
||||
export const BMSStSlDans: ClassInfo[] = [
|
||||
c("sl0", "Satellite 0"),
|
||||
c("sl1", "Satellite 1"),
|
||||
c("sl2", "Satellite 2"),
|
||||
c("sl3", "Satellite 3"),
|
||||
c("sl4", "Satellite 4"),
|
||||
c("sl5", "Satellite 5"),
|
||||
c("sl6", "Satellite 6"),
|
||||
c("sl7", "Satellite 7"),
|
||||
c("sl8", "Satellite 8"),
|
||||
c("sl9", "Satellite 9"),
|
||||
c("sl10", "Satellite 10"),
|
||||
c("sl11", "Satellite 11"),
|
||||
c("sl12", "Satellite 12"),
|
||||
c("st0", "Stella 0"),
|
||||
c("st1", "Stella 1"),
|
||||
c("st2", "Stella 2"),
|
||||
c("st3", "Stella 3"),
|
||||
c("st4", "Stella 4"),
|
||||
c("st5", "Stella 5"),
|
||||
c("st6", "Stella 6"),
|
||||
c("st7", "Stella 7"),
|
||||
c("st8", "Stella 8"),
|
||||
c("st9", "Stella 9"),
|
||||
c("st10", "Stella 10"),
|
||||
c("st11", "Stella 11"),
|
||||
c("sl0", "Satellite 0"),
|
||||
c("sl1", "Satellite 1"),
|
||||
c("sl2", "Satellite 2"),
|
||||
c("sl3", "Satellite 3"),
|
||||
c("sl4", "Satellite 4"),
|
||||
c("sl5", "Satellite 5"),
|
||||
c("sl6", "Satellite 6"),
|
||||
c("sl7", "Satellite 7"),
|
||||
c("sl8", "Satellite 8"),
|
||||
c("sl9", "Satellite 9"),
|
||||
c("sl10", "Satellite 10"),
|
||||
c("sl11", "Satellite 11"),
|
||||
c("sl12", "Satellite 12"),
|
||||
c("st0", "Stella 0"),
|
||||
c("st1", "Stella 1"),
|
||||
c("st2", "Stella 2"),
|
||||
c("st3", "Stella 3"),
|
||||
c("st4", "Stella 4"),
|
||||
c("st5", "Stella 5"),
|
||||
c("st6", "Stella 6"),
|
||||
c("st7", "Stella 7"),
|
||||
c("st8", "Stella 8"),
|
||||
c("st9", "Stella 9"),
|
||||
c("st10", "Stella 10"),
|
||||
c("st11", "Stella 11"),
|
||||
];
|
||||
|
||||
export const SDVXDans: ClassInfo[] = [
|
||||
c("LV.01", "1st Dan"),
|
||||
c("LV.02", "2nd Dan"),
|
||||
c("LV.03", "3rd Dan"),
|
||||
c("LV.04", "4th Dan"),
|
||||
c("LV.05", "5th Dan"),
|
||||
c("LV.06", "6th Dan"),
|
||||
c("LV.07", "7th Dan"),
|
||||
c("LV.08", "8th Dan"),
|
||||
c("LV.09", "9th Dan"),
|
||||
c("LV.10", "10th Dan"),
|
||||
c("LV.11", "11th Dan"),
|
||||
c("LV.INF", "Inf. Dan"),
|
||||
c("LV.01", "1st Dan"),
|
||||
c("LV.02", "2nd Dan"),
|
||||
c("LV.03", "3rd Dan"),
|
||||
c("LV.04", "4th Dan"),
|
||||
c("LV.05", "5th Dan"),
|
||||
c("LV.06", "6th Dan"),
|
||||
c("LV.07", "7th Dan"),
|
||||
c("LV.08", "8th Dan"),
|
||||
c("LV.09", "9th Dan"),
|
||||
c("LV.10", "10th Dan"),
|
||||
c("LV.11", "11th Dan"),
|
||||
c("LV.INF", "Inf. Dan"),
|
||||
];
|
||||
|
||||
export const SDVXVFClasses: ClassInfo[] = [
|
||||
n("Sienna I"),
|
||||
n("Sienna II"),
|
||||
n("Sienna III"),
|
||||
n("Sienna IV"),
|
||||
n("Cobalt I"),
|
||||
n("Cobalt II"),
|
||||
n("Cobalt III"),
|
||||
n("Cobalt IV"),
|
||||
n("Dandelion I"),
|
||||
n("Dandelion II"),
|
||||
n("Dandelion III"),
|
||||
n("Dandelion IV"),
|
||||
n("Cyan I"),
|
||||
n("Cyan II"),
|
||||
n("Cyan III"),
|
||||
n("Cyan IV"),
|
||||
n("Scarlet I"),
|
||||
n("Scarlet II"),
|
||||
n("Scarlet III"),
|
||||
n("Scarlet IV"),
|
||||
n("Coral I"),
|
||||
n("Coral II"),
|
||||
n("Coral III"),
|
||||
n("Coral IV"),
|
||||
n("Argento I"),
|
||||
n("Argento II"),
|
||||
n("Argento III"),
|
||||
n("Argento IV"),
|
||||
n("Eldora I"),
|
||||
n("Eldora II"),
|
||||
n("Eldora III"),
|
||||
n("Eldora IV"),
|
||||
n("Crimson I"),
|
||||
n("Crimson II"),
|
||||
n("Crimson III"),
|
||||
n("Crimson IV"),
|
||||
n("Imperial I"),
|
||||
n("Imperial II"),
|
||||
n("Imperial III"),
|
||||
n("Imperial IV"),
|
||||
n("Sienna I"),
|
||||
n("Sienna II"),
|
||||
n("Sienna III"),
|
||||
n("Sienna IV"),
|
||||
n("Cobalt I"),
|
||||
n("Cobalt II"),
|
||||
n("Cobalt III"),
|
||||
n("Cobalt IV"),
|
||||
n("Dandelion I"),
|
||||
n("Dandelion II"),
|
||||
n("Dandelion III"),
|
||||
n("Dandelion IV"),
|
||||
n("Cyan I"),
|
||||
n("Cyan II"),
|
||||
n("Cyan III"),
|
||||
n("Cyan IV"),
|
||||
n("Scarlet I"),
|
||||
n("Scarlet II"),
|
||||
n("Scarlet III"),
|
||||
n("Scarlet IV"),
|
||||
n("Coral I"),
|
||||
n("Coral II"),
|
||||
n("Coral III"),
|
||||
n("Coral IV"),
|
||||
n("Argento I"),
|
||||
n("Argento II"),
|
||||
n("Argento III"),
|
||||
n("Argento IV"),
|
||||
n("Eldora I"),
|
||||
n("Eldora II"),
|
||||
n("Eldora III"),
|
||||
n("Eldora IV"),
|
||||
n("Crimson I"),
|
||||
n("Crimson II"),
|
||||
n("Crimson III"),
|
||||
n("Crimson IV"),
|
||||
n("Imperial I"),
|
||||
n("Imperial II"),
|
||||
n("Imperial III"),
|
||||
n("Imperial IV"),
|
||||
];
|
||||
|
||||
export interface GameClassSets {
|
||||
"iidx:SP": "dan";
|
||||
"iidx:DP": "dan";
|
||||
"popn:9B": never;
|
||||
"sdvx:Single": "dan" | "vfClass";
|
||||
"usc:Single": never;
|
||||
"ddr:SP": "dan";
|
||||
"ddr:DP": "dan";
|
||||
"maimai:Single": never;
|
||||
"jubeat:Single": "colour";
|
||||
"museca:Single": never;
|
||||
"bms:7K": "genocideDan" | "stslDan";
|
||||
"bms:14K": "genocideDan";
|
||||
"chunithm:Single": never;
|
||||
"gitadora:Gita": "colour";
|
||||
"gitadora:Dora": "colour";
|
||||
"iidx:SP": "dan";
|
||||
"iidx:DP": "dan";
|
||||
"popn:9B": never;
|
||||
"sdvx:Single": "dan" | "vfClass";
|
||||
"usc:Single": never;
|
||||
"ddr:SP": "dan";
|
||||
"ddr:DP": "dan";
|
||||
"maimai:Single": never;
|
||||
"jubeat:Single": "colour";
|
||||
"museca:Single": never;
|
||||
"bms:7K": "genocideDan" | "stslDan";
|
||||
"bms:14K": "genocideDan";
|
||||
"chunithm:Single": never;
|
||||
"gitadora:Gita": "colour";
|
||||
"gitadora:Dora": "colour";
|
||||
}
|
||||
|
||||
export type AllClassSets = GameClassSets[IDStrings];
|
||||
|
||||
export type GameClasses<I extends IDStrings> = {
|
||||
[K in GameClassSets[I]]: integer;
|
||||
[K in GameClassSets[I]]: integer;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import t from "tap";
|
||||
|
||||
import * as tachiCommon from "./index";
|
||||
|
||||
// we just check that we're exporting stuff properly
|
||||
t.test("Property Checks", (t) => {
|
||||
t.type(tachiCommon.GetGameConfig, "function");
|
||||
t.type(tachiCommon.GetGamePTConfig, "function");
|
||||
t.type(tachiCommon.gameClasses, "object");
|
||||
t.type(tachiCommon.COLOUR_SET, "object");
|
||||
|
||||
t.end();
|
||||
});
|
||||
+479
-479
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
import t from "tap";
|
||||
import { GetGamePTConfig } from "../config/config";
|
||||
import { CalculateESD, ESDCompare, PercentCompare } from "./esd";
|
||||
|
||||
function approx(t: Tap.Test, given: number, recieved: number, acc = 0.01) {
|
||||
if (Math.abs(given - recieved) < acc) {
|
||||
return t.pass();
|
||||
} else {
|
||||
return t.fail(`Expected ${given} to be within ${acc} of ${recieved}.`);
|
||||
}
|
||||
}
|
||||
|
||||
t.test("#CalculateESD", (t) => {
|
||||
const jdg = GetGamePTConfig("iidx", "SP").judgementWindows!;
|
||||
approx(t, CalculateESD(jdg, 0.8), 17.58);
|
||||
approx(t, CalculateESD(jdg, 0), 200);
|
||||
t.throws(() => CalculateESD(jdg, 0, true));
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("#ESDCompare", (t) => {
|
||||
approx(t, ESDCompare(16, 14), 6.42);
|
||||
approx(t, ESDCompare(16, 14, 1), ESDCompare(16, 14));
|
||||
approx(t, ESDCompare(0, 200, 1), -68.27);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("#PercentCompare", (t) => {
|
||||
const jdg = GetGamePTConfig("iidx", "SP").judgementWindows!;
|
||||
approx(t, PercentCompare(jdg, 0.99, 0.98), -5.53);
|
||||
approx(t, PercentCompare(jdg, 0.99, 0.98), PercentCompare(jdg, 0.99, 0.98, 1));
|
||||
|
||||
t.end();
|
||||
});
|
||||
+100
-103
@@ -3,7 +3,7 @@
|
||||
* https://en.wikipedia.org/wiki/Cumulative_distribution_function
|
||||
*/
|
||||
function cdf(x: number, mean: number, variance: number) {
|
||||
return 0.5 * (1 + erf((x - mean) / Math.sqrt(2 * variance)));
|
||||
return 0.5 * (1 + erf((x - mean) / Math.sqrt(2 * variance)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -11,27 +11,27 @@ function cdf(x: number, mean: number, variance: number) {
|
||||
* https://en.wikipedia.org/wiki/Error_function
|
||||
*/
|
||||
function erf(x: number) {
|
||||
// save the sign of x
|
||||
const sign = x >= 0 ? 1 : -1;
|
||||
x = Math.abs(x);
|
||||
// save the sign of x
|
||||
const sign = x >= 0 ? 1 : -1;
|
||||
x = Math.abs(x);
|
||||
|
||||
// constants
|
||||
const a1 = 0.254829592;
|
||||
const a2 = -0.284496736;
|
||||
const a3 = 1.421413741;
|
||||
const a4 = -1.453152027;
|
||||
const a5 = 1.061405429;
|
||||
const p = 0.3275911;
|
||||
// constants
|
||||
const a1 = 0.254829592;
|
||||
const a2 = -0.284496736;
|
||||
const a3 = 1.421413741;
|
||||
const a4 = -1.453152027;
|
||||
const a5 = 1.061405429;
|
||||
const p = 0.3275911;
|
||||
|
||||
// A&S formula 7.1.26
|
||||
const t = 1.0 / (1.0 + p * x);
|
||||
const y = 1.0 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
|
||||
return sign * y; // erf(-x) = -erf(x);
|
||||
// A&S formula 7.1.26
|
||||
const t = 1.0 / (1.0 + p * x);
|
||||
const y = 1.0 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
|
||||
return sign * y; // erf(-x) = -erf(x);
|
||||
}
|
||||
|
||||
function CDFBetween(lowBound: number, highBound: number, mean: number, variance: number) {
|
||||
// Since the normal distribution is symmetrical, we want to double this, as the cut will only get one tail.
|
||||
return 2 * (cdf(highBound, mean, variance) - cdf(lowBound, mean, variance));
|
||||
// Since the normal distribution is symmetrical, we want to double this, as the cut will only get one tail.
|
||||
return 2 * (cdf(highBound, mean, variance) - cdf(lowBound, mean, variance));
|
||||
}
|
||||
|
||||
// This is a direct port of ESD-JS to typescript. Maybe this should be released as its own module some day.
|
||||
@@ -46,32 +46,32 @@ const MEAN = 0;
|
||||
* @returns The percent this std. deviation would produce.
|
||||
*/
|
||||
function StdDeviationToPercent(
|
||||
judgements: ESDJudgementFormat[],
|
||||
stddev: number,
|
||||
largestValue: number
|
||||
judgements: ESDJudgementFormat[],
|
||||
stddev: number,
|
||||
largestValue: number
|
||||
) {
|
||||
let lastJudgeMSBorder = 0;
|
||||
let prbSum = 0;
|
||||
let lastJudgeMSBorder = 0;
|
||||
let prbSum = 0;
|
||||
|
||||
for (let i = 0; i < judgements.length; i++) {
|
||||
const judge = judgements[i];
|
||||
const nVal = CDFBetween(lastJudgeMSBorder, judge.msBorder, MEAN, stddev ** 2) * judge.value;
|
||||
lastJudgeMSBorder = judge.msBorder;
|
||||
prbSum += nVal;
|
||||
}
|
||||
for (let i = 0; i < judgements.length; i++) {
|
||||
const judge = judgements[i];
|
||||
const nVal = CDFBetween(lastJudgeMSBorder, judge.msBorder, MEAN, stddev ** 2) * judge.value;
|
||||
lastJudgeMSBorder = judge.msBorder;
|
||||
prbSum += nVal;
|
||||
}
|
||||
|
||||
prbSum /= largestValue;
|
||||
prbSum /= largestValue;
|
||||
|
||||
return prbSum;
|
||||
return prbSum;
|
||||
}
|
||||
|
||||
const ACCEPTABLE_ERROR = 0.001;
|
||||
const MAX_ITERATIONS = 50;
|
||||
|
||||
export interface ESDJudgementFormat {
|
||||
name: string;
|
||||
msBorder: number;
|
||||
value: number;
|
||||
name: string;
|
||||
msBorder: number;
|
||||
value: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,58 +83,55 @@ export interface ESDJudgementFormat {
|
||||
* @returns
|
||||
*/
|
||||
export function CalculateESD(
|
||||
judgements: ESDJudgementFormat[],
|
||||
percent: number,
|
||||
errOnInaccuracy = false
|
||||
judgements: ESDJudgementFormat[],
|
||||
percent: number,
|
||||
errOnInaccuracy = false
|
||||
): number {
|
||||
if (percent > 1 || percent < 0 || Number.isNaN(percent)) {
|
||||
throw new Error(
|
||||
"(ESD) Invalid percent. Percent must be between 0 and 1, and also a number."
|
||||
);
|
||||
}
|
||||
const largestValue = judgements.slice(0).sort((a, b) => b.value - a.value)[0].value;
|
||||
if (percent > 1 || percent < 0 || Number.isNaN(percent)) {
|
||||
throw new Error(
|
||||
"(ESD) Invalid percent. Percent must be between 0 and 1, and also a number."
|
||||
);
|
||||
}
|
||||
const largestValue = judgements.slice(0).sort((a, b) => b.value - a.value)[0].value;
|
||||
|
||||
// massive optimisation possible here by using better initial estimates with precalc'd table of values.
|
||||
// until then, it's just kinda slow.
|
||||
let minSD = 0;
|
||||
let maxSD = 200;
|
||||
let estSD = (minSD + maxSD) / 2;
|
||||
// massive optimisation possible here by using better initial estimates with precalc'd table of values.
|
||||
// until then, it's just kinda slow.
|
||||
let minSD = 0;
|
||||
let maxSD = 200;
|
||||
let estSD = (minSD + maxSD) / 2;
|
||||
|
||||
// So, fundamentally the function that takes SD and returns estimated percent is NOT invertible.
|
||||
// as in, it is very literally not invertible.
|
||||
// if you figure it out, let me know.
|
||||
// until then; we make MAX_ITERATIONS attempts at finding a value within the acceptable range of error.
|
||||
// the defaults for these are 100 for iterations, and 0.001 for error.
|
||||
// for most of what i've tested, this has been fine.
|
||||
for (let i = 0; i < MAX_ITERATIONS; i++) {
|
||||
const estimatedPercent = StdDeviationToPercent(judgements, estSD, largestValue);
|
||||
// So, fundamentally the function that takes SD and returns estimated percent is NOT invertible.
|
||||
// as in, it is very literally not invertible.
|
||||
// if you figure it out, let me know.
|
||||
// until then; we make MAX_ITERATIONS attempts at finding a value within the acceptable range of error.
|
||||
// the defaults for these are 100 for iterations, and 0.001 for error.
|
||||
// for most of what i've tested, this has been fine.
|
||||
for (let i = 0; i < MAX_ITERATIONS; i++) {
|
||||
const estimatedPercent = StdDeviationToPercent(judgements, estSD, largestValue);
|
||||
|
||||
if (Math.abs(estimatedPercent - percent) < ACCEPTABLE_ERROR) {
|
||||
return estSD;
|
||||
}
|
||||
if (Math.abs(estimatedPercent - percent) < ACCEPTABLE_ERROR) {
|
||||
return estSD;
|
||||
}
|
||||
|
||||
if (estimatedPercent < percent) {
|
||||
maxSD = estSD;
|
||||
} else {
|
||||
minSD = estSD;
|
||||
}
|
||||
if (estimatedPercent < percent) {
|
||||
maxSD = estSD;
|
||||
} else {
|
||||
minSD = estSD;
|
||||
}
|
||||
|
||||
if (estSD === (minSD + maxSD) / 2) {
|
||||
// if it isn't moving, just terminate
|
||||
break;
|
||||
}
|
||||
if (estSD === (minSD + maxSD) / 2) {
|
||||
// if it isn't moving, just terminate
|
||||
break;
|
||||
}
|
||||
|
||||
estSD = (minSD + maxSD) / 2;
|
||||
}
|
||||
estSD = (minSD + maxSD) / 2;
|
||||
}
|
||||
|
||||
if (errOnInaccuracy) {
|
||||
throw `(ESD-JS) Did not reach value within MAX_ITERATIONS (${MAX_ITERATIONS})`;
|
||||
} else {
|
||||
console.warn(
|
||||
`(ESD-JS) Did not reach value within MAX_ITERATIONS (${MAX_ITERATIONS}), returning last estimate (${estSD}), which was generated from ${percent}.`
|
||||
);
|
||||
return estSD;
|
||||
}
|
||||
if (errOnInaccuracy) {
|
||||
throw `(ESD-JS) Did not reach value within MAX_ITERATIONS (${MAX_ITERATIONS})`;
|
||||
}
|
||||
|
||||
return estSD;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,42 +142,42 @@ export function CalculateESD(
|
||||
* @returns A number between -100 and 100.
|
||||
*/
|
||||
export function ESDCompare(baseESD: number, compareESD: number, cdeg = 1): number {
|
||||
const CONFIDENCE_DEGREE = cdeg;
|
||||
const BASE_CASE = CDFBetween(-1 * CONFIDENCE_DEGREE, CONFIDENCE_DEGREE, 0, 1) / 2;
|
||||
const CONFIDENCE_DEGREE = cdeg;
|
||||
const BASE_CASE = CDFBetween(-1 * CONFIDENCE_DEGREE, CONFIDENCE_DEGREE, 0, 1) / 2;
|
||||
|
||||
let inv = false;
|
||||
let variance;
|
||||
let bound;
|
||||
if (compareESD > baseESD) {
|
||||
inv = true;
|
||||
variance = compareESD ** 2;
|
||||
bound = CONFIDENCE_DEGREE * baseESD;
|
||||
} else {
|
||||
variance = baseESD ** 2;
|
||||
bound = CONFIDENCE_DEGREE * compareESD;
|
||||
}
|
||||
let inv = false;
|
||||
let variance;
|
||||
let bound;
|
||||
if (compareESD > baseESD) {
|
||||
inv = true;
|
||||
variance = compareESD ** 2;
|
||||
bound = CONFIDENCE_DEGREE * baseESD;
|
||||
} else {
|
||||
variance = baseESD ** 2;
|
||||
bound = CONFIDENCE_DEGREE * compareESD;
|
||||
}
|
||||
|
||||
const esdc = CDFBetween(-1 * bound, bound, 0, variance) / 2;
|
||||
const esdc = CDFBetween(-1 * bound, bound, 0, variance) / 2;
|
||||
|
||||
let besdc = BASE_CASE - esdc;
|
||||
let besdc = BASE_CASE - esdc;
|
||||
|
||||
if (inv) {
|
||||
besdc *= -1;
|
||||
}
|
||||
if (inv) {
|
||||
besdc *= -1;
|
||||
}
|
||||
|
||||
return besdc * 100;
|
||||
return besdc * 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts two percents to ESD, then runs ESDCompare.
|
||||
*/
|
||||
export function PercentCompare(
|
||||
judgements: ESDJudgementFormat[],
|
||||
baseP: number,
|
||||
compareP: number,
|
||||
cdeg = 1
|
||||
judgements: ESDJudgementFormat[],
|
||||
baseP: number,
|
||||
compareP: number,
|
||||
cdeg = 1
|
||||
): number {
|
||||
const e1 = CalculateESD(judgements, baseP);
|
||||
const e2 = CalculateESD(judgements, compareP);
|
||||
return ESDCompare(e1, e2, cdeg);
|
||||
const e1 = CalculateESD(judgements, baseP);
|
||||
const e2 = CalculateESD(judgements, compareP);
|
||||
return ESDCompare(e1, e2, cdeg);
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ import t from "tap";
|
||||
import { CalculateGradeDeltaIIDX } from "./util";
|
||||
|
||||
t.test("#CalculateGradeDeltaIIDX", (t) => {
|
||||
t.equal(CalculateGradeDeltaIIDX("A", 1000, 2000), "A-334");
|
||||
t.equal(CalculateGradeDeltaIIDX("AAA", 1778, 2000), "AAA+0");
|
||||
t.equal(CalculateGradeDeltaIIDX("MAX", 1900, 2000), "MAX-100");
|
||||
t.equal(CalculateGradeDeltaIIDX("A", 1000, 2000), "A-334");
|
||||
t.equal(CalculateGradeDeltaIIDX("AAA", 1778, 2000), "AAA+0");
|
||||
t.equal(CalculateGradeDeltaIIDX("MAX", 1900, 2000), "MAX-100");
|
||||
|
||||
t.end();
|
||||
t.end();
|
||||
});
|
||||
|
||||
+13
-13
@@ -4,22 +4,22 @@ import { Grades, integer } from "../types";
|
||||
const IIDXConfig = GetGamePTConfig("iidx", "SP");
|
||||
|
||||
export function CalculateGradeDeltaIIDX(
|
||||
cmpGrade: Grades["iidx:SP" | "iidx:DP"],
|
||||
score: integer,
|
||||
notecount: integer
|
||||
cmpGrade: Grades["iidx:SP" | "iidx:DP"],
|
||||
score: integer,
|
||||
notecount: integer
|
||||
): string {
|
||||
const cmpGradeIDX = IIDXConfig.grades.indexOf(cmpGrade);
|
||||
const cmpGradeIDX = IIDXConfig.grades.indexOf(cmpGrade);
|
||||
|
||||
const cmpGradePercent = IIDXConfig.gradeBoundaries[cmpGradeIDX];
|
||||
const cmpGradePercent = IIDXConfig.gradeBoundaries[cmpGradeIDX];
|
||||
|
||||
const cmpScore = Math.ceil(notecount * (cmpGradePercent / 100));
|
||||
const cmpScore = Math.ceil(notecount * (cmpGradePercent / 100));
|
||||
|
||||
const delta = score - cmpScore;
|
||||
const delta = score - cmpScore;
|
||||
|
||||
if (delta >= 0) {
|
||||
return `${cmpGrade}+${delta}`;
|
||||
} else {
|
||||
// negative numbers implicitly stringify with the - prefix
|
||||
return `${cmpGrade}${delta}`;
|
||||
}
|
||||
if (delta >= 0) {
|
||||
return `${cmpGrade}+${delta}`;
|
||||
} else {
|
||||
// negative numbers implicitly stringify with the - prefix
|
||||
return `${cmpGrade}${delta}`;
|
||||
}
|
||||
}
|
||||
|
||||
+952
-952
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user