80 lines
1.7 KiB
TypeScript
80 lines
1.7 KiB
TypeScript
import { Chess } from "chess.js";
|
|
|
|
const PGN_KEYS_TO_SHORT = {
|
|
Event: "E",
|
|
Site: "S",
|
|
White: "W",
|
|
Black: "B",
|
|
Date: "D",
|
|
Result: "R",
|
|
FEN: "F",
|
|
};
|
|
|
|
const PGN_KEYS = Object.keys(PGN_KEYS_TO_SHORT);
|
|
|
|
const PGN_KEYS_TO_LONG = Object.fromEntries(
|
|
Object.entries(PGN_KEYS_TO_SHORT).map(([long, short]) => [short, long])
|
|
);
|
|
|
|
const cleanPGN = (pgn: string) => {
|
|
const game = new Chess();
|
|
game.load_pgn(pgn);
|
|
game.delete_comments();
|
|
const [_, moves] = game.pgn().split("\n\n");
|
|
|
|
const header = Object.entries(game.header())
|
|
.filter(([key]) => PGN_KEYS.includes(key))
|
|
.map(([key, val]) => `[${key} "${val}"]`)
|
|
.sort()
|
|
.join("\n");
|
|
|
|
return [header, moves].join("\n\n");
|
|
};
|
|
|
|
const compressPGN = (pgn: string) => {
|
|
const game = new Chess();
|
|
game.load_pgn(pgn);
|
|
|
|
const moves = game.history().join(" ");
|
|
|
|
const header = Object.entries(game.header())
|
|
.filter(([key]) => PGN_KEYS.includes(key))
|
|
.map(([key, val]) => `${key[0].toUpperCase()} ${val}`)
|
|
.sort()
|
|
.join("\n");
|
|
|
|
return btoa([header, moves].join("\n\n"));
|
|
};
|
|
|
|
const decompressPGN = (compressedPGN: string) => {
|
|
const [headerRaw, movesRaw] = atob(compressedPGN).split("\n\n");
|
|
|
|
let result;
|
|
|
|
const header = headerRaw
|
|
.split("\n")
|
|
.map((entry) => {
|
|
const [shortKey, ...data] = entry.split(" ");
|
|
const value = data.join(" ");
|
|
|
|
if (shortKey === "R") {
|
|
result = value;
|
|
}
|
|
|
|
return `[${PGN_KEYS_TO_LONG[shortKey]} "${value}"]`;
|
|
})
|
|
.join("\n");
|
|
|
|
const moves =
|
|
movesRaw
|
|
.split(" ")
|
|
.map((move, index) =>
|
|
index % 2 === 0 ? `${index / 2 + 1}. ${move}` : move
|
|
)
|
|
.join(" ") + ` ${result}`;
|
|
|
|
return [header, moves].join("\n\n");
|
|
};
|
|
|
|
export { cleanPGN, compressPGN, decompressPGN };
|