});
this.amoves.push(move);
}
- this.subTurn = 1;
// Stack "first moves" (on subTurn 1) to merge and check opposite moves
this.firstMove = [];
}
}
const getPullExit = () => {
// Piece at subTurn 1 exited: can I be pulled?
- // Note: pawns and kings cannot suicide,
- // so fm.vanish[0].p is neither PAWN or KING
+ // Note: kings cannot suicide, so fm.vanish[0].p is not KING.
+ // Could be PAWN though, if a pawn was pushed out of board.
if (
+ fm.vanish[0].p != V.PAWN && //pawns cannot pull
this.isAprioriValidExit(
[x, y],
[fm.start.x, fm.start.y],
filterValid(moves) {
const color = this.turn;
+ const La = this.amoves.length;
if (this.subTurn == 1) {
return moves.filter(m => {
// A move is valid either if it doesn't result in a check,
// (not undoing a potential move + action of the opponent)
this.play(m);
let res = this.underCheck(color);
- if (res) {
+ let isOpposite = La > 0 && this.oppositeMoves(this.amoves[La-1], m);
+ if (res || isOpposite) {
const moves2 = this.getAllPotentialMoves();
for (let m2 of moves2) {
this.play(m2);
const res2 = this.underCheck(color);
+ const amove = this.getAmove(m, m2);
+ isOpposite =
+ La > 0 && this.oppositeMoves(this.amoves[La-1], amove);
this.undo(m2);
- if (!res2) {
+ if (!res2 && !isOpposite) {
res = false;
break;
}
return !res;
});
}
- const Lf = this.firstMove.length;
- const La = this.amoves.length;
if (La == 0) return super.filterValid(moves);
+ const Lf = this.firstMove.length;
return (
super.filterValid(
moves.filter(m => {
const pawnShift = (color == "w" ? 1 : -1);
for (let i of [-1, 1]) {
if (
- y + i >= 0 &&
- y + i < V.size.y &&
+ V.OnBoard(x + pawnShift, y + i) &&
+ this.board[x + pawnShift][y + i] != V.EMPTY &&
this.getPiece(x + pawnShift, y + i) == V.PAWN &&
this.getColor(x + pawnShift, y + i) == color
) {
- return !V.OnBoard(x - pawnShift, y - i);
+ if (!V.OnBoard(x - pawnShift, y - i)) return true;
+ }
+ }
+ return false;
+ }
+
+ static OnTheEdge(x, y) {
+ return (x == 0 || x == 7 || y == 0 || y == 7);
+ }
+
+ isAttackedByKing([x, y], color) {
+ // Attacked if I'm on the edge and the opponent king just next,
+ // but not on the edge.
+ if (V.OnTheEdge(x, y)) {
+ for (let step of V.steps[V.ROOK].concat(V.steps[V.BISHOP])) {
+ const [i, j] = [x + step[0], y + step[1]];
+ if (
+ V.OnBoard(i, j) &&
+ !V.OnTheEdge(i, j) &&
+ this.board[i][j] != V.EMPTY &&
+ this.getPiece(i, j) == V.KING
+ // NOTE: since only one king of each color, and (x, y) is occupied
+ // by our king, no need to check other king's color.
+ ) {
+ return true;
+ }
}
}
return false;
return potentialMoves;
}
- getCurrentScore() {
- if (this.subTurn == 2)
- // Move not over
- return "*";
- return super.getCurrentScore();
- }
-
doClick(square) {
// A click to promote a piece on subTurn 2 would trigger this.
// For now it would then return [NaN, NaN] because surrounding squares
// have no IDs in the promotion modal. TODO: improve this?
- if (!square[0]) return null;
- // If subTurn == 2 && square is empty && !underCheck,
+ if (isNaN(square[0])) return null;
+ // If subTurn == 2 && square is empty && !underCheck && !isOpposite,
// then return an empty move, allowing to "pass" subTurn2
+ const La = this.amoves.length;
+ const Lf = this.firstMove.length;
if (
this.subTurn == 2 &&
this.board[square[0]][square[1]] == V.EMPTY &&
- !this.underCheck(this.turn)
+ !this.underCheck(this.turn) &&
+ (La == 0 || !this.oppositeMoves(this.amoves[La-1], this.firstMove[Lf-1]))
) {
return {
start: { x: -1, y: -1 },
this.disaggregateFlags(JSON.parse(move.flags));
V.UndoOnBoard(this.board, move);
if (this.subTurn == 1) {
+ this.amoves.pop();
this.turn = V.GetOppCol(this.turn);
this.movesCount--;
}