sendou.ink/app/modules/map-pool-serializer/serializer.ts
2022-10-27 13:31:36 +02:00

85 lines
1.9 KiB
TypeScript

import invariant from "tiny-invariant";
import { modesShort, type StageId, stageIds } from "../in-game-lists";
import type { MapPoolObject, ReadonlyMapPoolObject } from "./types";
export function mapPoolToSerializedString(
mapPool: ReadonlyMapPoolObject
): string {
const serializedModes = [];
for (const mode of modesShort) {
const stages = mapPool[mode];
if (stages.length === 0) continue;
serializedModes.push(`${mode}:${binaryToHex(stageIdsToBinary(stages))}`);
}
return serializedModes.join(";").toLowerCase();
}
function stageIdsToBinary(input: readonly StageId[]) {
let result = "1";
for (const stageId of stageIds) {
if (input.includes(stageId)) {
result += "1";
} else {
result += "0";
}
}
return result;
}
function binaryToHex(binary: string) {
return parseInt(binary, 2).toString(16);
}
export function serializedStringToMapPool(
serialized: string
): ReadonlyMapPoolObject {
const result: MapPoolObject = {
SZ: [],
CB: [],
RM: [],
TC: [],
TW: [],
};
for (const serializedMode of serialized.split(";")) {
const [mode, mapsInHex] = serializedMode.split(":");
if (!mode || !mapsInHex) continue;
const validatedMode = modesShort.find(
(realMode) => realMode === mode.toUpperCase()
);
if (!validatedMode) continue;
const stagesBinary = hexToBinary(mapsInHex);
result[validatedMode].push(...binaryToStageIds(stagesBinary));
}
return result;
}
function binaryToStageIds(binary: string): readonly StageId[] {
const result: StageId[] = [];
// first 1 is padding
for (let i = 1; i <= stageIds.length; i++) {
const letter = binary[i];
if (letter === "0" || !letter) continue;
const stage = stageIds[i - 1];
invariant(typeof stage === "number");
result.push(stage);
}
return result;
}
function hexToBinary(hex: string) {
return parseInt(hex, 16).toString(2);
}