return noCaptures.concat(this.getCastleMoves(sq));
}
+ // No "under check" verifications:
+ getCastleMoves([x, y]) {
+ const c = this.getColor(x, y);
+ if (x != (c == "w" ? V.size.x - 1 : 0) || y != this.INIT_COL_KING[c])
+ return []; //x isn't first rank, or king has moved (shortcut)
+
+ // Castling ?
+ const oppCol = V.GetOppCol(c);
+ let moves = [];
+ let i = 0;
+ // King, then rook:
+ const finalSquares = [
+ [2, 3],
+ [V.size.y - 2, V.size.y - 3]
+ ];
+ castlingCheck: for (
+ let castleSide = 0;
+ castleSide < 2;
+ castleSide++ //large, then small
+ ) {
+ if (this.castleFlags[c][castleSide] >= 8) continue;
+ // If this code is reached, rooks and king are on initial position
+
+ const rookPos = this.castleFlags[c][castleSide];
+ if (this.getColor(x, rookPos) != c)
+ // Rook is here but changed color
+ continue;
+
+ // Nothing on the path of the king ?
+ const finDist = finalSquares[castleSide][0] - y;
+ let step = finDist / Math.max(1, Math.abs(finDist));
+ for (let i = y; i != finalSquares[castleSide][0]; i += step) {
+ if (
+ this.board[x][i] != V.EMPTY &&
+ // NOTE: next check is enough, because of chessboard constraints
+ (this.getColor(x, i) != c ||
+ ![V.KING, V.ROOK].includes(this.getPiece(x, i)))
+ ) {
+ continue castlingCheck;
+ }
+ }
+
+ // Nothing on the path to the rook?
+ step = castleSide == 0 ? -1 : 1;
+ for (i = y + step; i != rookPos; i += step) {
+ if (this.board[x][i] != V.EMPTY) continue castlingCheck;
+ }
+
+ // Nothing on final squares, except maybe king and castling rook?
+ for (i = 0; i < 2; i++) {
+ if (
+ this.board[x][finalSquares[castleSide][i]] != V.EMPTY &&
+ this.getPiece(x, finalSquares[castleSide][i]) != V.KING &&
+ finalSquares[castleSide][i] != rookPos
+ ) {
+ continue castlingCheck;
+ }
+ }
+
+ // If this code is reached, castle is valid
+ moves.push(
+ new Move({
+ appear: [
+ new PiPo({ x: x, y: finalSquares[castleSide][0], p: V.KING, c: c }),
+ new PiPo({ x: x, y: finalSquares[castleSide][1], p: V.ROOK, c: c })
+ ],
+ vanish: [
+ new PiPo({ x: x, y: y, p: V.KING, c: c }),
+ new PiPo({ x: x, y: rookPos, p: V.ROOK, c: c })
+ ],
+ end:
+ Math.abs(y - rookPos) <= 2
+ ? { x: x, y: rookPos }
+ : { x: x, y: y + 2 * (castleSide == 0 ? -1 : 1) }
+ })
+ );
+ }
+
+ return moves;
+ }
+
// TODO: appear/vanish description of a move is too verbose for Benedict.
// => Would need a new "flipped" array, to be passed in Game.vue...
getPotentialMovesFrom([x, y]) {
let moves = super.getPotentialMovesFrom([x, y]);
// Add flips:
moves.forEach(m => {
+ let newAppear = [];
+ let newVanish = [];
V.PlayOnBoard(this.board, m);
- const flipped = this.findCaptures([m.end.x, m.end.y]);
- V.UndoOnBoard(this.board, m);
- flipped.forEach(sq => {
- const piece = this.getPiece(sq[0],sq[1]);
- const pipoA = new PiPo({
- x:sq[0],
- y:sq[1],
- c:color,
- p:piece
+ // If castling, m.appear has 2 elements:
+ m.appear.forEach(a => {
+ const flipped = this.findCaptures([a.x, a.y]);
+ flipped.forEach(sq => {
+ const piece = this.getPiece(sq[0],sq[1]);
+ const pipoA = new PiPo({
+ x:sq[0],
+ y:sq[1],
+ c:color,
+ p:piece
+ });
+ const pipoV = new PiPo({
+ x:sq[0],
+ y:sq[1],
+ c:oppCol,
+ p:piece
+ });
+ newAppear.push(pipoA);
+ newVanish.push(pipoV);
});
- const pipoV = new PiPo({
- x:sq[0],
- y:sq[1],
- c:oppCol,
- p:piece
- });
- m.appear.push(pipoA);
- m.vanish.push(pipoV);
});
+ Array.prototype.push.apply(m.appear, newAppear);
+ Array.prototype.push.apply(m.vanish, newVanish);
+ V.UndoOnBoard(this.board, m);
});
return moves;
}
return [];
}
+ // Stop at the first move found
+ atLeastOneMove() {
+ const color = this.turn;
+ const oppCol = V.GetOppCol(color);
+ for (let i = 0; i < V.size.x; i++) {
+ for (let j = 0; j < V.size.y; j++) {
+ if (this.board[i][j] != V.EMPTY && this.getColor(i, j) != oppCol) {
+ const moves = this.getPotentialMovesFrom([i, j]);
+ if (moves.length > 0)
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
getCurrentScore() {
const color = this.turn;
// Did a king change color?
const kp = this.kingPos[color];
if (this.getColor(kp[0], kp[1]) != color)
return color == "w" ? "0-1" : "1-0";
- return "*";
+ if (this.atLeastOneMove())
+ return "*";
+ // Stalemate:
+ return "1/2";
+ }
+
+ getNotation(move) {
+ // Just remove flips:
+ const basicMove = {
+ appear: [move.appear[0]],
+ vanish: [move.vanish[0]],
+ start: move.start,
+ end: move.end
+ };
+ return super.getNotation(basicMove);
}
};