chess-moments 1.4.8 → 1.6.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.
@@ -0,0 +1,22 @@
1
+ const glyphs = {
2
+ $7: '□', // Only move
3
+ $22: '⨀', // Zugzwang
4
+ $10: '=', // Equal position
5
+ $13: '∞', // Unclear position
6
+ $14: '⩲', // White is slightly better
7
+ $15: '⩱', // Black is slightly better
8
+ $16: '±', // White is better
9
+ $17: '∓', // Black is better
10
+ $18: '+−', // White is winning
11
+ $19: '-+', // Black is winning
12
+ $146: 'N', // Novelty
13
+ $32: '↑↑', // Development
14
+ $36: '↑', // Initiative
15
+ $40: '→', // Attack
16
+ $132: '⇆', // Counterplay
17
+ $138: '⊕', // Time trouble
18
+ $44: '=∞', // With compensation
19
+ $140: '∆', // With the idea
20
+ };
21
+
22
+ module.exports = glyphs;
@@ -1,7 +1,17 @@
1
1
  const prettify = require('./prettify');
2
2
  const shape = require('./shape');
3
3
 
4
- module.exports = ({ depth, move, fen, comment, suffix, from, to }) => {
4
+ module.exports = ({
5
+ depth,
6
+ move,
7
+ fen,
8
+ comment,
9
+ suffix,
10
+ glyph,
11
+ from,
12
+ to,
13
+ headers,
14
+ }) => {
5
15
  const moment = { depth, fen };
6
16
  if (move) {
7
17
  moment.move = move;
@@ -23,6 +33,12 @@ module.exports = ({ depth, move, fen, comment, suffix, from, to }) => {
23
33
  if (suffix) {
24
34
  moment.suffix = suffix;
25
35
  }
36
+ if (glyph) {
37
+ moment.glyph = glyph;
38
+ }
39
+ if (headers) {
40
+ moment.headers = headers;
41
+ }
26
42
 
27
43
  return moment;
28
44
  };
@@ -21,9 +21,46 @@ const momentsToPgn = (moments) => {
21
21
  let currentDepth = 1;
22
22
  let variationStack = [];
23
23
 
24
- // Add FEN headers
25
- pgn += `[SetUp "1"]\n`;
26
- pgn += `[FEN "${moments[0].fen}"]\n\n`;
24
+ const headers = moments[0].headers;
25
+ const standardHeaders = [
26
+ 'Event',
27
+ 'Site',
28
+ 'Date',
29
+ 'Round',
30
+ 'White',
31
+ 'Black',
32
+ 'Result',
33
+ ];
34
+
35
+ if (headers) {
36
+ // Add standard headers (excluding placeholder values)
37
+ for (const key of standardHeaders) {
38
+ if (
39
+ headers[key] &&
40
+ headers[key] !== '?' &&
41
+ headers[key] !== '????.??.??'
42
+ ) {
43
+ pgn += `[${key} "${headers[key]}"]\n`;
44
+ }
45
+ }
46
+
47
+ // Add custom headers
48
+ for (const key in headers) {
49
+ if (!standardHeaders.includes(key) && key !== 'FEN' && key !== 'SetUp') {
50
+ pgn += `[${key} "${headers[key]}"]\n`;
51
+ }
52
+ }
53
+ }
54
+
55
+ const fenString = headers?.FEN || moments[0].fen;
56
+
57
+ if (fenString !== fen.initial) {
58
+ const setUp = headers?.SetUp || '1';
59
+ pgn += `[SetUp "${setUp}"]\n`;
60
+ pgn += `[FEN "${fenString}"]\n`;
61
+ }
62
+
63
+ pgn += '\n';
27
64
 
28
65
  for (let i = 0; i < moments.length; i++) {
29
66
  const moment = moments[i];
@@ -105,6 +142,11 @@ const momentsToPgn = (moments) => {
105
142
  pgn += moment.suffix;
106
143
  }
107
144
 
145
+ // Add glyph if present (keep as NAG code from original PGN)
146
+ if (moment.glyph) {
147
+ pgn += ` ${moment.glyph}`;
148
+ }
149
+
108
150
  // Add comment if present
109
151
  if (moment.comment) {
110
152
  pgn += ` {${moment.comment}}`;
@@ -164,8 +206,8 @@ const momentsToPgn = (moments) => {
164
206
  pgn += ')';
165
207
  }
166
208
 
167
- // Add default result
168
- pgn += ' *';
209
+ // Add result from headers if available, otherwise default to *
210
+ pgn += ` ${headers?.Result || '*'}`;
169
211
 
170
212
  return pgn.trim();
171
213
  };
@@ -5,7 +5,11 @@ const pgn = require('./pgn');
5
5
  const split = require('./split');
6
6
 
7
7
  const make = (sloppyPgn) => {
8
- const normalizedPgn = pgn.normalize(sloppyPgn);
8
+ let normalizedPgn = pgn.normalize(sloppyPgn);
9
+ // when PGN is empty, create a default one with initial FEN
10
+ if (!normalizedPgn) {
11
+ normalizedPgn = pgn.build([], fen.initial);
12
+ }
9
13
 
10
14
  // load PGN and check headers for existing FEN
11
15
  const chess = new Chess(); // can throw if PGN is invalid
@@ -18,7 +22,7 @@ const make = (sloppyPgn) => {
18
22
  };
19
23
 
20
24
  const history = new Map();
21
- const variations = split(normalizedPgn).map(({ moves, depth }) => {
25
+ const variations = split(normalizedPgn).map(({ moves, depth }, index) => {
22
26
  // find previous FEN
23
27
  if (history.get(store.depth)) {
24
28
  store.fen = fen.previous(history, moves, depth, store.depth);
@@ -26,7 +30,13 @@ const make = (sloppyPgn) => {
26
30
  store.depth = depth;
27
31
 
28
32
  // parse current moves with the computed FEN
29
- const moments = parser(moves, store.fen, depth);
33
+ // only pass headers to the first move
34
+ const moments = parser(
35
+ moves,
36
+ store.fen,
37
+ depth,
38
+ index === 0 ? headers : null
39
+ );
30
40
 
31
41
  // set history for the current depth
32
42
  history.set(depth, fen.history(moments, history, depth));
@@ -1,9 +1,11 @@
1
1
  const { Chess } = require('chess.js');
2
+ const { invert } = require('lodash');
2
3
  const { initial } = require('./fen');
3
4
  const pgn = require('./pgn');
4
5
  const moment = require('./moment');
6
+ const glyphs = require('../constants/glyphs');
5
7
 
6
- module.exports = (moves, fen = initial, depth = 1) => {
8
+ module.exports = (moves, fen = initial, depth = 1, headers = null) => {
7
9
  const chess = new Chess();
8
10
  chess.loadPgn(pgn.build(moves, fen)); // can throw if PGN is invalid
9
11
 
@@ -17,6 +19,7 @@ module.exports = (moves, fen = initial, depth = 1) => {
17
19
  depth,
18
20
  comment: chess.getComment(),
19
21
  fen: chess.fen(),
22
+ headers,
20
23
  });
21
24
 
22
25
  const moments = history.map((item) => {
@@ -29,13 +32,14 @@ module.exports = (moves, fen = initial, depth = 1) => {
29
32
  to: item.to,
30
33
  comment: chess.getComment(),
31
34
  suffix: chess.getSuffixAnnotation(),
35
+ glyph: invert(glyphs)[chess.getGlyph()],
32
36
  fen: chess.fen(),
33
37
  });
34
38
  });
35
39
 
36
40
  // finally, add the first chess "moment" when needed
37
- const headers = chess.getHeaders();
38
- if (headers.FEN || fen === initial || first.comment || first.shapes) {
41
+ const pgnHeaders = chess.getHeaders();
42
+ if (pgnHeaders.FEN || fen === initial || first.comment || first.shapes) {
39
43
  moments.unshift(first);
40
44
  }
41
45
 
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "chess-moments",
3
- "version": "1.4.8",
3
+ "version": "1.6.0",
4
4
  "description": "PGN parser that transforms PGN files into chess \"moments\"",
5
5
  "main": "index.js",
6
6
  "files": [
7
7
  "index.js",
8
8
  "chess.js",
9
- "functions/**/*.js"
9
+ "functions/**/*.js",
10
+ "constants/**/*.js"
10
11
  ],
11
12
  "scripts": {
12
13
  "test": "mocha",
@@ -24,7 +25,7 @@
24
25
  ],
25
26
  "license": "MIT",
26
27
  "dependencies": {
27
- "chess.js": "github:jhlywa/chess.js#master"
28
+ "chess.js": "github:brobert1/chess.js#master"
28
29
  },
29
30
  "devDependencies": {
30
31
  "chai": "^4.3.7",