pgn-manager 2.2.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +12 -1
- package/dist/index.js +50 -13
- package/package.json +3 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { ShortMove } from "chess.js";
|
|
2
1
|
import * as pgnParser from "pgn-parser";
|
|
3
2
|
import type { ParsedPGN, Move, Rav, Header, Result } from "pgn-parser";
|
|
4
3
|
export declare const FEN_START_POSITION = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
5
4
|
export declare const FEN_EMPTY_POSITION = "8/8/8/8/8/8/8/8";
|
|
5
|
+
/** Move input type for pushMove — from/to with optional promotion */
|
|
6
|
+
export type ShortMove = {
|
|
7
|
+
from: string;
|
|
8
|
+
to: string;
|
|
9
|
+
promotion?: string;
|
|
10
|
+
};
|
|
6
11
|
declare class PGNManager {
|
|
7
12
|
/** The raw PGN string input */
|
|
8
13
|
private rawPGN;
|
|
@@ -20,11 +25,17 @@ declare class PGNManager {
|
|
|
20
25
|
private ravParent;
|
|
21
26
|
/** Map of moves to the color of the player who made the move */
|
|
22
27
|
private moveColor;
|
|
28
|
+
/** Whether this game is a Chess960 game */
|
|
29
|
+
private _isChess960;
|
|
23
30
|
/**
|
|
24
31
|
* Creates a new PGNManager instance
|
|
25
32
|
* @param pgn - The PGN string to parse and manage
|
|
26
33
|
*/
|
|
27
34
|
constructor(pgn: string);
|
|
35
|
+
/**
|
|
36
|
+
* Returns whether this game is a Chess960 game
|
|
37
|
+
*/
|
|
38
|
+
get isChess960(): boolean;
|
|
28
39
|
/**
|
|
29
40
|
* Initializes the game traversal starting from the initial position
|
|
30
41
|
* @param game - The parsed PGN game object
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FEN_EMPTY_POSITION = exports.FEN_START_POSITION = void 0;
|
|
4
|
-
const
|
|
5
|
-
const Chess = typeof ChessJS === "function" ? ChessJS : ChessJS.Chess;
|
|
4
|
+
const void57_chess_1 = require("void57-chess");
|
|
6
5
|
const pgnParser = require("pgn-parser");
|
|
7
6
|
const utils_1 = require("./utils");
|
|
8
7
|
exports.FEN_START_POSITION = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
9
8
|
exports.FEN_EMPTY_POSITION = "8/8/8/8/8/8/8/8";
|
|
9
|
+
/** Known variant header values that indicate Chess960 */
|
|
10
|
+
const CHESS960_VARIANTS = ["chess960", "fischerandom", "fischerrandom"];
|
|
11
|
+
/**
|
|
12
|
+
* Determines whether the game is a Chess960 game based on PGN headers
|
|
13
|
+
*/
|
|
14
|
+
function isChess960Game(headers) {
|
|
15
|
+
if (!headers)
|
|
16
|
+
return false;
|
|
17
|
+
const variant = headers.find((h) => h.name.toLowerCase() === "variant")?.value;
|
|
18
|
+
return variant ? CHESS960_VARIANTS.includes(variant.toLowerCase()) : false;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates the appropriate Chess or Chess960 instance based on game headers
|
|
22
|
+
*/
|
|
23
|
+
function createChessInstance(fen, headers) {
|
|
24
|
+
if (isChess960Game(headers)) {
|
|
25
|
+
return new void57_chess_1.Chess960(fen);
|
|
26
|
+
}
|
|
27
|
+
return new void57_chess_1.Chess(fen);
|
|
28
|
+
}
|
|
10
29
|
class PGNManager {
|
|
11
30
|
/** The raw PGN string input */
|
|
12
31
|
rawPGN;
|
|
@@ -24,6 +43,8 @@ class PGNManager {
|
|
|
24
43
|
ravParent;
|
|
25
44
|
/** Map of moves to the color of the player who made the move */
|
|
26
45
|
moveColor;
|
|
46
|
+
/** Whether this game is a Chess960 game */
|
|
47
|
+
_isChess960;
|
|
27
48
|
/**
|
|
28
49
|
* Creates a new PGNManager instance
|
|
29
50
|
* @param pgn - The PGN string to parse and manage
|
|
@@ -37,16 +58,24 @@ class PGNManager {
|
|
|
37
58
|
this.moveFen = new Map();
|
|
38
59
|
this.fenMove = new Map();
|
|
39
60
|
this.moveColor = new Map();
|
|
61
|
+
this._isChess960 = isChess960Game(this.game.headers);
|
|
40
62
|
this.dfOnGame(this.game);
|
|
41
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns whether this game is a Chess960 game
|
|
66
|
+
*/
|
|
67
|
+
get isChess960() {
|
|
68
|
+
return this._isChess960;
|
|
69
|
+
}
|
|
42
70
|
/**
|
|
43
71
|
* Initializes the game traversal starting from the initial position
|
|
44
72
|
* @param game - The parsed PGN game object
|
|
45
73
|
*/
|
|
46
74
|
dfOnGame = (game) => {
|
|
47
75
|
this.sortedMoves = [];
|
|
48
|
-
|
|
49
|
-
exports.FEN_START_POSITION
|
|
76
|
+
const startFen = game.headers?.find((h) => h.name.toUpperCase() === "FEN")?.value ||
|
|
77
|
+
exports.FEN_START_POSITION;
|
|
78
|
+
var chessGame = createChessInstance(startFen, game.headers);
|
|
50
79
|
for (let move of game.moves) {
|
|
51
80
|
this.dfsOnGame(move, game, chessGame);
|
|
52
81
|
}
|
|
@@ -63,16 +92,19 @@ class PGNManager {
|
|
|
63
92
|
if (move.ravs) {
|
|
64
93
|
for (let rav of move.ravs) {
|
|
65
94
|
this.ravParent.set(rav, move);
|
|
66
|
-
let newVarChessGame =
|
|
95
|
+
let newVarChessGame = createChessInstance(chessGame.fen(), this.game.headers);
|
|
67
96
|
for (let ravMove of rav.moves) {
|
|
68
97
|
this.dfsOnGame(ravMove, rav, newVarChessGame);
|
|
69
98
|
}
|
|
70
99
|
}
|
|
71
100
|
}
|
|
72
101
|
// move only after variations are processed
|
|
73
|
-
|
|
74
|
-
|
|
102
|
+
try {
|
|
103
|
+
chessGame.move(move.move);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
75
106
|
console.log("Invalid move: " + move.move);
|
|
107
|
+
}
|
|
76
108
|
this.moveFen.set(move, chessGame.fen());
|
|
77
109
|
this.fenMove.set(chessGame.fen(), move);
|
|
78
110
|
this.moveColor.set(move, chessGame.turn() === "w" ? "b" : "w");
|
|
@@ -280,18 +312,23 @@ class PGNManager {
|
|
|
280
312
|
parentRav = this.parsedPGN;
|
|
281
313
|
const fenHdr = this.headers.find((h) => h.name.toLowerCase() === "fen");
|
|
282
314
|
const startFen = fenHdr ? fenHdr.value : exports.FEN_START_POSITION;
|
|
283
|
-
chess =
|
|
315
|
+
chess = createChessInstance(startFen, this.game.headers);
|
|
284
316
|
}
|
|
285
317
|
else {
|
|
286
318
|
current = this.getMove(moveId);
|
|
287
319
|
if (!current)
|
|
288
320
|
throw new Error("Invalid moveId while pushing a new move!");
|
|
289
321
|
parentRav = this.moveParent.get(current) || this.parsedPGN;
|
|
290
|
-
chess =
|
|
322
|
+
chess = createChessInstance(this.getMoveFen(current), this.game.headers);
|
|
323
|
+
}
|
|
324
|
+
// 2) Play the move
|
|
325
|
+
let played;
|
|
326
|
+
try {
|
|
327
|
+
played = chess.move(newMove);
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
played = null;
|
|
291
331
|
}
|
|
292
|
-
// 2) Play the SAN move (strict → sloppy)
|
|
293
|
-
const played = chess.move(newMove, { sloppy: false }) ||
|
|
294
|
-
chess.move(newMove, { sloppy: true });
|
|
295
332
|
if (!played)
|
|
296
333
|
throw new Error("Invalid move");
|
|
297
334
|
const san = chess.history().slice(-1)[0];
|
|
@@ -316,7 +353,7 @@ class PGNManager {
|
|
|
316
353
|
comments: [],
|
|
317
354
|
};
|
|
318
355
|
// 4) Insert into structure & flag first‐of‐variation
|
|
319
|
-
let isFirstOfVariation =
|
|
356
|
+
let isFirstOfVariation = !current;
|
|
320
357
|
if (!current) {
|
|
321
358
|
// brand-new mainline => variation of first move if exists
|
|
322
359
|
const first = parentRav.moves[0];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pgn-manager",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Libraray built on top of chess.js and pgn-parser to load and process PGN files in typescript.",
|
|
5
5
|
"main": "dist/index",
|
|
6
6
|
"typings": "dist/index",
|
|
@@ -29,11 +29,10 @@
|
|
|
29
29
|
},
|
|
30
30
|
"homepage": "https://github.com/hadron43/pgn-manager#readme",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"
|
|
33
|
-
"
|
|
32
|
+
"pgn-parser": "2.1.0",
|
|
33
|
+
"void57-chess": "1.0.2"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@types/chess.js": "^0.11.2",
|
|
37
36
|
"@types/jest": "^30.0.0",
|
|
38
37
|
"@types/pgn-parser": "^2.1.0",
|
|
39
38
|
"jest": "^30.0.4",
|