schachnovelle 1.0.1 → 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.
- package/package.json +3 -1
- package/server/api.js +119 -11
- package/server/index.js +331 -31
- package/ui/Board.js +25 -4
- package/ui/Fen.js +5 -0
- package/ui/Game.js +405 -332
- package/ui/LichessGame.js +11 -0
- package/ui/Side.js +10 -9
- package/ui/Utils.js +3 -2
- package/ui/index.js +69 -8
- package/ui/moves.js +0 -0
- package/views/error.pug +6 -0
- package/views/index.pug +6 -0
- package/views/layout.pug +6 -0
- package/views/welcome.pug +6 -0
- package/yarn-error.log +0 -367
package/ui/Game.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
const readline = require(
|
|
2
|
-
const Side = require(
|
|
3
|
-
const Board = require(
|
|
4
|
-
const Printer = require(
|
|
5
|
-
const Utils = require(
|
|
1
|
+
const readline = require("readline")
|
|
2
|
+
const Side = require("./Side")
|
|
3
|
+
const Board = require("./Board")
|
|
4
|
+
const Printer = require("./Printer")
|
|
5
|
+
const Utils = require("./Utils")
|
|
6
6
|
|
|
7
|
-
const Enquirer = require(
|
|
7
|
+
const Enquirer = require("enquirer")
|
|
8
8
|
|
|
9
9
|
class Game {
|
|
10
|
-
constructor
|
|
11
|
-
this.white = new Side(
|
|
12
|
-
this.black = new Side(
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.white = new Side("white")
|
|
12
|
+
this.black = new Side("black")
|
|
13
13
|
this.playingAs = options.playingAs
|
|
14
|
-
this.toMove =
|
|
14
|
+
this.toMove = "white"
|
|
15
15
|
|
|
16
16
|
this.moveIndex = 0
|
|
17
17
|
this.history = []
|
|
@@ -20,10 +20,10 @@ class Game {
|
|
|
20
20
|
|
|
21
21
|
// Initialize the board
|
|
22
22
|
this.board = new Board(this.white, this.black, {
|
|
23
|
-
mode:
|
|
23
|
+
mode: "pieces", // possibly add text mode
|
|
24
24
|
orientation: this.playingAs,
|
|
25
25
|
spacing: options.spacing,
|
|
26
|
-
mode: options.mode
|
|
26
|
+
mode: options.mode,
|
|
27
27
|
})
|
|
28
28
|
|
|
29
29
|
this.enquirer = new Enquirer()
|
|
@@ -36,19 +36,21 @@ class Game {
|
|
|
36
36
|
* 2. Sets that as the selected piece
|
|
37
37
|
*/
|
|
38
38
|
async promptPieceSelection() {
|
|
39
|
-
const response = await this.enquirer
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
39
|
+
const response = await this.enquirer
|
|
40
|
+
.prompt([
|
|
41
|
+
{
|
|
42
|
+
type: "select",
|
|
43
|
+
name: "piece",
|
|
44
|
+
message: "Piece",
|
|
45
|
+
choices: this.listAvailablePieces(),
|
|
46
|
+
result: result => {
|
|
47
|
+
this.setSelectedPiece(result)
|
|
48
|
+
return result
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
])
|
|
52
|
+
.catch(console.error)
|
|
53
|
+
|
|
52
54
|
/**
|
|
53
55
|
* Only do something if the await has been fulfilled
|
|
54
56
|
*/
|
|
@@ -62,29 +64,33 @@ class Game {
|
|
|
62
64
|
* 3. Asks for the new coordinates of that piece
|
|
63
65
|
*/
|
|
64
66
|
async promptFileSelection() {
|
|
65
|
-
const backToPiece =
|
|
66
|
-
const response = await this.enquirer
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
67
|
+
const backToPiece = "... piece selection"
|
|
68
|
+
const response = await this.enquirer
|
|
69
|
+
.prompt([
|
|
70
|
+
{
|
|
71
|
+
type: "select",
|
|
72
|
+
name: "file",
|
|
73
|
+
message: "File:",
|
|
74
|
+
choices: this.possibleFiles().concat(backToPiece),
|
|
75
|
+
result: result => {
|
|
76
|
+
if (result === backToPiece) {
|
|
77
|
+
return result
|
|
78
|
+
} else {
|
|
79
|
+
this.setSelectedFile(result)
|
|
80
|
+
return result
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
])
|
|
85
|
+
.catch(console.error)
|
|
86
|
+
|
|
83
87
|
/**
|
|
84
88
|
* Only do something if the await has been fulfilled
|
|
85
89
|
*/
|
|
86
90
|
if (response) {
|
|
87
|
-
if (response.file === backToPiece) {
|
|
91
|
+
if (response.file === backToPiece) {
|
|
92
|
+
this.promptPieceSelection()
|
|
93
|
+
} else {
|
|
88
94
|
this.promptRankSelection()
|
|
89
95
|
}
|
|
90
96
|
}
|
|
@@ -95,156 +101,188 @@ class Game {
|
|
|
95
101
|
* 3. Asks for the new coordinates of that piece
|
|
96
102
|
*/
|
|
97
103
|
async promptRankSelection() {
|
|
98
|
-
const backToFile =
|
|
99
|
-
const response = await this.enquirer
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
104
|
+
const backToFile = "... file selection"
|
|
105
|
+
const response = await this.enquirer
|
|
106
|
+
.prompt([
|
|
107
|
+
{
|
|
108
|
+
type: "select",
|
|
109
|
+
name: "rank",
|
|
110
|
+
message: "Rank:",
|
|
111
|
+
choices: this.possibleRanks().concat(backToFile),
|
|
112
|
+
result: result => {
|
|
113
|
+
if (result === backToFile) {
|
|
114
|
+
return result
|
|
115
|
+
} else {
|
|
116
|
+
this.setSelectedRank(Number(result))
|
|
117
|
+
return Number(result)
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
])
|
|
122
|
+
.catch(console.error)
|
|
123
|
+
|
|
116
124
|
/**
|
|
117
125
|
* Only do something if the await has been fulfilled
|
|
118
126
|
*/
|
|
119
127
|
if (response) {
|
|
120
|
-
if (response.rank === backToFile) {
|
|
128
|
+
if (response.rank === backToFile) {
|
|
129
|
+
this.promptFileSelection()
|
|
130
|
+
} else {
|
|
121
131
|
this.validateMove()
|
|
122
132
|
}
|
|
123
133
|
}
|
|
124
134
|
}
|
|
125
135
|
|
|
136
|
+
/**
|
|
137
|
+
* For the given color, return all possible moves
|
|
138
|
+
*/
|
|
139
|
+
allPossibleMoves(color) {
|
|
140
|
+
let all = []
|
|
141
|
+
this.board[color].pieces
|
|
142
|
+
.filter(p => !p.captured)
|
|
143
|
+
.forEach(p => {
|
|
144
|
+
this.possibleMoves(p, color)
|
|
145
|
+
.forEach(m => all.push(m))
|
|
146
|
+
})
|
|
147
|
+
return all
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Return all possible checks
|
|
152
|
+
* @param {*} color
|
|
153
|
+
* @returns
|
|
154
|
+
*/
|
|
155
|
+
allPossibleChecks(color) {
|
|
156
|
+
// Moves
|
|
157
|
+
const moves = this.allPossibleMoves(color)
|
|
158
|
+
|
|
159
|
+
const allChecks = moves.filter(m => m[2] === 'check')
|
|
160
|
+
|
|
161
|
+
return allChecks
|
|
162
|
+
}
|
|
163
|
+
|
|
126
164
|
/**
|
|
127
165
|
* Return the possible moves for the selected piece
|
|
128
166
|
* Returns an object with all possible moves split into file, and rank
|
|
129
167
|
*/
|
|
130
|
-
possibleMoves
|
|
168
|
+
possibleMoves(piece, color) {
|
|
169
|
+
// TODO: If the current color is in check,
|
|
170
|
+
// then limit the possible moves to the ones that get you out of it
|
|
171
|
+
|
|
131
172
|
// Start with the selected piece. First of all, it can't move to it's own square
|
|
132
173
|
switch (piece.type) {
|
|
133
|
-
case
|
|
134
|
-
return this.possiblePawnMoves(piece)
|
|
135
|
-
case
|
|
136
|
-
return this.possibleKnightMoves(piece)
|
|
137
|
-
case
|
|
138
|
-
return this.possibleBishopMoves(piece)
|
|
139
|
-
case
|
|
140
|
-
return this.possibleRookMoves(piece)
|
|
141
|
-
case
|
|
142
|
-
return this.possibleQueenMoves(piece)
|
|
143
|
-
case
|
|
144
|
-
return this.possibleKingMoves(piece)
|
|
174
|
+
case "Pawn":
|
|
175
|
+
return this.possiblePawnMoves(piece, color)
|
|
176
|
+
case "Knight":
|
|
177
|
+
return this.possibleKnightMoves(piece, color)
|
|
178
|
+
case "Bishop":
|
|
179
|
+
return this.possibleBishopMoves(piece, color)
|
|
180
|
+
case "Rook":
|
|
181
|
+
return this.possibleRookMoves(piece, color)
|
|
182
|
+
case "Queen":
|
|
183
|
+
return this.possibleQueenMoves(piece, color)
|
|
184
|
+
case "King":
|
|
185
|
+
return this.possibleKingMoves(piece, color)
|
|
145
186
|
}
|
|
146
187
|
}
|
|
147
188
|
|
|
148
189
|
/**
|
|
149
190
|
* Returns all possible moves for a pawn
|
|
150
191
|
*/
|
|
151
|
-
possiblePawnMoves (pawn) {
|
|
192
|
+
possiblePawnMoves (pawn, color) {
|
|
152
193
|
const possible = []
|
|
153
194
|
const positions = []
|
|
154
|
-
const
|
|
155
|
-
|
|
195
|
+
const direction = this.playingAs === color ? 1 : -1
|
|
196
|
+
|
|
197
|
+
const nextRank = pawn.pos[1] + direction
|
|
198
|
+
const secondNextRank = pawn.pos[1] + (direction * 2)
|
|
156
199
|
// If it's on the starting rank, allow two moves
|
|
157
|
-
if (pawn.pos[1] === 2 &&
|
|
158
|
-
positions.push(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
positions.push(
|
|
164
|
-
[pawn.pos[0], nextRank],
|
|
165
|
-
[pawn.pos[0], secondNextRank]
|
|
166
|
-
)
|
|
167
|
-
} else if (this.toMove === 'white') {
|
|
168
|
-
positions.push(
|
|
169
|
-
[pawn.pos[0], nextRank]
|
|
170
|
-
)
|
|
200
|
+
if (pawn.pos[1] === 2 && color === "white") {
|
|
201
|
+
positions.push([pawn.pos[0], nextRank], [pawn.pos[0], secondNextRank])
|
|
202
|
+
} else if (pawn.pos[1] === 7 && color === "black") {
|
|
203
|
+
positions.push([pawn.pos[0], nextRank], [pawn.pos[0], secondNextRank])
|
|
204
|
+
} else if (color === "white") {
|
|
205
|
+
positions.push([pawn.pos[0], nextRank])
|
|
171
206
|
} else {
|
|
172
|
-
positions.push(
|
|
173
|
-
[pawn.pos[0], nextRank]
|
|
174
|
-
)
|
|
207
|
+
positions.push([pawn.pos[0], nextRank])
|
|
175
208
|
}
|
|
176
209
|
// Captures
|
|
177
210
|
const fileIndex = this.board.files.indexOf(pawn.pos[0])
|
|
178
211
|
const positionsToCapture = []
|
|
179
212
|
switch (fileIndex) {
|
|
180
|
-
case
|
|
181
|
-
const posXL = [
|
|
213
|
+
case 0:
|
|
214
|
+
const posXL = [this.board.files[fileIndex + 1], nextRank]
|
|
182
215
|
positionsToCapture.push(posXL)
|
|
183
216
|
break
|
|
184
|
-
case
|
|
185
|
-
const posXR = [
|
|
217
|
+
case 7:
|
|
218
|
+
const posXR = [this.board.files[fileIndex - 1], nextRank]
|
|
186
219
|
positionsToCapture.push(posXR)
|
|
187
220
|
break
|
|
188
221
|
default:
|
|
189
|
-
const posL = [
|
|
190
|
-
const posR = [
|
|
222
|
+
const posL = [this.board.files[fileIndex + 1], nextRank]
|
|
223
|
+
const posR = [this.board.files[fileIndex - 1], nextRank]
|
|
191
224
|
positionsToCapture.push(posL, posR)
|
|
192
225
|
break
|
|
193
226
|
}
|
|
194
227
|
for (const pos of positions) {
|
|
195
|
-
if (this.movePotential(pos, false) !==
|
|
228
|
+
if (this.movePotential(pos, color, false) !== "blocked") {
|
|
196
229
|
possible.push(pos)
|
|
197
230
|
}
|
|
198
231
|
}
|
|
199
232
|
for (const pos of positionsToCapture) {
|
|
200
|
-
if (this.movePotential(pos, true) ===
|
|
233
|
+
if (this.movePotential(pos, color, true) === "capture") {
|
|
234
|
+
possible.push(pos)
|
|
235
|
+
} else if (this.movePotential(pos, color, true) === "check") {
|
|
236
|
+
pos.push('check')
|
|
201
237
|
possible.push(pos)
|
|
202
238
|
}
|
|
203
239
|
}
|
|
204
240
|
// TODO: en passant (depends on a history)
|
|
205
|
-
// TODO: Promotion. convert to queen / rook / bishop / knight
|
|
206
241
|
return possible
|
|
207
242
|
}
|
|
208
243
|
|
|
209
244
|
/**
|
|
210
245
|
* Just returns the candidate positions a knight could move to
|
|
211
|
-
* @param {Integer} fileIndex
|
|
212
|
-
* @param {Integer} rankIndex
|
|
246
|
+
* @param {Integer} fileIndex
|
|
247
|
+
* @param {Integer} rankIndex
|
|
213
248
|
*/
|
|
214
|
-
knightCandidateMoves
|
|
249
|
+
knightCandidateMoves(fileIndex, rankIndex) {
|
|
215
250
|
return [
|
|
216
251
|
// Two up, one left
|
|
217
|
-
[this.board.files[fileIndex - 1],
|
|
252
|
+
[this.board.files[fileIndex - 1], this.board.ranks[rankIndex + 2]],
|
|
218
253
|
// Two up, one right
|
|
219
|
-
[this.board.files[fileIndex + 1],
|
|
254
|
+
[this.board.files[fileIndex + 1], this.board.ranks[rankIndex + 2]],
|
|
220
255
|
// Two right, one up
|
|
221
|
-
[this.board.files[fileIndex + 2],
|
|
256
|
+
[this.board.files[fileIndex + 2], this.board.ranks[rankIndex + 1]],
|
|
222
257
|
// Two right, one down
|
|
223
|
-
[this.board.files[fileIndex + 2],
|
|
258
|
+
[this.board.files[fileIndex + 2], this.board.ranks[rankIndex - 1]],
|
|
224
259
|
// Two down, one right
|
|
225
|
-
[this.board.files[fileIndex + 1],
|
|
260
|
+
[this.board.files[fileIndex + 1], this.board.ranks[rankIndex - 2]],
|
|
226
261
|
// Two down, one left
|
|
227
|
-
[this.board.files[fileIndex - 1],
|
|
262
|
+
[this.board.files[fileIndex - 1], this.board.ranks[rankIndex - 2]],
|
|
228
263
|
// Two left, one down
|
|
229
|
-
[this.board.files[fileIndex - 2],
|
|
264
|
+
[this.board.files[fileIndex - 2], this.board.ranks[rankIndex - 1]],
|
|
230
265
|
// Two left, one up
|
|
231
|
-
[this.board.files[fileIndex - 2],
|
|
266
|
+
[this.board.files[fileIndex - 2], this.board.ranks[rankIndex + 1]],
|
|
232
267
|
]
|
|
233
268
|
}
|
|
234
269
|
|
|
235
270
|
/**
|
|
236
271
|
* Returns the possible moves for a knight
|
|
237
272
|
*/
|
|
238
|
-
possibleKnightMoves
|
|
273
|
+
possibleKnightMoves(knight, color) {
|
|
239
274
|
const fileIndex = this.board.files.indexOf(knight.pos[0])
|
|
240
275
|
const rankIndex = this.board.ranks.indexOf(knight.pos[1])
|
|
241
276
|
// From the starting square, draw a plus in each direction and then go one diagonal from there
|
|
242
277
|
// Take the starting file and go left and right
|
|
243
278
|
const candidates = this.knightCandidateMoves(fileIndex, rankIndex)
|
|
244
279
|
|
|
245
|
-
const possible = candidates.filter(
|
|
280
|
+
const possible = candidates.filter(move => {
|
|
246
281
|
if (move[0] !== undefined && move[1] !== undefined) {
|
|
247
|
-
if (this.movePotential(move,
|
|
282
|
+
if (this.movePotential(move, color, true) === "check") {
|
|
283
|
+
move.push('check')
|
|
284
|
+
return move
|
|
285
|
+
} else if (this.movePotential(move, color, true) !== "blocked") {
|
|
248
286
|
return move
|
|
249
287
|
}
|
|
250
288
|
}
|
|
@@ -255,15 +293,15 @@ class Game {
|
|
|
255
293
|
/**
|
|
256
294
|
* Returns the possible moves for a bishop
|
|
257
295
|
*/
|
|
258
|
-
possibleBishopMoves
|
|
296
|
+
possibleBishopMoves(bishop, color) {
|
|
259
297
|
// go into all diagonal directions until there's no place or there's a capture or there's a block
|
|
260
298
|
const fileIndex = this.board.files.indexOf(bishop.pos[0])
|
|
261
299
|
const rankIndex = this.board.ranks.indexOf(bishop.pos[1])
|
|
262
|
-
|
|
263
|
-
const fU = this.forwardAndUp(fileIndex, rankIndex)
|
|
264
|
-
const fD = this.forwardAndDown(fileIndex, rankIndex, false)
|
|
265
|
-
const bU = this.backwardAndUp(fileIndex, rankIndex, false)
|
|
266
|
-
const bD = this.backwardAndDown(fileIndex, rankIndex, false)
|
|
300
|
+
|
|
301
|
+
const fU = this.forwardAndUp(fileIndex, rankIndex, color)
|
|
302
|
+
const fD = this.forwardAndDown(fileIndex, rankIndex, color, false)
|
|
303
|
+
const bU = this.backwardAndUp(fileIndex, rankIndex, color, false)
|
|
304
|
+
const bD = this.backwardAndDown(fileIndex, rankIndex, color, false)
|
|
267
305
|
|
|
268
306
|
return [...fU, ...fD, ...bU, ...bD]
|
|
269
307
|
}
|
|
@@ -271,15 +309,15 @@ class Game {
|
|
|
271
309
|
/**
|
|
272
310
|
* Returns the possible moves for a rook
|
|
273
311
|
*/
|
|
274
|
-
possibleRookMoves
|
|
312
|
+
possibleRookMoves(rook, color) {
|
|
275
313
|
// go into all diagonal directions until there's no place or there's a capture or there's a block
|
|
276
314
|
const fileIndex = this.board.files.indexOf(rook.pos[0])
|
|
277
315
|
const rankIndex = this.board.ranks.indexOf(rook.pos[1])
|
|
278
|
-
|
|
279
|
-
const u = this.up(fileIndex, rankIndex, false)
|
|
280
|
-
const d = this.down(fileIndex, rankIndex, false)
|
|
281
|
-
const l = this.left(fileIndex, rankIndex, false)
|
|
282
|
-
const r = this.right(fileIndex, rankIndex, false)
|
|
316
|
+
|
|
317
|
+
const u = this.up(fileIndex, rankIndex, color, false)
|
|
318
|
+
const d = this.down(fileIndex, rankIndex, color, false)
|
|
319
|
+
const l = this.left(fileIndex, rankIndex, color, false)
|
|
320
|
+
const r = this.right(fileIndex, rankIndex, color, false)
|
|
283
321
|
|
|
284
322
|
return [...u, ...d, ...l, ...r]
|
|
285
323
|
}
|
|
@@ -287,19 +325,19 @@ class Game {
|
|
|
287
325
|
/**
|
|
288
326
|
* Returns the possible moves for a queen
|
|
289
327
|
*/
|
|
290
|
-
possibleQueenMoves
|
|
328
|
+
possibleQueenMoves(queen, color) {
|
|
291
329
|
// go into all diagonal directions until there's no place or there's a capture or there's a block
|
|
292
330
|
const fileIndex = this.board.files.indexOf(queen.pos[0])
|
|
293
331
|
const rankIndex = this.board.ranks.indexOf(queen.pos[1])
|
|
294
|
-
|
|
295
|
-
const u = this.up(fileIndex, rankIndex, false)
|
|
296
|
-
const d = this.down(fileIndex, rankIndex, false)
|
|
297
|
-
const l = this.left(fileIndex, rankIndex, false)
|
|
298
|
-
const r = this.right(fileIndex, rankIndex, false)
|
|
299
|
-
const fU = this.forwardAndUp(fileIndex, rankIndex, false)
|
|
300
|
-
const fD = this.forwardAndDown(fileIndex, rankIndex, false)
|
|
301
|
-
const bU = this.backwardAndUp(fileIndex, rankIndex, false)
|
|
302
|
-
const bD = this.backwardAndDown(fileIndex, rankIndex, false)
|
|
332
|
+
|
|
333
|
+
const u = this.up(fileIndex, rankIndex, color, false)
|
|
334
|
+
const d = this.down(fileIndex, rankIndex, color, false)
|
|
335
|
+
const l = this.left(fileIndex, rankIndex, color, false)
|
|
336
|
+
const r = this.right(fileIndex, rankIndex, color, false)
|
|
337
|
+
const fU = this.forwardAndUp(fileIndex, rankIndex, color, false)
|
|
338
|
+
const fD = this.forwardAndDown(fileIndex, rankIndex, color, false)
|
|
339
|
+
const bU = this.backwardAndUp(fileIndex, rankIndex, color, false)
|
|
340
|
+
const bD = this.backwardAndDown(fileIndex, rankIndex, color, false)
|
|
303
341
|
|
|
304
342
|
return [...u, ...d, ...l, ...r, ...fU, ...fD, ...bU, ...bD]
|
|
305
343
|
}
|
|
@@ -307,19 +345,19 @@ class Game {
|
|
|
307
345
|
/**
|
|
308
346
|
* Returns the possible moves for a queen
|
|
309
347
|
*/
|
|
310
|
-
possibleKingMoves
|
|
348
|
+
possibleKingMoves(king, color) {
|
|
311
349
|
// go into all diagonal directions until there's no place or there's a capture or there's a block
|
|
312
350
|
const fileIndex = this.board.files.indexOf(king.pos[0])
|
|
313
351
|
const rankIndex = this.board.ranks.indexOf(king.pos[1])
|
|
314
|
-
|
|
315
|
-
const u = this.up(fileIndex, rankIndex, true)
|
|
316
|
-
const d = this.down(fileIndex, rankIndex, true)
|
|
317
|
-
const l = this.left(fileIndex, rankIndex, true)
|
|
318
|
-
const r = this.right(fileIndex, rankIndex, true)
|
|
319
|
-
const fU = this.forwardAndUp(fileIndex, rankIndex, true)
|
|
320
|
-
const fD = this.forwardAndDown(fileIndex, rankIndex, true)
|
|
321
|
-
const bU = this.backwardAndUp(fileIndex, rankIndex, true)
|
|
322
|
-
const bD = this.backwardAndDown(fileIndex, rankIndex, true)
|
|
352
|
+
|
|
353
|
+
const u = this.up(fileIndex, rankIndex, color, true)
|
|
354
|
+
const d = this.down(fileIndex, rankIndex, color, true)
|
|
355
|
+
const l = this.left(fileIndex, rankIndex, color, true)
|
|
356
|
+
const r = this.right(fileIndex, rankIndex, color, true)
|
|
357
|
+
const fU = this.forwardAndUp(fileIndex, rankIndex, color, true)
|
|
358
|
+
const fD = this.forwardAndDown(fileIndex, rankIndex, color, true)
|
|
359
|
+
const bU = this.backwardAndUp(fileIndex, rankIndex, color, true)
|
|
360
|
+
const bD = this.backwardAndDown(fileIndex, rankIndex, color, true)
|
|
323
361
|
|
|
324
362
|
return [...u, ...d, ...l, ...r, ...fU, ...fD, ...bU, ...bD]
|
|
325
363
|
}
|
|
@@ -330,17 +368,24 @@ class Game {
|
|
|
330
368
|
* 1. To determine the next moves for a person playing
|
|
331
369
|
* 2. To check if the next move will be checking the opponent's king
|
|
332
370
|
*/
|
|
333
|
-
forwardAndUp
|
|
371
|
+
forwardAndUp(fileIndex, rankIndex, color, king) {
|
|
334
372
|
const possible = []
|
|
335
373
|
let fi = fileIndex + 1
|
|
336
374
|
let ri = rankIndex + 1
|
|
337
375
|
|
|
338
376
|
let nextPosition = [this.board.files[fi], this.board.ranks[ri]]
|
|
339
|
-
|
|
340
|
-
while (
|
|
341
|
-
|
|
377
|
+
|
|
378
|
+
while (
|
|
379
|
+
this.movePotential(nextPosition, color, true) !== "blocked" &&
|
|
380
|
+
this.movePotential(nextPosition, color, true) !== "impossible"
|
|
381
|
+
) {
|
|
382
|
+
if (this.movePotential(nextPosition, color, true) === "check") {
|
|
383
|
+
nextPosition.push('check')
|
|
384
|
+
possible.push(nextPosition)
|
|
385
|
+
break
|
|
386
|
+
}
|
|
342
387
|
possible.push(nextPosition)
|
|
343
|
-
if (this.movePotential(nextPosition, true) ===
|
|
388
|
+
if (this.movePotential(nextPosition, color, true) === "capture" || king) break
|
|
344
389
|
fi++
|
|
345
390
|
ri++
|
|
346
391
|
nextPosition = [this.board.files[fi], this.board.ranks[ri]]
|
|
@@ -352,17 +397,24 @@ class Game {
|
|
|
352
397
|
/**
|
|
353
398
|
* Returns the possible moves on a diagonal going right and down
|
|
354
399
|
*/
|
|
355
|
-
forwardAndDown
|
|
400
|
+
forwardAndDown(fileIndex, rankIndex, color, king) {
|
|
356
401
|
const possible = []
|
|
357
402
|
let fi = fileIndex + 1
|
|
358
403
|
let ri = rankIndex + -1
|
|
359
|
-
|
|
404
|
+
|
|
360
405
|
let nextPosition = [this.board.files[fi], this.board.ranks[ri]]
|
|
361
|
-
|
|
362
|
-
while (
|
|
363
|
-
|
|
406
|
+
|
|
407
|
+
while (
|
|
408
|
+
this.movePotential(nextPosition, color, true) !== "blocked" &&
|
|
409
|
+
this.movePotential(nextPosition, color, true) !== "impossible"
|
|
410
|
+
) {
|
|
411
|
+
if (this.movePotential(nextPosition, color, true) === "check") {
|
|
412
|
+
nextPosition.push('check')
|
|
413
|
+
possible.push(nextPosition)
|
|
414
|
+
break
|
|
415
|
+
}
|
|
364
416
|
possible.push(nextPosition)
|
|
365
|
-
if (this.movePotential(nextPosition, true) ===
|
|
417
|
+
if (this.movePotential(nextPosition, color, true) === "capture" || king) break
|
|
366
418
|
fi++
|
|
367
419
|
ri--
|
|
368
420
|
nextPosition = [this.board.files[fi], this.board.ranks[ri]]
|
|
@@ -373,17 +425,24 @@ class Game {
|
|
|
373
425
|
/**
|
|
374
426
|
* Returns the possible moves on a diagonal going left and up
|
|
375
427
|
*/
|
|
376
|
-
backwardAndUp
|
|
428
|
+
backwardAndUp(fileIndex, rankIndex, color, king) {
|
|
377
429
|
const possible = []
|
|
378
430
|
let fi = fileIndex - 1
|
|
379
431
|
let ri = rankIndex + 1
|
|
380
432
|
|
|
381
433
|
let nextPosition = [this.board.files[fi], this.board.ranks[ri]]
|
|
382
|
-
|
|
383
|
-
while (
|
|
384
|
-
|
|
434
|
+
|
|
435
|
+
while (
|
|
436
|
+
this.movePotential(nextPosition, color, true) !== "blocked" &&
|
|
437
|
+
this.movePotential(nextPosition, color, true) !== "impossible"
|
|
438
|
+
) {
|
|
439
|
+
if (this.movePotential(nextPosition, color, true) === "check") {
|
|
440
|
+
nextPosition.push('check')
|
|
441
|
+
possible.push(nextPosition)
|
|
442
|
+
break
|
|
443
|
+
}
|
|
385
444
|
possible.push(nextPosition)
|
|
386
|
-
if (this.movePotential(nextPosition, true) ===
|
|
445
|
+
if (this.movePotential(nextPosition, color, true) === "capture" || king) break
|
|
387
446
|
fi--
|
|
388
447
|
ri++
|
|
389
448
|
nextPosition = [this.board.files[fi], this.board.ranks[ri]]
|
|
@@ -394,17 +453,24 @@ class Game {
|
|
|
394
453
|
/**
|
|
395
454
|
* Returns the possible moves on a diagonal going left and down
|
|
396
455
|
*/
|
|
397
|
-
backwardAndDown
|
|
456
|
+
backwardAndDown(fileIndex, rankIndex, color, king) {
|
|
398
457
|
const possible = []
|
|
399
458
|
let fi = fileIndex - 1
|
|
400
459
|
let ri = rankIndex - 1
|
|
401
460
|
|
|
402
461
|
let nextPosition = [this.board.files[fi], this.board.ranks[ri]]
|
|
403
|
-
|
|
404
|
-
while (
|
|
405
|
-
|
|
462
|
+
|
|
463
|
+
while (
|
|
464
|
+
this.movePotential(nextPosition, color, true) !== "blocked" &&
|
|
465
|
+
this.movePotential(nextPosition, color, true) !== "impossible"
|
|
466
|
+
) {
|
|
467
|
+
if (this.movePotential(nextPosition, color, true) === "check") {
|
|
468
|
+
nextPosition.push('check')
|
|
469
|
+
possible.push(nextPosition)
|
|
470
|
+
break
|
|
471
|
+
}
|
|
406
472
|
possible.push(nextPosition)
|
|
407
|
-
if (this.movePotential(nextPosition, true) ===
|
|
473
|
+
if (this.movePotential(nextPosition, color, true) === "capture" || king) break
|
|
408
474
|
fi--
|
|
409
475
|
ri--
|
|
410
476
|
nextPosition = [this.board.files[fi], this.board.ranks[ri]]
|
|
@@ -415,16 +481,23 @@ class Game {
|
|
|
415
481
|
/**
|
|
416
482
|
* Returns the possible moves on a file going up
|
|
417
483
|
*/
|
|
418
|
-
up
|
|
484
|
+
up(fileIndex, rankIndex, color, king) {
|
|
419
485
|
const possible = []
|
|
420
486
|
let ri = rankIndex + 1
|
|
421
487
|
|
|
422
488
|
let nextPosition = [this.board.files[fileIndex], this.board.ranks[ri]]
|
|
423
|
-
|
|
424
|
-
while (
|
|
425
|
-
|
|
489
|
+
|
|
490
|
+
while (
|
|
491
|
+
this.movePotential(nextPosition, color, true) !== "blocked" &&
|
|
492
|
+
this.movePotential(nextPosition, color, true) !== "impossible"
|
|
493
|
+
) {
|
|
494
|
+
if (this.movePotential(nextPosition, color, true) === "check") {
|
|
495
|
+
nextPosition.push('check')
|
|
496
|
+
possible.push(nextPosition)
|
|
497
|
+
break
|
|
498
|
+
}
|
|
426
499
|
possible.push(nextPosition)
|
|
427
|
-
if (this.movePotential(nextPosition, true) ===
|
|
500
|
+
if (this.movePotential(nextPosition, color, true) === "capture" || king) break
|
|
428
501
|
ri++
|
|
429
502
|
nextPosition = [this.board.files[fileIndex], this.board.ranks[ri]]
|
|
430
503
|
}
|
|
@@ -434,16 +507,23 @@ class Game {
|
|
|
434
507
|
/**
|
|
435
508
|
* Returns the possible moves on a file going down
|
|
436
509
|
*/
|
|
437
|
-
down
|
|
510
|
+
down(fileIndex, rankIndex, color, king) {
|
|
438
511
|
const possible = []
|
|
439
512
|
let ri = rankIndex - 1
|
|
440
513
|
|
|
441
514
|
let nextPosition = [this.board.files[fileIndex], this.board.ranks[ri]]
|
|
442
|
-
|
|
443
|
-
while (
|
|
444
|
-
|
|
515
|
+
|
|
516
|
+
while (
|
|
517
|
+
this.movePotential(nextPosition, color, true) !== "blocked" &&
|
|
518
|
+
this.movePotential(nextPosition, color, true) !== "impossible"
|
|
519
|
+
) {
|
|
520
|
+
if (this.movePotential(nextPosition, color, true) === "check") {
|
|
521
|
+
nextPosition.push('check')
|
|
522
|
+
possible.push(nextPosition)
|
|
523
|
+
break
|
|
524
|
+
}
|
|
445
525
|
possible.push(nextPosition)
|
|
446
|
-
if (this.movePotential(nextPosition, true) ===
|
|
526
|
+
if (this.movePotential(nextPosition, color, true) === "capture" || king) break
|
|
447
527
|
ri--
|
|
448
528
|
nextPosition = [this.board.files[fileIndex], this.board.ranks[ri]]
|
|
449
529
|
}
|
|
@@ -453,16 +533,23 @@ class Game {
|
|
|
453
533
|
/**
|
|
454
534
|
* Returns the possible moves on a rank going left
|
|
455
535
|
*/
|
|
456
|
-
left
|
|
536
|
+
left(fileIndex, rankIndex, color, king) {
|
|
457
537
|
const possible = []
|
|
458
538
|
let fi = fileIndex - 1
|
|
459
539
|
|
|
460
540
|
let nextPosition = [this.board.files[fi], this.board.ranks[rankIndex]]
|
|
461
|
-
|
|
462
|
-
while (
|
|
463
|
-
|
|
541
|
+
|
|
542
|
+
while (
|
|
543
|
+
this.movePotential(nextPosition, color, true) !== "blocked" &&
|
|
544
|
+
this.movePotential(nextPosition, color, true) !== "impossible"
|
|
545
|
+
) {
|
|
546
|
+
if (this.movePotential(nextPosition, color, true) === "check") {
|
|
547
|
+
nextPosition.push('check')
|
|
548
|
+
possible.push(nextPosition)
|
|
549
|
+
break
|
|
550
|
+
}
|
|
464
551
|
possible.push(nextPosition)
|
|
465
|
-
if (this.movePotential(nextPosition, true) ===
|
|
552
|
+
if (this.movePotential(nextPosition, color, true) === "capture" || king) break
|
|
466
553
|
fi--
|
|
467
554
|
nextPosition = [this.board.files[fi], this.board.ranks[rankIndex]]
|
|
468
555
|
}
|
|
@@ -472,16 +559,23 @@ class Game {
|
|
|
472
559
|
/**
|
|
473
560
|
* Returns the possible moves on a rank going right
|
|
474
561
|
*/
|
|
475
|
-
right
|
|
562
|
+
right(fileIndex, rankIndex, color, king) {
|
|
476
563
|
const possible = []
|
|
477
564
|
let fi = fileIndex + 1
|
|
478
565
|
|
|
479
566
|
let nextPosition = [this.board.files[fi], this.board.ranks[rankIndex]]
|
|
480
|
-
|
|
481
|
-
while (
|
|
482
|
-
|
|
567
|
+
|
|
568
|
+
while (
|
|
569
|
+
this.movePotential(nextPosition, color, true) !== "blocked" &&
|
|
570
|
+
this.movePotential(nextPosition, color, true) !== "impossible"
|
|
571
|
+
) {
|
|
572
|
+
if (this.movePotential(nextPosition, color, true) === "check") {
|
|
573
|
+
nextPosition.push('check')
|
|
574
|
+
possible.push(nextPosition)
|
|
575
|
+
break
|
|
576
|
+
}
|
|
483
577
|
possible.push(nextPosition)
|
|
484
|
-
if (this.movePotential(nextPosition, true) ===
|
|
578
|
+
if (this.movePotential(nextPosition, color, true) === "capture" || king) break
|
|
485
579
|
fi++
|
|
486
580
|
nextPosition = [this.board.files[fi], this.board.ranks[rankIndex]]
|
|
487
581
|
}
|
|
@@ -491,8 +585,10 @@ class Game {
|
|
|
491
585
|
/**
|
|
492
586
|
* Returns the possible ranks from the possiblemoves function
|
|
493
587
|
*/
|
|
494
|
-
possibleFiles
|
|
495
|
-
const possible = this.possibleMoves(this.selectedPiece).map(
|
|
588
|
+
possibleFiles() {
|
|
589
|
+
const possible = this.possibleMoves(this.selectedPiece, this.toMove).map(pos => {
|
|
590
|
+
return pos[0]
|
|
591
|
+
})
|
|
496
592
|
/** Filter unique */
|
|
497
593
|
return [...new Set(possible)]
|
|
498
594
|
}
|
|
@@ -500,12 +596,16 @@ class Game {
|
|
|
500
596
|
/**
|
|
501
597
|
* Returns the possible ranks from the possiblemoves function
|
|
502
598
|
*/
|
|
503
|
-
possibleRanks
|
|
504
|
-
const possible = this.possibleMoves(this.selectedPiece
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
599
|
+
possibleRanks() {
|
|
600
|
+
const possible = this.possibleMoves(this.selectedPiece, this.toMove)
|
|
601
|
+
.filter(move => {
|
|
602
|
+
if (move[0] === this.selectedFile) {
|
|
603
|
+
return move[1]
|
|
604
|
+
}
|
|
605
|
+
})
|
|
606
|
+
.map(pos => {
|
|
607
|
+
return pos[1].toString()
|
|
608
|
+
})
|
|
509
609
|
/** Filter unique */
|
|
510
610
|
return [...new Set(possible)]
|
|
511
611
|
}
|
|
@@ -515,7 +615,7 @@ class Game {
|
|
|
515
615
|
* 2. TODO: Check check
|
|
516
616
|
* 3. TODO: Check checkmate
|
|
517
617
|
*/
|
|
518
|
-
async validateMove
|
|
618
|
+
async validateMove() {
|
|
519
619
|
// Commit the move to update the board
|
|
520
620
|
this.processCapture()
|
|
521
621
|
await this.promptPromotion()
|
|
@@ -524,85 +624,56 @@ class Game {
|
|
|
524
624
|
|
|
525
625
|
/**
|
|
526
626
|
* Allowed configures the check to consider if a capture may be made
|
|
527
|
-
* If it is true,
|
|
627
|
+
* If it is true,
|
|
528
628
|
* Returns 'capture' if there is an opposing piece at the given position
|
|
529
629
|
* Returns 'check' if the opposing piece at the given position is a king
|
|
530
630
|
* Returns 'blocked' if there is an own piece or 'possible' for no piece at the given position
|
|
531
631
|
*/
|
|
532
|
-
movePotential
|
|
533
|
-
if (pos[0] === undefined || pos[1] === undefined) {
|
|
632
|
+
movePotential(pos, color, allowed) {
|
|
633
|
+
if (pos[0] === undefined || pos[1] === undefined) {
|
|
634
|
+
return "impossible"
|
|
635
|
+
}
|
|
534
636
|
|
|
535
|
-
const opponentsPieces =
|
|
637
|
+
const opponentsPieces =
|
|
638
|
+
this.board[this.utils.opposingColor(color)].pieces
|
|
536
639
|
|
|
537
|
-
const ownPiece = this.board[
|
|
640
|
+
const ownPiece = this.board[color].pieces.find(piece => {
|
|
538
641
|
return piece.pos[0] === pos[0] && piece.pos[1] === pos[1]
|
|
539
642
|
})
|
|
540
|
-
const opponentsPiece = opponentsPieces.find(
|
|
643
|
+
const opponentsPiece = opponentsPieces.find(piece => {
|
|
541
644
|
return piece.pos[0] === pos[0] && piece.pos[1] === pos[1]
|
|
542
645
|
})
|
|
543
646
|
|
|
544
647
|
if (opponentsPiece && allowed) {
|
|
545
|
-
if (opponentsPiece.type ===
|
|
546
|
-
return
|
|
648
|
+
if (opponentsPiece.type === "King") {
|
|
649
|
+
return "check"
|
|
547
650
|
} else {
|
|
548
|
-
return
|
|
651
|
+
return "capture"
|
|
549
652
|
}
|
|
550
653
|
}
|
|
551
|
-
if (ownPiece && allowed) {
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
// * Returns check if the opponents piece in the way gives a check
|
|
562
|
-
// */
|
|
563
|
-
// checkPotential (pos, direction) {
|
|
564
|
-
// if (pos[0] === undefined || pos[1] === undefined) { return 'impossible' }
|
|
565
|
-
|
|
566
|
-
// const ownPiece = this.board[this.toMove].pieces.find((piece) => {
|
|
567
|
-
// return piece.pos[0] === pos[0] && piece.pos[1] === pos[1]
|
|
568
|
-
// })
|
|
569
|
-
// const opponentsPiece = opponentsPieces.find((piece) => {
|
|
570
|
-
// return piece.pos[0] === pos[0] && piece.pos[1] === pos[1]
|
|
571
|
-
// })
|
|
572
|
-
|
|
573
|
-
// if (ownPiece) { return 'blocked' }
|
|
574
|
-
// if (!ownPiece && !opponentsPiece) { return 'empty' }
|
|
575
|
-
// if (opponentsPiece) {
|
|
576
|
-
// // There is an opposing piece on this square.
|
|
577
|
-
// switch (direction) {
|
|
578
|
-
// case ('up'):
|
|
579
|
-
// switch (opponentsPiece.type) {
|
|
580
|
-
// case ('Pawn'):
|
|
581
|
-
// return 'blocked'
|
|
582
|
-
// case ('Knight'):
|
|
583
|
-
// return 'blocked'
|
|
584
|
-
// case ('Bishop'):
|
|
585
|
-
// return
|
|
586
|
-
// case ('Rook'):
|
|
587
|
-
// return
|
|
588
|
-
// case ('Queen'):
|
|
589
|
-
// return
|
|
590
|
-
// case ('King'):
|
|
591
|
-
// return 'impossible'
|
|
592
|
-
// }
|
|
593
|
-
// }
|
|
594
|
-
// }
|
|
595
|
-
// }
|
|
654
|
+
if (ownPiece && allowed) {
|
|
655
|
+
return "blocked"
|
|
656
|
+
}
|
|
657
|
+
if (ownPiece || (opponentsPiece && !allowed)) {
|
|
658
|
+
return "blocked"
|
|
659
|
+
}
|
|
660
|
+
if (!ownPiece && !opponentsPiece) {
|
|
661
|
+
return "possible"
|
|
662
|
+
}
|
|
663
|
+
}
|
|
596
664
|
|
|
597
665
|
/**
|
|
598
666
|
* Processes a capture.
|
|
599
667
|
* 1. Checks for capture
|
|
600
668
|
* 2. If capture, set the piece status to captured
|
|
601
669
|
*/
|
|
602
|
-
processCapture
|
|
603
|
-
const opponentsPieces =
|
|
604
|
-
|
|
605
|
-
|
|
670
|
+
processCapture() {
|
|
671
|
+
const opponentsPieces =
|
|
672
|
+
this.board[this.utils.opposingColor(this.toMove)].pieces
|
|
673
|
+
const capturedPiece = opponentsPieces.find(piece => {
|
|
674
|
+
return (
|
|
675
|
+
piece.pos[0] === this.selectedFile && piece.pos[1] === this.selectedRank
|
|
676
|
+
)
|
|
606
677
|
})
|
|
607
678
|
if (capturedPiece) {
|
|
608
679
|
capturedPiece.captured = true
|
|
@@ -614,70 +685,63 @@ class Game {
|
|
|
614
685
|
* 1. Asks user which piece to promote to
|
|
615
686
|
* 2. Sets said piece to its new values
|
|
616
687
|
*/
|
|
617
|
-
async promptPromotion
|
|
618
|
-
if (
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
688
|
+
async promptPromotion() {
|
|
689
|
+
if (
|
|
690
|
+
(this.selectedPiece.type === "Pawn" &&
|
|
691
|
+
this.toMove === "white" &&
|
|
692
|
+
this.selectedRank === 8) ||
|
|
693
|
+
(this.selectedPiece.type === "Pawn" &&
|
|
694
|
+
this.toMove === "black" &&
|
|
695
|
+
this.selectedRank === 1)
|
|
696
|
+
) {
|
|
697
|
+
await this.enquirer
|
|
698
|
+
.prompt({
|
|
699
|
+
type: "select",
|
|
700
|
+
name: "promotion",
|
|
701
|
+
message: "Promote to:",
|
|
702
|
+
choices: this.board[this.toMove].promotionChoices.map(choice => {
|
|
703
|
+
return choice.piece
|
|
704
|
+
}),
|
|
705
|
+
result: piece => {
|
|
706
|
+
const promotionChoice = this.board[
|
|
707
|
+
this.toMove
|
|
708
|
+
].promotionChoices.find(choice => {
|
|
709
|
+
return choice.piece === piece
|
|
710
|
+
})
|
|
711
|
+
const selectedPiece = this.getSelectedPiece()
|
|
712
|
+
selectedPiece.piece = piece
|
|
713
|
+
selectedPiece.type = promotionChoice.type
|
|
714
|
+
selectedPiece.prefix = promotionChoice.prefix
|
|
715
|
+
selectedPiece.value = promotionChoice.piece
|
|
716
|
+
return selectedPiece
|
|
717
|
+
},
|
|
718
|
+
})
|
|
719
|
+
.catch(console.error)
|
|
636
720
|
}
|
|
637
721
|
}
|
|
638
722
|
|
|
639
|
-
|
|
640
723
|
/**
|
|
641
|
-
*
|
|
724
|
+
* Check master function. Is run right before passTurn and board.render
|
|
642
725
|
*/
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
726
|
+
checkForCheck() {
|
|
727
|
+
// If the opponent's checks length is > 0, that means you're in check
|
|
728
|
+
const opponent = this.utils.opposingColor(this.toMove)
|
|
729
|
+
const opponentsChecks = this.allPossibleChecks(opponent)
|
|
646
730
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
}
|
|
653
|
-
ri++
|
|
654
|
-
nextPosition = [this.board.files[fileIndex], this.board.ranks[ri]]
|
|
731
|
+
if (opponentsChecks.length > 0) {
|
|
732
|
+
this.board[this.toMove].inCheck = true
|
|
733
|
+
} else {
|
|
734
|
+
this.board[this.toMove].inCheck = false
|
|
735
|
+
this.board[opponent].inCheck = false
|
|
655
736
|
}
|
|
656
|
-
return checks
|
|
657
|
-
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
/**
|
|
661
|
-
* Looks from the perspective of the king if he is being seen by any of the other player's pieces.
|
|
662
|
-
*/
|
|
663
|
-
getChecks () {
|
|
664
|
-
// return [...u]
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/**
|
|
668
|
-
* Check master function. Is run right before passTurn and board.render
|
|
669
|
-
*/
|
|
670
|
-
setCheck () {
|
|
671
|
-
const checks = this.getChecks()
|
|
672
|
-
// List the possible moves that put the king in check. If the array remains length 0, do nothing. Otherwise, set the king in check
|
|
673
737
|
}
|
|
674
738
|
|
|
675
739
|
/**
|
|
676
740
|
* Passes the turn to the other player by setting the toMove var and prompting the next move
|
|
677
741
|
*/
|
|
678
|
-
passTurn
|
|
679
|
-
this.toMove ===
|
|
680
|
-
this.
|
|
742
|
+
passTurn() {
|
|
743
|
+
this.toMove = this.toMove === "white" ? "black" : "white"
|
|
744
|
+
this.checkForCheck()
|
|
681
745
|
this.promptPieceSelection()
|
|
682
746
|
}
|
|
683
747
|
|
|
@@ -688,7 +752,7 @@ class Game {
|
|
|
688
752
|
* 3. Passes the turn to the other player
|
|
689
753
|
* 4. Renders the board
|
|
690
754
|
*/
|
|
691
|
-
commitMove
|
|
755
|
+
commitMove() {
|
|
692
756
|
this.getSelectedPiece().pos = [this.selectedFile, this.selectedRank]
|
|
693
757
|
this.commitToHistory()
|
|
694
758
|
this.passTurn()
|
|
@@ -699,25 +763,26 @@ class Game {
|
|
|
699
763
|
/**
|
|
700
764
|
* Pushes move to history
|
|
701
765
|
*/
|
|
702
|
-
commitToHistory
|
|
703
|
-
}
|
|
766
|
+
commitToHistory() {}
|
|
704
767
|
|
|
705
768
|
/**
|
|
706
769
|
* Returns a list of available pieces for the prompt
|
|
707
770
|
*/
|
|
708
|
-
listAvailablePieces
|
|
709
|
-
return this.board[this.toMove].pieces
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
771
|
+
listAvailablePieces() {
|
|
772
|
+
return this.board[this.toMove].pieces
|
|
773
|
+
.filter(piece => {
|
|
774
|
+
return !piece.captured && this.possibleMoves(piece, this.toMove).length > 0
|
|
775
|
+
})
|
|
776
|
+
.map(piece => {
|
|
777
|
+
return `${piece.piece} (${piece.pos})`
|
|
778
|
+
})
|
|
714
779
|
}
|
|
715
780
|
|
|
716
781
|
/**
|
|
717
782
|
* Sets the given piece as selected for this move
|
|
718
783
|
*/
|
|
719
|
-
setSelectedPiece
|
|
720
|
-
const selection = this.board[this.toMove].pieces.find(
|
|
784
|
+
setSelectedPiece(piece) {
|
|
785
|
+
const selection = this.board[this.toMove].pieces.find(p => {
|
|
721
786
|
return p.pos[0] === piece[3] && p.pos[1] === Number(piece[5])
|
|
722
787
|
})
|
|
723
788
|
this.selectedPiece = selection
|
|
@@ -726,46 +791,54 @@ class Game {
|
|
|
726
791
|
/**
|
|
727
792
|
* Sets the given file as selected for this move
|
|
728
793
|
*/
|
|
729
|
-
setSelectedFile
|
|
794
|
+
setSelectedFile(file) {
|
|
730
795
|
this.selectedFile = file
|
|
731
796
|
}
|
|
732
797
|
|
|
733
798
|
/**
|
|
734
799
|
* Sets the given rank as selected for this move
|
|
735
800
|
*/
|
|
736
|
-
setSelectedRank
|
|
801
|
+
setSelectedRank(rank) {
|
|
737
802
|
this.selectedRank = rank
|
|
738
803
|
}
|
|
739
804
|
|
|
740
805
|
/**
|
|
741
806
|
* Get the current player's piece
|
|
742
807
|
*/
|
|
743
|
-
getPiece
|
|
744
|
-
return this.board[this.toMove].pieces.find(
|
|
808
|
+
getPiece(type) {
|
|
809
|
+
return this.board[this.toMove].pieces.find(piece => {
|
|
810
|
+
return piece.type === type
|
|
811
|
+
})
|
|
745
812
|
}
|
|
746
813
|
|
|
747
814
|
/**
|
|
748
815
|
* Get the opponent's piece
|
|
749
816
|
*/
|
|
750
|
-
getOpponentsPiece
|
|
751
|
-
return this.board[this.utils.
|
|
817
|
+
getOpponentsPiece(type) {
|
|
818
|
+
return this.board[this.utils.opposingColor(this.toMove)].pieces.find(
|
|
819
|
+
piece => {
|
|
820
|
+
return piece.type === type
|
|
821
|
+
}
|
|
822
|
+
)
|
|
752
823
|
}
|
|
753
824
|
|
|
754
825
|
/**
|
|
755
826
|
* returns the selected piece for this move
|
|
756
827
|
*/
|
|
757
|
-
getSelectedPiece
|
|
758
|
-
return this.board[this.toMove].pieces.find(piece => {
|
|
828
|
+
getSelectedPiece() {
|
|
829
|
+
return this.board[this.toMove].pieces.find(piece => {
|
|
830
|
+
return piece === this.selectedPiece
|
|
831
|
+
})
|
|
759
832
|
}
|
|
760
833
|
|
|
761
834
|
/**
|
|
762
835
|
* Um Gottes Wille, nicht!
|
|
763
836
|
*/
|
|
764
|
-
init
|
|
837
|
+
init() {
|
|
765
838
|
this.board.clear()
|
|
766
839
|
this.board.render()
|
|
767
840
|
this.promptPieceSelection()
|
|
768
841
|
}
|
|
769
842
|
}
|
|
770
843
|
|
|
771
|
-
module.exports = Game
|
|
844
|
+
module.exports = Game
|