cm-chess 2.3.4 → 2.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cm-chess",
3
- "version": "2.3.4",
3
+ "version": "2.4.0",
4
4
  "description": "Like chess.js, but in ES6 and can handle variations (tree-structured move history)",
5
5
  "main": "./src/cm-chess/Chess.js",
6
6
  "scripts": {
@@ -24,11 +24,11 @@
24
24
  },
25
25
  "homepage": "https://github.com/shaack/cm-chess#readme",
26
26
  "dependencies": {
27
- "chess.mjs": "^1.2.0",
27
+ "chess.mjs": "^1.3.1",
28
28
  "cm-pgn": "^2.1.9",
29
29
  "modrator": "^1.2.1"
30
30
  },
31
31
  "devDependencies": {
32
- "teevi": "^2.1.11"
32
+ "teevi": "^2.2.2"
33
33
  }
34
34
  }
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import {Pgn} from "../../lib/cm-pgn/Pgn.js"
7
7
  import {TAGS} from "../../lib/cm-pgn/Header.js"
8
- import {Chess as ChessJs} from "../../lib/chess.mjs/Chess.js"
8
+ import {Chess as ChessJs, SQUARES} from "../../lib/chess.mjs/Chess.js"
9
9
 
10
10
  export const PIECES = {
11
11
  p: {name: "pawn", value: 1},
@@ -26,6 +26,21 @@ export const FEN = {
26
26
  start: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
27
27
  }
28
28
 
29
+ export const EVENT_TYPE = {
30
+ illegalMove: "illegalMove",
31
+ legalMove: "legalMove",
32
+ undoMove: "undoMove",
33
+ initialized: "initialized"
34
+ }
35
+
36
+ function publishEvent(observers, eventType, data = {}) {
37
+ for (const observer of observers) {
38
+ setTimeout(() => {
39
+ observer(eventType, data)
40
+ })
41
+ }
42
+ }
43
+
29
44
  /**
30
45
  * Like chess.js, but handles variations and is written in ES5
31
46
  * Uses chess.js for validation and cm-pgn for the history and PGN header
@@ -33,12 +48,13 @@ export const FEN = {
33
48
  export class Chess {
34
49
 
35
50
  constructor(fenOrProps = FEN.start) {
36
- if(typeof fenOrProps === "string") {
51
+ this.observers = []
52
+ if (typeof fenOrProps === "string") {
37
53
  this.load(fenOrProps)
38
54
  } else {
39
- if(fenOrProps.fen) {
55
+ if (fenOrProps.fen) {
40
56
  this.load(fenOrProps.fen)
41
- } else if(fenOrProps.pgn) {
57
+ } else if (fenOrProps.pgn) {
42
58
  this.loadPgn(fenOrProps.pgn)
43
59
  } else {
44
60
  this.load(FEN.start)
@@ -49,14 +65,11 @@ export class Chess {
49
65
  /**
50
66
  * @returns {string} the FEN of the last move, or the setUpFen(), if no move was made.
51
67
  */
52
- fen() {
53
- const lastMove = this.lastMove()
54
- if (lastMove) {
55
- return lastMove.fen
56
- } else if (this.setUpFen()) {
57
- return this.setUpFen()
68
+ fen(move = this.lastMove()) {
69
+ if (move) {
70
+ return move.fen
58
71
  } else {
59
- return FEN.start
72
+ return this.setUpFen()
60
73
  }
61
74
  }
62
75
 
@@ -169,6 +182,7 @@ export class Chess {
169
182
  } else {
170
183
  throw Error("Invalid fen " + fen)
171
184
  }
185
+ publishEvent(this.observers, EVENT_TYPE.initialized, {fen: fen})
172
186
  }
173
187
 
174
188
  /**
@@ -178,6 +192,7 @@ export class Chess {
178
192
  */
179
193
  loadPgn(pgn) {
180
194
  this.pgn = new Pgn(pgn)
195
+ publishEvent(this.observers, EVENT_TYPE.initialized, {pgn: pgn})
181
196
  }
182
197
 
183
198
  /**
@@ -189,12 +204,40 @@ export class Chess {
189
204
  */
190
205
  move(move, previousMove = undefined, sloppy = true) {
191
206
  try {
192
- return this.pgn.history.addMove(move, previousMove, sloppy)
207
+ const moveResult = this.pgn.history.addMove(move, previousMove, sloppy)
208
+ publishEvent(this.observers, EVENT_TYPE.legalMove, {move: move, previousMove: previousMove})
209
+ return moveResult
193
210
  } catch (e) {
211
+ publishEvent(this.observers, EVENT_TYPE.illegalMove, {move: move, previousMove: previousMove})
194
212
  return null
195
213
  }
196
214
  }
197
215
 
216
+ /**
217
+ * Return all valid moves
218
+ * @param options {{ square: "e2", piece: "n", verbose: true }}
219
+ * Fields with { verbose: true }
220
+ * - `color` indicates the color of the moving piece (w or b).
221
+ * - `from` and `to` fields are from and to squares in algebraic notation.
222
+ * - `piece`, `captured`, and `promotion` fields contain the lowercase representation of the applicable piece (pnbrqk). The captured and promotion fields are only present when the move is a valid capture or promotion.
223
+ * - `san` is the move in Standard Algebraic Notation (SAN).
224
+ * - `flags` field contains one or more of the string values:
225
+ * n - a non-capture
226
+ * b - a pawn push of two squares
227
+ * e - an en passant capture
228
+ * c - a standard capture
229
+ * p - a promotion
230
+ * k - kingside castling
231
+ * q - queenside castling
232
+ * A flags value of pc would mean that a pawn captured a piece on the 8th rank and promoted.
233
+ * @param previousMove
234
+ * @returns {{}}
235
+ */
236
+ moves(options = undefined, previousMove = this.lastMove()) {
237
+ const chessJs = new ChessJs(this.fen(previousMove))
238
+ return chessJs.moves(options)
239
+ }
240
+
198
241
  /**
199
242
  * Don't make a move, just validate, if it would be a correct move
200
243
  * @param move
@@ -231,7 +274,7 @@ export class Chess {
231
274
  const chessJs = move ? new ChessJs(move.fen) : new ChessJs()
232
275
  let result = []
233
276
  for (let i = 0; i < 64; i++) {
234
- const square = chessJs.SQUARES[i]
277
+ const square = SQUARES[i]
235
278
  const piece = chessJs.get(square)
236
279
  if (piece) {
237
280
  piece.square = square
@@ -277,6 +320,7 @@ export class Chess {
277
320
  return element.ply === move.ply
278
321
  })
279
322
  move.variation = move.variation.splice(index)
323
+ publishEvent(this.observers, EVENT_TYPE.undoMove, {move: move})
280
324
  }
281
325
 
282
326
  plyCount() {
@@ -284,12 +328,14 @@ export class Chess {
284
328
  }
285
329
 
286
330
  fenOfPly(plyNumber) {
287
- if(plyNumber > 0) {
331
+ if (plyNumber > 0) {
288
332
  return this.history()[plyNumber - 1].fen
289
333
  } else {
290
334
  return this.setUpFen()
291
335
  }
292
336
  }
293
337
 
294
-
338
+ addObserver(callback) {
339
+ this.observers.push(callback)
340
+ }
295
341
  }
package/test/TestChess.js CHANGED
@@ -217,7 +217,31 @@ describe("Chess", function () {
217
217
  assert.notEqual(chess.validateMove("Nf3"), null)
218
218
  assert.equal(chess.validateMove("xyz"), null)
219
219
  assert.equal(chess.validateMove("e6"), null)
220
+ })
220
221
 
222
+ it("should publish events", function() {
223
+ return new Promise((resolve, reject) => {
224
+ const chess = new Chess()
225
+ chess.addObserver((event, data) => {
226
+ if(event === "legalMove" && data.move === "e4") {
227
+ resolve()
228
+ } else {
229
+ reject("error event")
230
+ }
231
+ })
232
+ chess.move("e4")
233
+ })
234
+ })
235
+
236
+ it("should provide valid moves", function() {
237
+ const chess = new Chess()
238
+ assert.equal(chess.moves().length, 20)
239
+ chess.move("Nc3")
240
+ assert.equal(chess.moves().length, 20)
241
+ chess.move("e5")
242
+ assert.equal(chess.moves().length, 22)
243
+ assert.equal(JSON.stringify(chess.moves({ square: "e2"})), '["e3","e4"]')
244
+ assert.equal(JSON.stringify(chess.moves({ piece: "n" })), '["Na4","Nb5","Nd5","Ne4","Nb1","Nf3","Nh3"]')
221
245
  })
222
246
 
223
247
  })