chess-moments 1.0.0 → 1.1.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,66 @@
1
+ const { flatten } = require('lodash');
2
+ const { insertMomentIntoTree } = require('../helpers');
3
+
4
+ const addMomentToTree = (tree, newMoment) => {
5
+ if (!newMoment || !newMoment.san || !newMoment.before) {
6
+ return tree;
7
+ }
8
+
9
+ const flat = flatten(tree);
10
+ // Check if moment FEN already exists in the tree
11
+ if (flat.some((moment) => moment.fen === newMoment.after)) {
12
+ return tree;
13
+ }
14
+
15
+ // Find the appropriate position to insert the moment
16
+ let point = null;
17
+
18
+ // Look for the position where this moment should be inserted
19
+ // by finding the moment with matching "before" FEN at any depth
20
+ for (let lineIndex = 0; lineIndex < tree.length; lineIndex++) {
21
+ const line = tree[lineIndex];
22
+
23
+ for (let momentIndex = 0; momentIndex < line.length; momentIndex++) {
24
+ const existingMoment = line[momentIndex];
25
+
26
+ // If we find a moment with the same "before" FEN, this is where we branch
27
+ if (existingMoment.fen === newMoment.before) {
28
+ // Check if there's already a move after this position in the same line
29
+ const nextMomentInLine = line[momentIndex + 1];
30
+
31
+ if (nextMomentInLine && nextMomentInLine.move) {
32
+ // There's already a move after this position, so create a new sideline
33
+ point = {
34
+ type: 'newLine',
35
+ afterLineIndex: lineIndex,
36
+ branchMomentIndex: momentIndex,
37
+ };
38
+ } else {
39
+ // No move after this position, so continue in the same line
40
+ point = { type: 'sameLine', lineIndex, momentIndex: momentIndex + 1 };
41
+ }
42
+ break;
43
+ }
44
+ }
45
+
46
+ // If we found an insertion point, no need to continue searching
47
+ if (point) {
48
+ break;
49
+ }
50
+ }
51
+
52
+ // Insert the moment into the tree
53
+ const newTree = insertMomentIntoTree(tree, point, newMoment);
54
+
55
+ // Reindex all moments
56
+ let globalIndex = 0;
57
+ for (const line of newTree) {
58
+ for (const moment of line) {
59
+ moment.index = globalIndex++;
60
+ }
61
+ }
62
+
63
+ return newTree;
64
+ };
65
+
66
+ module.exports = addMomentToTree;
@@ -1,9 +1,11 @@
1
+ const addMomentToTree = require('./add-moment-to-tree');
1
2
  const getNextMoments = require('./get-next-moments');
2
3
  const getPrevMoment = require('./get-prev-moment');
3
4
  const momentsToPgn = require('./moments-to-pgn');
4
5
  const moveTrainer = require('./move-trainer');
5
6
 
