static get PawnSpecs() {
return {
directions: { 'w': -1, 'b': 1 },
+ initShift: { w: 1, b: 1 },
twoSquares: true,
+ threeSquares: false,
promotions: [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN],
canCapture: true,
captureBackward: false,
return V.CanFlip;
}
+ // Some variants use click infos:
+ doClick() {
+ return null;
+ }
+
static get IMAGE_EXTENSION() {
// All pieces should be in the SVG format
return ".svg";
return !!flags.match(/^[a-z]{4,4}$/);
}
+ // NOTE: not with regexp to adapt to different board sizes. (TODO?)
static IsGoodEnpassant(enpassant) {
if (enpassant != "-") {
const ep = V.SquareToCoords(enpassant);
const [sizeX, sizeY] = [V.size.x, V.size.y];
const pawnShiftX = V.PawnSpecs.directions[color];
const firstRank = (color == "w" ? sizeX - 1 : 0);
- const startRank = (color == "w" ? sizeX - 2 : 1);
// Pawn movements in shiftX direction:
const getPawnMoves = (shiftX) => {
// Next condition because pawns on 1st rank can generally jump
if (
V.PawnSpecs.twoSquares &&
- [startRank, firstRank].includes(x) &&
- this.board[x + 2 * shiftX][y] == V.EMPTY
+ (
+ (color == 'w' && x >= V.size.x - 1 - V.PawnSpecs.initShift['w'])
+ ||
+ (color == 'b' && x <= V.PawnSpecs.initShift['b'])
+ )
) {
- // Two squares jump
- moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
+ if (this.board[x + 2 * shiftX][y] == V.EMPTY) {
+ // Two squares jump
+ moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
+ if (
+ V.PawnSpecs.threeSquares &&
+ this.board[x + 3 * shiftX][y] == V.EMPTY
+ ) {
+ // Three squares jump
+ moves.push(this.getBasicMove([x, y], [x + 3 * shiftX, y]));
+ }
+ }
}
}
// Captures
// NOTE: in some variants this is not a rook
const rookPos = this.castleFlags[c][castleSide];
- const castlingPiece = this.getPiece(x, rookPos);
- if (this.getColor(x, rookPos) != c)
- // Rook is here but changed color (see Benedict)
+ if (this.board[x][rookPos] == V.EMPTY || this.getColor(x, rookPos) != c)
+ // Rook is not here, or changed color (see Benedict)
continue;
// Nothing on the path of the king ? (and no checks)
+ const castlingPiece = this.getPiece(x, rookPos);
const finDist = finalSquares[castleSide][0] - y;
let step = finDist / Math.max(1, Math.abs(finDist));
i = y;
do {
if (
- (!castleInCheck && this.isAttacked([x, i], oppCol)) ||
+ // NOTE: "castling" arg is used by some variants (Monster),
+ // where "isAttacked" is overloaded in an infinite-recursive way.
+ (!castleInCheck && this.isAttacked([x, i], oppCol, "castling")) ||
(this.board[x][i] != V.EMPTY &&
// NOTE: next check is enough, because of chessboard constraints
(this.getColor(x, i) != c ||
// Nothing on final squares, except maybe king and castling rook?
for (i = 0; i < 2; i++) {
if (
+ finalSquares[castleSide][i] != rookPos &&
this.board[x][finalSquares[castleSide][i]] != V.EMPTY &&
- this.getPiece(x, finalSquares[castleSide][i]) != V.KING &&
- finalSquares[castleSide][i] != rookPos
+ (
+ this.getPiece(x, finalSquares[castleSide][i]) != V.KING ||
+ this.getColor(x, finalSquares[castleSide][i]) != c
+ )
) {
continue castlingCheck;
}
});
}
- // Search for all valid moves considering current turn
- // (for engine and game end)
- getAllValidMoves() {
+ getAllPotentialMoves() {
const color = this.turn;
let potentialMoves = [];
for (let i = 0; i < V.size.x; i++) {
for (let j = 0; j < V.size.y; j++) {
- if (this.getColor(i, j) == color) {
+ if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) {
Array.prototype.push.apply(
potentialMoves,
this.getPotentialMovesFrom([i, j])
}
}
}
- return this.filterValid(potentialMoves);
+ return potentialMoves;
+ }
+
+ // Search for all valid moves considering current turn
+ // (for engine and game end)
+ getAllValidMoves() {
+ return this.filterValid(this.getAllPotentialMoves());
}
// Stop at the first move found
if (piece == V.KING && move.appear.length > 0) {
this.kingPos[c][0] = move.appear[0].x;
this.kingPos[c][1] = move.appear[0].y;
- return;
}
if (V.HasCastle) this.updateCastleFlags(move, piece);
}