-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathTestChess.js
More file actions
337 lines (300 loc) · 12.1 KB
/
TestChess.js
File metadata and controls
337 lines (300 loc) · 12.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/**
* @author Stefan Haack (https://shaack.com)
*/
import {TAGS} from "cm-pgn/src/Header.js"
import {describe, it, assert} from "../node_modules/teevi/src/teevi.js"
import {Chess, COLOR, FEN} from "../src/Chess.js"
describe("Chess", function () {
it("should make a black move from FEN and SAN", function () {
const chess = new Chess({fen: "rnbqkbnr/pppp1ppp/8/4p3/4PP2/8/PPPP2PP/RNBQKBNR b KQkq f3 0 2"})
const result = chess.move("d5")
assert.true(result)
const chess2 = new Chess({fen: "rnbqkbnr/ppp2ppp/8/3pp3/4PP2/8/PPPP2PP/RNBQKBNR w KQkq d6 0 3"})
const result2 = chess2.move("Ne2")
assert.true(result2)
})
it("should create empty Chess", () => {
const chess = new Chess()
assert.equal(chess.history().length, 0)
assert.equal(Object.keys(chess.header()).length, 0)
assert.equal(chess.fen(), FEN.start)
})
it("should load a game from FEN", function () {
const fen = "4k3/pppppppp/8/8/8/8/PPPPPPPP/4K3 w - - 0 1"
const chess = new Chess({fen: fen})
assert.equal(chess.pgn.header.tags[TAGS.FEN], fen)
assert.equal(chess.fen(), fen)
assert.equal(chess.piece("e1").type, "k")
assert.equal(chess.piece("e1").color, "w")
})
it("should load a pgn with SetUp and FEN", function () {
const pgn = `[SetUp "1"]
[FEN "4k3/pppppppp/8/8/8/8/PPPPPPPP/4K3 w - - 0 1"]
1. e4 (1. d4 {Die Variante} d5) e5 {Ein Kommentar} 2. a3`
const chess = new Chess({pgn: pgn})
assert.equal(chess.move("Nc6"), null)
const result = chess.move("h6")
console.log("TestChess result", result)
assert.equal(result.fen, "4k3/pppp1pp1/7p/4p3/4P3/P7/1PPP1PPP/4K3 w - - 0 3")
})
it("should load a pgn", function () {
const chess = new Chess()
const pgn = `[Event "IBM Kasparov vs. Deep Blue Rematch"]
[Site "New York, NY USA"]
[Date "1997.05.11"]
[Round "6"]
[White "Deep Blue"]
[Black "Kasparov, Garry"]
[Opening "Caro-Kann: 4...Nd7"]
[ECO "B17"]
[Result "1-0"]
1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Nd7 5.Ng5 Ngf6 6.Bd3 e6 7.N1f3 h6
8.Nxe6 Qe7 9.O-O fxe6 10.Bg6+ Kd8 {Kasparov schüttelt kurz den Kopf}
11.Bf4 b5 12.a4 Bb7 13.Re1 Nd5 14.Bg3 Kc8 15.axb5 cxb5 16.Qd3 Bc6
17.Bf5 exf5 18.Rxe7 Bxe7 19.c4 1-0`
chess.loadPgn(pgn)
assert.equal(chess.history().length, 37)
assert.equal(chess.header()[TAGS.White], "Deep Blue")
const firstMove = chess.history()[0]
assert.equal(firstMove.color, "w")
assert.equal(firstMove.san, "e4")
assert.equal(firstMove.fen, "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
assert.equal(chess.history()[19].commentAfter, "Kasparov schüttelt kurz den Kopf")
})
it("should load a pgn with SetUp", () => {
const pgn = `[Event "?"]
[White "?"]
[Black "?"]
[Result "0-1"]
[SetUp "1"]
[FEN "5rk1/2nb1p1p/1p4p1/p2p2P1/1p2qP1P/1P2P3/P1Q1NK2/1B5R w - - 0 1"]
1. Qc1 Qe6 2. Qxc7
0-1`
const chess = new Chess({pgn: pgn})
assert.equal(chess.history()[2].san, "Qxc7")
})
it('should parse stappenmethode weekly.pgn', () => {
const chess = new Chess()
const pgn = `[Event "?"]
[Site "?"]
[Date "2012.??.??"]
[Round "?"]
[White "Schaak opheffen"]
[Black "Materiaal"]
[Result "0-1"]
[Annotator "S3"]
[Annotator "app 037-1"]
[SetUp "1"]
[FEN "r1b1Q1k1/1p2bpqp/8/8/p1Pr4/4PpN1/P6P/R4RK1 b - - 0 1"]
1... Bf8 (1... Qf8? 2. Qxf8+ Bxf8 3. exd4) 2. exd4 Qxd4+ {%Q} 3. Kh1 Bh3
0-1`
chess.loadPgn(pgn)
assert.equal(5, chess.pgn.history.moves.length)
assert.equal("Schaak opheffen", chess.pgn.header.tags[TAGS.White])
assert.equal("app 037-1", chess.pgn.header.tags[TAGS.Annotator])
})
it('should allow traverse through moves', () => {
const chess = new Chess()
const pgn = `[SetUp "1"]
[FEN "8/8/b2Bq3/7Q/3kp3/5pP1/8/3K4 w - - 0 1"]
[Result "1-0"]
1. Qc5+ Kd3 2. Qc2+ Kd4 3. Qd2+ Bd3 4. Qe3+ Kxe3 (4... Kc3 5. Qc1+ Kb3 6. Qa3+ Kc4 7. Qb4+ Kd5 8. Qc5#) 5. Bc5#
1-0`
chess.loadPgn(pgn)
assert.equal(chess.turn(), COLOR.black)
const firstMove = chess.history()[0]
assert.equal(firstMove.san, "Qc5+")
const secondMove = firstMove.next
assert.equal(secondMove.san, "Kd3")
assert.equal(chess.lastMove().san, "Bc5#")
assert.equal(chess.gameOver(), true)
assert.equal(chess.lastMove().inCheckmate, true)
assert.equal(chess.inCheckmate(), true)
assert.equal(chess.inDraw(), false)
assert.equal(chess.renderPgn(), `[SetUp "1"]
[FEN "8/8/b2Bq3/7Q/3kp3/5pP1/8/3K4 w - - 0 1"]
[Result "1-0"]
1. Qc5+ Kd3 2. Qc2+ Kd4 3. Qd2+ Bd3 4. Qe3+ Kxe3 (4... Kc3 5. Qc1+ Kb3 6. Qa3+
Kc4 7. Qb4+ Kd5 8. Qc5#) 5. Bc5# 1-0`)
})
it('should add move at the end of the history', () => {
const chess = new Chess()
assert.equal(chess.turn(), COLOR.white)
chess.move("e4")
assert.equal(chess.turn(), COLOR.black)
assert.equal(chess.history()[0].san, "e4")
chess.move("e5")
assert.equal(chess.turn(), COLOR.white)
})
it('should provide correct turn after loading a FEN', () => {
const chess = new Chess()
chess.load('rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1')
assert.equal(chess.turn(), COLOR.black)
})
it('invalid move should return `null`', () => {
const chess = new Chess()
chess.load('rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1')
assert.equal(chess.turn(), COLOR.black)
// assert.notEqual(chess.validateMove("a1"), null)
const move = chess.move("a1")
assert.equal(move, null)
})
it('should return pieces', () => {
const chess = new Chess()
assert.equal(chess.pieces().length, 32)
const pgn = `[SetUp "1"]
[FEN "8/8/b2Bq3/7Q/3kp3/5pP1/8/3K4 w - - 0 1"]
1. Qc5+ Kd3 2. Qc2+ Kd4 3. Qd2+ Bd3 4. Qe3+ Kxe3 (4... Kc3 5. Qc1+ Kb3 6. Qa3+ Kc4 7. Qb4+ Kd5 8. Qc5#) 5. Bc5#
1-0`
chess.loadPgn(pgn)
assert.equal(chess.pieces("k").length, 2)
})
it('should undo lastMove', () => {
const chess = new Chess()
const pgn = `[SetUp "1"]
[FEN "8/8/b2Bq3/7Q/3kp3/5pP1/8/3K4 w - - 0 1"]
1. Qc5+ Kd3 2. Qc2+ Kd4 3. Qd2+ Bd3 4. Qe3+ Kxe3 (4... Kc3 5. Qc1+ Kb3 6. Qa3+ Kc4 7. Qb4+ Kd5 8. Qc5#) 5. Bc5#
1-0`
chess.loadPgn(pgn)
assert.equal(chess.history().length, 9)
chess.undo()
assert.equal(chess.history().length, 8)
})
it('should undo more moves', () => {
const chess = new Chess()
const pgn = `[SetUp "1"]
[FEN "8/8/b2Bq3/7Q/3kp3/5pP1/8/3K4 w - - 0 1"]
1. Qc5+ Kd3 2. Qc2+ Kd4 3. Qd2+ Bd3 4. Qe3+ Kxe3 (4... Kc3 5. Qc1+ Kb3 6. Qa3+ Kc4 7. Qb4+ Kd5 8. Qc5#) 5. Bc5#
1-0`
chess.loadPgn(pgn)
chess.undo(chess.history()[5])
assert.equal(chess.history().length, 5)
assert.equal(chess.plyCount(), 5)
assert.equal(chess.fenOfPly(0), "8/8/b2Bq3/7Q/3kp3/5pP1/8/3K4 w - - 0 1")
assert.equal(chess.fenOfPly(3), "8/8/b2Bq3/8/4p3/3k1pP1/2Q5/3K4 b - - 3 2")
})
it("should not load incorrect FEN", function () {
const fen = "4k3/pppppppp/8/8/8/8/PPPPPP/4K3 w - - 0 1"
try {
new Chess({fen: fen})
assert.true(false)
} catch (e) {
// OK
}
try {
const chess = new Chess()
chess.load(fen)
assert.true(false)
} catch (e) {
// OK
}
})
it("should load an unusual FEN", function () {
const fen = "ppppkppp/pppppppp/pppppppp/pppppppp/8/8/8/RNBQKBNR w KQ - 0 1"
const chess = new Chess({fen: fen})
assert.equal(chess.history().length, 0)
assert.equal(chess.turn(), COLOR.white)
assert.equal(chess.fen(), fen)
const result = chess.move("e4")
assert.equal(chess.fen(), fen)
assert.true(result === null)
assert.true(chess.move("Ke2") !== null)
chess.load(FEN.start)
assert.true(chess.move("e4"))
})
it("should validate Moves", function () {
const chess = new Chess()
assert.notEqual(chess.validateMove("e4"), null)
assert.notEqual(chess.validateMove("e3"), null)
assert.notEqual(chess.validateMove("Nf3"), null)
assert.equal(chess.validateMove("xyz"), null)
assert.equal(chess.validateMove("e6"), null)
})
it("should publish events", function () {
return new Promise((resolve, reject) => {
const chess = new Chess()
chess.addObserver((event) => {
if (event.type === "legalMove" &&
event.move.from === "e2" &&
event.move.to === "e4") {
resolve()
} else {
reject("error event")
}
})
chess.move("e4")
})
})
it("should provide valid moves", function () {
const chess = new Chess()
assert.equal(chess.moves().length, 20)
chess.move("Nc3")
assert.equal(chess.moves().length, 20)
chess.move("e5")
assert.equal(chess.moves().length, 22)
assert.equal(JSON.stringify(chess.moves({square: "e2"})), '["e3","e4"]')
assert.equal(JSON.stringify(chess.moves({piece: "n"})), '["Na4","Nb5","Nd5","Ne4","Nb1","Nf3","Nh3"]')
})
it("should detect a check in a game without moves", function () {
const chess = new Chess({fen: "4k3/1P6/8/b7/6r1/8/pp2PPPP/2R1KBNR w K - 0 1"})
assert.true(chess.inCheck())
})
// see https://www.chessmail.de/forum/thread.html?key=GINGFqlNiAjf&sv=6
it("should make a move with sloppy SAN", function () {
let chess = new Chess({fen: "r1R2r1k/1R6/1P2B2p/4pPp1/4N1P1/7P/5P2/2R3K1 w - - 1 44"})
let result = chess.move("R8c7", undefined, false)
assert.true(result !== null)
chess = new Chess({fen: "r1R2r1k/1R6/1P2B2p/4pPp1/4N1P1/7P/5P2/2R3K1 w - - 1 44"})
result = chess.move("Rc8c7", undefined, false)
assert.true(result == null)
chess = new Chess({fen: "r1R2r1k/1R6/1P2B2p/4pPp1/4N1P1/7P/5P2/2R3K1 w - - 1 44"})
result = chess.move("Rc8-c7", undefined, false)
assert.true(result == null)
chess = new Chess({fen: "r1R2r1k/1R6/1P2B2p/4pPp1/4N1P1/7P/5P2/2R3K1 w - - 1 44"})
result = chess.move("Rc8-c7", undefined, true)
assert.true(result != null)
chess = new Chess({fen: "r1R2r1k/1R6/1P2B2p/4pPp1/4N1P1/7P/5P2/2R3K1 w - - 1 44"})
result = chess.move("Rc8c7", undefined, true)
assert.true(result != null)
})
it("should promote a pawn via SAN", function () {
const chess = new Chess({fen: "rnbqkbnr/ppppppPp/8/8/8/8/PPPPPP1P/RNBQKBNR w KQkq - 0 1"})
const move = chess.move("gxh8=Q")
assert.true(move !== null)
assert.equal(move.promotion, "q")
assert.true(move.flags.includes("p"))
assert.equal(chess.piece("h8").type, "q")
assert.equal(chess.piece("h8").color, "w")
})
it("should promote to a knight (underpromotion)", function () {
const chess = new Chess({fen: "4k3/P7/8/8/8/8/8/4K3 w - - 0 1"})
const move = chess.move("a8=N")
assert.true(move !== null)
assert.equal(move.promotion, "n")
assert.equal(chess.piece("a8").type, "n")
})
it("should capture en passant", function () {
const chess = new Chess({fen: "rnbqkbnr/pp1ppppp/8/2pP4/8/8/PPP1PPPP/RNBQKBNR w KQkq c6 0 1"})
const move = chess.move("dxc6")
assert.true(move !== null)
assert.true(move.flags.includes("e"))
assert.equal(move.fen, "rnbqkbnr/pp1ppppp/2P5/8/8/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1")
assert.equal(chess.piece("c5"), null)
})
it("should load a sloppy pgn", function () {
const pgn = `pgn [SetUp "1"]
[FEN "r1R2r1k/1R6/1P2B2p/4pPp1/4N1P1/7P/5P2/2R3K1 w - - 1 44"]
1.Rc8c7 *`
let chess
try {
chess = new Chess({pgn: pgn, sloppy: false})
assert.fail("should throw error")
} catch (e) {
// ok
}
assert.true(chess == null)
// should work with sloppy = true
chess = new Chess({pgn: pgn, sloppy: true})
assert.true(chess != null)
})
})