cm-chess 3.5.1 → 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 +0 -2
- package/README.md +1 -1
- package/package.json +3 -3
- package/src/Chess.js +30 -18
- package/test/TestChess.js +17 -2
- package/test/TestChess960.js +63 -0
- package/test/index.html +1 -0
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
|
|
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.
|
|
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": "^
|
|
28
|
-
"cm-pgn": "
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
58
|
-
this.props.fen =
|
|
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
|
|
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.
|
|
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
|
+
})
|