chess-moments 0.13.0 → 0.14.1
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/functions/extras/index.js +9 -0
- package/functions/extras/moments-to-pgn.js +158 -0
- package/functions/helpers/get-brush-code.js +14 -0
- package/functions/helpers/get-brush-color.js +15 -0
- package/functions/helpers/index.js +7 -0
- package/functions/index.js +0 -6
- package/functions/shape.js +2 -2
- package/index.js +4 -6
- package/package.json +2 -2
- package/functions/brush.js +0 -9
- /package/functions/{get-next-moments.js → extras/get-next-moments.js} +0 -0
- /package/functions/{get-prev-moment.js → extras/get-prev-moment.js} +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
const fen = require('../fen');
|
|
2
|
+
const { getBrushCode } = require('../helpers');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Converts chess moments back to PGN format
|
|
6
|
+
* @param {Array} moments - Array of chess moment objects
|
|
7
|
+
* @returns {String} PGN string
|
|
8
|
+
*/
|
|
9
|
+
const momentsToPgn = (moments) => {
|
|
10
|
+
if (!Array.isArray(moments) || moments.length === 0) {
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let pgn = '';
|
|
15
|
+
let currentDepth = 1;
|
|
16
|
+
let variationStack = [];
|
|
17
|
+
|
|
18
|
+
// Check if we need to add FEN headers for non-standard starting position
|
|
19
|
+
const initialMoment = moments[0];
|
|
20
|
+
if (initialMoment && initialMoment.fen && initialMoment.fen !== fen.initial) {
|
|
21
|
+
pgn += `[SetUp "1"]\n`;
|
|
22
|
+
pgn += `[FEN "${initialMoment.fen}"]\n\n`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
for (let i = 0; i < moments.length; i++) {
|
|
26
|
+
const moment = moments[i];
|
|
27
|
+
const depth = moment.depth || 1;
|
|
28
|
+
|
|
29
|
+
// Handle moments without moves (initial position or variation breaks)
|
|
30
|
+
if (!moment.move) {
|
|
31
|
+
// If this is a variation marker (depth > 1) and not the initial position
|
|
32
|
+
if (depth > 1 && i > 0) {
|
|
33
|
+
// Check if we need to start a new variation at the same depth
|
|
34
|
+
if (depth === currentDepth) {
|
|
35
|
+
// Close current variation and start a new one at the same level
|
|
36
|
+
pgn += ') (';
|
|
37
|
+
} else if (depth > currentDepth) {
|
|
38
|
+
// Starting a new variation at a deeper level
|
|
39
|
+
variationStack.push(currentDepth);
|
|
40
|
+
pgn += ' (';
|
|
41
|
+
currentDepth = depth;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Add initial comment if present
|
|
46
|
+
if (moment.comment) {
|
|
47
|
+
pgn += `{${moment.comment}} `;
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Determine who made this move and what move number it is from the FEN
|
|
53
|
+
const fenParts = moment.fen.split(' ');
|
|
54
|
+
const activeColorAfterMove = fenParts[1]; // 'w' or 'b' - who moves next
|
|
55
|
+
const fullmoveNumber = parseInt(fenParts[5]);
|
|
56
|
+
|
|
57
|
+
// If black is to move after this move, then white made this move
|
|
58
|
+
const moveWasByWhite = activeColorAfterMove === 'b';
|
|
59
|
+
// For white moves, the move number is the fullmove number
|
|
60
|
+
// For black moves, the move number is fullmove number - 1 (since fullmove increments after black's move)
|
|
61
|
+
const moveNumber = moveWasByWhite ? fullmoveNumber : fullmoveNumber - 1;
|
|
62
|
+
|
|
63
|
+
// Handle depth changes (variations)
|
|
64
|
+
if (depth > currentDepth) {
|
|
65
|
+
// Starting a new variation
|
|
66
|
+
variationStack.push(currentDepth);
|
|
67
|
+
pgn += ' (';
|
|
68
|
+
currentDepth = depth;
|
|
69
|
+
} else if (depth < currentDepth) {
|
|
70
|
+
// Ending variation(s) - close as many as needed to get to the right depth
|
|
71
|
+
while (currentDepth > depth) {
|
|
72
|
+
variationStack.pop();
|
|
73
|
+
pgn += ')';
|
|
74
|
+
currentDepth--;
|
|
75
|
+
}
|
|
76
|
+
if (pgn.endsWith(')')) {
|
|
77
|
+
pgn += ' ';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Add move number for white moves or when starting a variation
|
|
82
|
+
if (moveWasByWhite || (depth > 1 && pgn.endsWith('('))) {
|
|
83
|
+
pgn += `${moveNumber}.`;
|
|
84
|
+
if (!moveWasByWhite) {
|
|
85
|
+
pgn += '..';
|
|
86
|
+
}
|
|
87
|
+
pgn += ' ';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Add the move
|
|
91
|
+
pgn += moment.move;
|
|
92
|
+
|
|
93
|
+
// Add comment if present
|
|
94
|
+
if (moment.comment) {
|
|
95
|
+
pgn += ` {${moment.comment}}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Add shapes if present
|
|
99
|
+
if (moment.shapes && moment.shapes.length > 0) {
|
|
100
|
+
let shapesComment = '';
|
|
101
|
+
const squareHighlights = moment.shapes.filter(
|
|
102
|
+
(s) => !s.dest || s.dest === ']'
|
|
103
|
+
);
|
|
104
|
+
const arrows = moment.shapes.filter((s) => s.dest && s.dest !== ']');
|
|
105
|
+
|
|
106
|
+
if (squareHighlights.length > 0) {
|
|
107
|
+
const coloredSquares = squareHighlights
|
|
108
|
+
.map((s) => {
|
|
109
|
+
const colorCode = getBrushCode(s.brush);
|
|
110
|
+
return `${colorCode}${s.orig}`;
|
|
111
|
+
})
|
|
112
|
+
.join(',');
|
|
113
|
+
shapesComment += `[%csl ${coloredSquares}]`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (arrows.length > 0) {
|
|
117
|
+
const coloredArrows = arrows
|
|
118
|
+
.map((s) => {
|
|
119
|
+
const colorCode = getBrushCode(s.brush);
|
|
120
|
+
return `${colorCode}${s.orig}${s.dest}`;
|
|
121
|
+
})
|
|
122
|
+
.join(',');
|
|
123
|
+
if (shapesComment) shapesComment += ' ';
|
|
124
|
+
shapesComment += `[%cal ${coloredArrows}]`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (shapesComment) {
|
|
128
|
+
if (moment.comment) {
|
|
129
|
+
// If there's already a comment, add shapes to it
|
|
130
|
+
pgn = pgn.replace(/\{([^}]*)\}$/, `{$1 ${shapesComment}}`);
|
|
131
|
+
} else {
|
|
132
|
+
pgn += ` {${shapesComment}}`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Add space after move if not the last move
|
|
138
|
+
if (i < moments.length - 1) {
|
|
139
|
+
const nextMoment = moments[i + 1];
|
|
140
|
+
if (nextMoment && nextMoment.move) {
|
|
141
|
+
pgn += ' ';
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Close any remaining variations
|
|
147
|
+
while (variationStack.length > 0) {
|
|
148
|
+
variationStack.pop();
|
|
149
|
+
pgn += ')';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Add default result
|
|
153
|
+
pgn += ' *';
|
|
154
|
+
|
|
155
|
+
return pgn.trim();
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
module.exports = momentsToPgn;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert brush color name to PGN color code
|
|
3
|
+
*/
|
|
4
|
+
const getBrushCode = (brush) => {
|
|
5
|
+
const brushCodes = {
|
|
6
|
+
green: 'G',
|
|
7
|
+
red: 'R',
|
|
8
|
+
blue: 'B',
|
|
9
|
+
yellow: 'Y',
|
|
10
|
+
};
|
|
11
|
+
return brushCodes[brush] || 'G';
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
module.exports = getBrushCode;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert PGN color code to brush color name
|
|
3
|
+
*/
|
|
4
|
+
const getBrushColor = (letter) => {
|
|
5
|
+
const brushes = {
|
|
6
|
+
R: 'red',
|
|
7
|
+
Y: 'yellow',
|
|
8
|
+
G: 'green',
|
|
9
|
+
B: 'blue',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
return brushes[letter] || 'green';
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
module.exports = getBrushColor;
|
package/functions/index.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
const brush = require('./brush');
|
|
2
1
|
const fen = require('./fen');
|
|
3
2
|
const flat = require('./flat');
|
|
4
|
-
const getNextMoments = require('./get-next-moments');
|
|
5
|
-
const getPrevMoment = require('./get-prev-moment');
|
|
6
3
|
const lines = require('./lines');
|
|
7
4
|
const moment = require('./moment');
|
|
8
5
|
const parser = require('./parser');
|
|
@@ -15,11 +12,8 @@ const train = require('./train');
|
|
|
15
12
|
const tree = require('./tree');
|
|
16
13
|
|
|
17
14
|
module.exports = {
|
|
18
|
-
brush,
|
|
19
15
|
fen,
|
|
20
16
|
flat,
|
|
21
|
-
getNextMoments,
|
|
22
|
-
getPrevMoment,
|
|
23
17
|
lines,
|
|
24
18
|
moment,
|
|
25
19
|
parser,
|
package/functions/shape.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const { getBrushColor } = require('./helpers');
|
|
2
2
|
|
|
3
3
|
module.exports = (comment) => {
|
|
4
4
|
try {
|
|
@@ -16,7 +16,7 @@ module.exports = (comment) => {
|
|
|
16
16
|
|
|
17
17
|
for (const target of shapes.join('').split(',')) {
|
|
18
18
|
draw.push({
|
|
19
|
-
brush:
|
|
19
|
+
brush: getBrushColor(target.substr(0, 1)),
|
|
20
20
|
orig: target.substr(1, 2),
|
|
21
21
|
dest: target.substr(3, 2),
|
|
22
22
|
});
|
package/index.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
+
const { fen, pgn, flat, train, tree } = require('./functions');
|
|
1
2
|
const {
|
|
2
|
-
fen,
|
|
3
|
-
pgn,
|
|
4
|
-
flat,
|
|
5
|
-
train,
|
|
6
|
-
tree,
|
|
7
3
|
getNextMoments,
|
|
8
4
|
getPrevMoment,
|
|
9
|
-
|
|
5
|
+
momentsToPgn,
|
|
6
|
+
} = require('./functions/extras');
|
|
10
7
|
|
|
11
8
|
module.exports = {
|
|
12
9
|
fen,
|
|
@@ -16,4 +13,5 @@ module.exports = {
|
|
|
16
13
|
tree,
|
|
17
14
|
getNextMoments,
|
|
18
15
|
getPrevMoment,
|
|
16
|
+
momentsToPgn,
|
|
19
17
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chess-moments",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "PGN parser that transforms PGN files into chess \"moments\"",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"index.js",
|
|
8
8
|
"chess.js",
|
|
9
|
-
"functions
|
|
9
|
+
"functions/**/*.js"
|
|
10
10
|
],
|
|
11
11
|
"scripts": {
|
|
12
12
|
"test": "mocha",
|
package/functions/brush.js
DELETED
|
File without changes
|
|
File without changes
|