6
7
  module.exports = {
8
+ addMomentToTree,
7
9
  getNextMoments,
8
10
  getPrevMoment,
9
11
  momentsToPgn,
@@ -1,9 +1,13 @@
1
1
  const getBrushCode = require('./get-brush-code');
2
2
  const getBrushColor = require('./get-brush-color');
3
3
  const getMoveNumber = require('./get-move-number');
4
+ const insertMomentIntoTree = require('./insert-moment-into-tree');
5
+ const prepareMoment = require('./prepare-moment');
4
6
 
5
7
  module.exports = {
6
8
  getBrushCode,
7
9
  getBrushColor,
8
10
  getMoveNumber,
11
+ insertMomentIntoTree,
12
+ prepareMoment,
9
13
  };
@@ -0,0 +1,97 @@
1
+ const prepareMoment = require('./prepare-moment');
2
+
3
+ /**
4
+ * Inserts a new moment into the tree at the specified point.
5
+ * This function handles both inserting into existing lines and creating new sidelines.
6
+ * @param {Array} tree - The current tree structure.
7
+ * @param {Object} point - The point in the tree where the moment will be inserted.
8
+ * @param {Object} newMoment - The new moment to be inserted, containing properties like san, fen, from, to.
9
+ * @returns {Array} Updated tree with the new moment inserted
10
+ */
11
+ const insertMomentIntoTree = (tree, point, newMoment) => {
12
+ // Prepare the moment to be inserted with only the properties that match normal moments
13
+ const momentToInsert = prepareMoment(tree, point, newMoment);
14
+
15
+ // If no matching position found, always create a new line
16
+ if (!point) {
17
+ tree.push([momentToInsert]);
18
+ return tree;
19
+ }
20
+
21
+ // Insert into existing line
22
+ if (point.type === 'sameLine') {
23
+ tree[point.lineIndex].splice(point.momentIndex, 0, momentToInsert);
24
+ return tree;
25
+ }
26
+
27
+ // Create new sideline
28
+ if (point.type === 'newLine') {
29
+ // Check if we need to split the mainline to create proper structure
30
+ const originalMainline = tree[point.afterLineIndex];
31
+ const branchMomentIndex = point.branchMomentIndex;
32
+
33
+ // Find where to split: look for moves that come after the branch point sequence
34
+ let splitIndex = branchMomentIndex + 1;
35
+
36
+ // Skip the immediate next move(s) that continue from the branch point
37
+ // and find moves that should be in a separate continuation
38
+ while (splitIndex < originalMainline.length) {
39
+ const currentMoment = originalMainline[splitIndex];
40
+ if (currentMoment.move) {
41
+ // For now, assume the next move continues the sequence
42
+ // and the move after that should be separated
43
+ let nextMoveIndex = splitIndex + 1;
44
+ while (
45
+ nextMoveIndex < originalMainline.length &&
46
+ !originalMainline[nextMoveIndex].move
47
+ ) {
48
+ nextMoveIndex++;
49
+ }
50
+
51
+ if (nextMoveIndex < originalMainline.length) {
52
+ // There's another move after this one, split here for continuation
53
+ splitIndex = nextMoveIndex;
54
+ break;
55
+ }
56
+ }
57
+ splitIndex++;
58
+ }
59
+
60
+ if (splitIndex < originalMainline.length) {
61
+ // Split the mainline
62
+ const beforeSplit = originalMainline.slice(0, splitIndex);
63
+ const afterSplit = originalMainline.slice(splitIndex);
64
+
65
+ // Update the original mainline to keep the sequence up to the split
66
+ tree[point.afterLineIndex] = beforeSplit;
67
+
68
+ // Insert the sideline after the mainline
69
+ const sidelinePositionMarker = {
70
+ depth: momentToInsert.depth,
71
+ fen: newMoment.before,
72
+ };
73
+ const sidelineLine = [sidelinePositionMarker, momentToInsert];
74
+ tree.splice(point.afterLineIndex + 1, 0, sidelineLine);
75
+
76
+ // Insert the continuation line after the sideline
77
+ const continuationPositionMarker = {
78
+ depth: beforeSplit[0]?.depth || 1, // Use the depth of the line being continued
79
+ fen: beforeSplit[beforeSplit.length - 1].fen,
80
+ };
81
+ const continuationLine = [continuationPositionMarker, ...afterSplit];
82
+ tree.splice(point.afterLineIndex + 2, 0, continuationLine);
83
+ } else {
84
+ // No continuation needed, just add the sideline
85
+ const sidelinePositionMarker = {
86
+ depth: momentToInsert.depth,
87
+ fen: newMoment.before,
88
+ };
89
+ const sidelineLine = [sidelinePositionMarker, momentToInsert];
90
+ tree.splice(point.afterLineIndex + 1, 0, sidelineLine);
91
+ }
92
+ }
93
+
94
+ return tree;
95
+ };
96
+
97
+ module.exports = insertMomentIntoTree;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Prepares a moment object for insertion into the tree.
3
+ * It ensures the moment has the correct properties and depth based on its position.
4
+ * @param {Array} tree - The current tree structure.
5
+ * @param {Object} point - The point in the tree where the moment will be inserted.
6
+ * @param {Object} newMoment - The new moment to be inserted, containing properties like san, fen, from, to.
7
+ * @returns {Object} Prepared moment object with depth and necessary properties
8
+ */
9
+ const prepareMoment = (tree, point, newMoment) => {
10
+ let targetDepth = newMoment.depth || 1;
11
+
12
+ if (point) {
13
+ if (point.type === 'sameLine' && point.lineIndex !== undefined) {
14
+ // Use the depth of the line we're inserting into
15
+ targetDepth = tree[point.lineIndex]?.[0]?.depth || 1;
16
+ } else if (point.type === 'newLine') {
17
+ // For new sidelines, increment the depth from where we're branching
18
+ const branchingLine = tree[point.afterLineIndex];
19
+ const branchingMoment = branchingLine?.[point.branchMomentIndex];
20
+ const branchingDepth = branchingMoment?.depth || 1;
21
+ targetDepth = branchingDepth + 1;
22
+ }
23
+ }
24
+
25
+ return {
26
+ depth: targetDepth,
27
+ fen: newMoment.after,
28
+ move: newMoment.san,
29
+ from: newMoment.from,
30
+ to: newMoment.to,
31
+ };
32
+ };
33
+
34
+ module.exports = prepareMoment;
package/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const { fen, pgn, flat, tree, mainline } = require('./functions');
2
2
  const {
3
+ addMomentToTree,
3
4
  getNextMoments,
4
5
  getPrevMoment,
5
6
  momentsToPgn,
@@ -12,6 +13,7 @@ module.exports = {
12
13
  flat,
13
14
  tree,
14
15
  mainline,
16
+ addMomentToTree,
15
17
  getNextMoments,
16
18
  getPrevMoment,
17
19
  momentsToPgn,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chess-moments",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "PGN parser that transforms PGN files into chess \"moments\"",
5
5
  "main": "index.js",
6
6
  "files": [