cm-chess 3.5.0 → 3.5.2

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/LICENSE CHANGED
@@ -1,7 +1,5 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020 Stefan Haack
4
-
5
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
4
  of this software and associated documentation files (the "Software"), to deal
7
5
  in the Software without restriction, including without limitation the rights
package/README.md CHANGED
@@ -13,7 +13,7 @@ PGN header values, Nags and Comments.
13
13
  - It has a similar API to chess.js
14
14
  - It can handle history variations
15
15
  - It can add Nags, Comments and Annotations
16
- - It is used by the 7,000 users of [chessmail](https://www.chessmail.de) (it works)
16
+ - It is a core component of my online chess server [chessmail.de](https://www.chessmail.de) (it works)
17
17
 
18
18
  ## API
19
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cm-chess",
3
- "version": "3.5.0",
3
+ "version": "3.5.2",
4
4
  "description": "It's like chess.js, but in ES6 and can handle variations (tree-structured move history)",
5
5
  "main": "./src/Chess.js",
6
6
  "type": "module",
@@ -24,8 +24,8 @@
24
24
  },
25
25
  "homepage": "https://github.com/shaack/cm-chess#readme",
26
26
  "dependencies": {
27
- "chess.mjs": "^1.4.0",
28
- "cm-pgn": "3.2.1"
27
+ "chess.mjs": "^2.2.3",
28
+ "cm-pgn": "4.0.6"
29
29
  },
30
30
  "devDependencies": {
31
31
  "teevi": "^2.2.4"
package/src/Chess.js CHANGED
@@ -47,17 +47,29 @@ function publishEvent(observers, event) {
47
47
  */
48
48
  export class Chess {
49
49
 
50
- constructor(fenOrProps = FEN.start) {
50
+ /**
51
+ * @param props {object}
52
+ * - an object with these properties:
53
+ * fen: a FEN string
54
+ * pgn: a PGN
55
+ * chess960: true, if chess960 are used
56
+ * sloppy: true, if sloppy parsing is allowed
57
+ */
58
+ constructor(props = {}) {
51
59
  this.observers = []
52
60
  this.props = {
53
61
  fen: undefined, // use a fen or a pgn with setUpFen
54
62
  pgn: undefined,
55
- sloppy: true // sloppy parsing allows small mistakes in SAN
63
+ chess960: false,
64
+ sloppy: true, // sloppy parsing allows small mistakes in SAN
65
+ ...props
66
+ }
67
+ if (typeof props === "string") {
68
+ console.warn("directly passing a FEN is deprecated, use `{fen: \"" + props + "\"}`")
69
+ this.props.fen = props
56
70
  }
57
- if (typeof fenOrProps === "string") {
58
- this.props.fen = fenOrProps
59
- } else if (typeof fenOrProps === "object") {
60
- Object.assign(this.props, fenOrProps)
71
+ if (!this.props.fen && !this.props.pgn) {
72
+ this.props.fen = FEN.start
61
73
  }
62
74
  if (this.props.fen) {
63
75
  this.load(this.props.fen)
@@ -105,7 +117,7 @@ export class Chess {
105
117
  if (move) {
106
118
  return move.gameOver
107
119
  } else {
108
- return new ChessJs(this.fen()).game_over()
120
+ return new ChessJs(this.fen(), {chess960: this.props.chess960}).game_over()
109
121
  }
110
122
  }
111
123
 
@@ -117,7 +129,7 @@ export class Chess {
117
129
  if (move) {
118
130
  return move.inDraw === true
119
131
  } else {
120
- return new ChessJs(this.fen()).in_draw()
132
+ return new ChessJs(this.fen(), {chess960: this.props.chess960}).in_draw()
121
133
  }
122
134
  }
123
135
 
@@ -129,7 +141,7 @@ export class Chess {
129
141
  if (move) {
130
142
  return move.inStalemate === true
131
143
  } else {
132
- return new ChessJs(this.fen()).in_stalemate()
144
+ return new ChessJs(this.fen(), {chess960: this.props.chess960}).in_stalemate()
133
145
  }
134
146
  }
135
147
 
@@ -141,7 +153,7 @@ export class Chess {
141
153
  if (move) {
142
154
  return move.insufficientMaterial === true
143
155
  } else {
144
- return new ChessJs(this.fen()).insufficient_material()
156
+ return new ChessJs(this.fen(), {chess960: this.props.chess960}).insufficient_material()
145
157
  }
146
158
  }
147
159
 
@@ -161,7 +173,7 @@ export class Chess {
161
173
  if (move) {
162
174
  return move.inCheckmate === true
163
175
  } else {
164
- return new ChessJs(this.fen()).in_checkmate()
176
+ return new ChessJs(this.fen(), {chess960: this.props.chess960}).in_checkmate()
165
177
  }
166
178
  }
167
179
 
@@ -173,7 +185,7 @@ export class Chess {
173
185
  if (move) {
174
186
  return move.inCheck === true
175
187
  } else {
176
- return new ChessJs(this.fen()).in_check()
188
+ return new ChessJs(this.fen(), {chess960: this.props.chess960}).in_check()
177
189
  }
178
190
  }
179
191
 
@@ -201,13 +213,13 @@ export class Chess {
201
213
  * @param fen
202
214
  */
203
215
  load(fen) {
204
- const chess = new ChessJs(fen)
216
+ const chess = new ChessJs(fen, {chess960: this.props.chess960})
205
217
  if (chess && chess.fen() === fen) {
206
- this.pgn = new Pgn()
218
+ this.pgn = new Pgn(undefined, {chess960: this.props.chess960})
207
219
  if (fen !== FEN.start) {
208
220
  this.pgn.header.tags[TAGS.SetUp] = "1"
209
221
  this.pgn.header.tags[TAGS.FEN] = chess.fen()
210
- this.pgn.history.setUpFen = fen
222
+ this.pgn.history.props.setUpFen = fen
211
223
  }
212
224
  } else {
213
225
  throw Error("Invalid fen " + fen)
@@ -267,7 +279,7 @@ export class Chess {
267
279
  * @returns {{}}
268
280
  */
269
281
  moves(options = undefined, move = this.lastMove()) {
270
- const chessJs = new ChessJs(this.fen(move))
282
+ const chessJs = new ChessJs(this.fen(move), {chess960: this.props.chess960})
271
283
  return chessJs.moves(options)
272
284
  }
273
285
 
@@ -301,7 +313,7 @@ export class Chess {
301
313
  * @returns {[]} the pieces (positions) at a specific move
302
314
  */
303
315
  pieces(type = undefined, color = undefined, move = this.lastMove()) {
304
- const chessJs = move ? new ChessJs(move.fen) : new ChessJs(this.fen())
316
+ const chessJs = move ? new ChessJs(move.fen, {chess960: this.props.chess960}) : new ChessJs(this.fen(), {chess960: this.props.chess960})
305
317
  let result = []
306
318
  for (let i = 0; i < 64; i++) {
307
319
  const square = SQUARES[i]
@@ -329,7 +341,7 @@ export class Chess {
329
341
  * @returns {{color: any, type: any}|null}
330
342
  */
331
343
  piece(square, move = this.lastMove()) {
332
- const chessJs = move ? new ChessJs(move.fen) : new ChessJs(this.fen())
344
+ const chessJs = move ? new ChessJs(move.fen, {chess960: this.props.chess960}) : new ChessJs(this.fen(), {chess960: this.props.chess960})
333
345
  return chessJs.get(square)
334
346
  }
335
347
 
package/test/TestChess.js CHANGED
@@ -7,6 +7,15 @@ import {Chess, COLOR, FEN} from "../src/Chess.js"
7
7
 
8
8
  describe("Chess", function () {
9
9
 
10
+ it("should make a black move from FEN and SAN", function () {
11
+ const chess = new Chess("rnbqkbnr/pppp1ppp/8/4p3/4PP2/8/PPPP2PP/RNBQKBNR b KQkq f3 0 2")
12
+ const result = chess.move("d5")
13
+ assert.true(result)
14
+ const chess2 = new Chess({fen: "rnbqkbnr/ppp2ppp/8/3pp3/4PP2/8/PPPP2PP/RNBQKBNR w KQkq d6 0 3"})
15
+ const result2 = chess2.move("Ne2")
16
+ assert.true(result)
17
+ })
18
+
10
19
  it("should create empty Chess", () => {
11
20
  const chess = new Chess()
12
21
  assert.equal(chess.history().length, 0)
@@ -31,6 +40,7 @@ describe("Chess", function () {
31
40
  const chess = new Chess({pgn: pgn})
32
41
  assert.equal(chess.move("Nc6"), null)
33
42
  const result = chess.move("h6")
43
+ console.log("TestChess result", result)
34
44
  assert.equal(result.fen, "4k3/pppp1pp1/7p/4p3/4P3/P7/1PPP1PPP/4K3 w - - 0 3")
35
45
  })
36
46
 
@@ -205,10 +215,15 @@ Kc4 7. Qb4+ Kd5 8. Qc5#) 5. Bc5# 1-0`)
205
215
  }
206
216
  })
207
217
 
208
- it("should load different PGNs and then work correctly", function () {
218
+ it("should load an unusual FEN", function () {
209
219
  const fen = "ppppkppp/pppppppp/pppppppp/pppppppp/8/8/8/RNBQKBNR w KQ - 0 1"
210
220
  const chess = new Chess({fen: fen})
211
- assert.true(chess.move("e4") === null)
221
+ assert.equal(chess.history().length, 0)
222
+ assert.equal(chess.turn(), COLOR.white)
223
+ assert.equal(chess.fen(), fen)
224
+ const result = chess.move("e4");
225
+ assert.equal(chess.fen(), fen)
226
+ assert.true(result === null)
212
227
  assert.true(chess.move("Ke2") !== null)
213
228
  chess.load(FEN.start)
214
229
  assert.true(chess.move("e4"))
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @author Stefan Haack (https://shaack.com)
3
+ */
4
+ import {describe, it, assert} from "teevi/src/teevi.js"
5
+ import {Chess} from "../src/Chess.js"
6
+
7
+ describe("Testing Chess 960", function () {
8
+
9
+ it("should load a chess960 game from a valid chess960 fen and do castling", function () {
10
+ const fen = "nrkbrnbq/pppppppp/8/8/8/8/PPPPPPPP/NRKBRNBQ w KQkq - 0 1"
11
+ const chess = new Chess({chess960: true})
12
+ chess.load(fen)
13
+ assert.equal(chess.fen(), fen)
14
+ assert.true(chess.move("f4"))
15
+ assert.true(chess.move("Nb6"))
16
+ assert.true(chess.move("Nb3"))
17
+ assert.true(chess.move("f6"))
18
+ assert.true(chess.move("e4"))
19
+ assert.true(chess.move("e5"))
20
+ assert.true(chess.move("f5"))
21
+ assert.true(chess.move("d5"))
22
+ assert.true(chess.move("g4"))
23
+ assert.true(chess.move("Nfd7"))
24
+ assert.true(chess.move("exd5"))
25
+ assert.true(chess.move("Bxd5"))
26
+ assert.true(chess.move("Bf3"))
27
+ assert.true(chess.move("c6"))
28
+ assert.true(chess.move("Ng3"))
29
+ assert.true(chess.move("Be7"))
30
+ assert.true(chess.move("O-O-O"))
31
+ assert.true(chess.move("Qg8"))
32
+ assert.equal(chess.fen(), "1rk1r1q1/pp1nb1pp/1np2p2/3bpP2/6P1/1N3BN1/PPPP3P/2KRR1BQ w kq - 4 10")
33
+
34
+ })
35
+
36
+ it("should load a chess960 game from a valid chess960 pgn", function () {
37
+ const pgn = `[Event "Freestyle Weissenhaus KO"]
38
+ [Site "Wangels GER"]
39
+ [Date "2025.02.09"]
40
+ [EventDate "2025.02.09"]
41
+ [Round "1.1"]
42
+ [Result "1-0"]
43
+ [White "Levon Aronian"]
44
+ [Black "Vladimir Fedoseev"]
45
+ [ECO "?"]
46
+ [WhiteElo "?"]
47
+ [BlackElo "?"]
48
+ [PlyCount "72"]
49
+ [Variant "Chess960"]
50
+ [SetUp "1"]
51
+ [FEN "nrkbrnbq/pppppppp/8/8/8/8/PPPPPPPP/NRKBRNBQ w KQkq - 0 1"]
52
+
53
+ 1. f4 Nb6 2. Nb3 f6 3. e4 e5 4. f5 d5 5. g4 Nfd7 6. exd5 Bxd5 7. Bf3 c6 8.
54
+ Ng3 Be7 9. O-O-O Qg8 10. d3 Bb4 11. c3 Be7 12. c4 Bxf3 13. Qxf3 Qf7 14. Ne4
55
+ O-O 15. Be3 Na4 16. Rg1 b5 17. c5 b4 18. Qf2 Rb5 19. Qc2 a5 20. d4 Ra8 21.
56
+ g5 Kh8 22. gxf6 Bxf6 23. d5 cxd5 24. Nd6 Qf8 25. Nxb5 d4 26. c6 Rc8 27.
57
+ N3xd4 exd4 28. Bxd4 Nac5 29. Bxf6 Nxf6 30. c7 b3 31. axb3 Na6 32. Kb1 Nb4
58
+ 33. Qc4 Ne8 34. Rd8 Qxf5+ 35. Ka1 Nc2+ 36. Qxc2 1-0`
59
+ const chess = new Chess()
60
+ chess.loadPgn(pgn)
61
+ assert.equal(chess.fen(), "2rRn2k/2P3pp/8/pN3q2/8/1P6/1PQ4P/K5R1 b - - 0 36")
62
+ })
63
+ })
package/test/index.html CHANGED
@@ -18,6 +18,7 @@
18
18
  <script type="module">
19
19
  import {teevi} from "teevi/src/teevi.js"
20
20
  import "./TestChess.js"
21
+ import "./TestChess960.js"
21
22
  import "./TestFen.js"
22
23
  teevi.run()
23
24
  </script>