return true;
}
+ loseOnRepetition() {
+ // If current side is under check: lost
+ return this.underCheck(this.turn);
+ }
+
static IsGoodFen(fen) {
if (!ChessRules.IsGoodFen(fen)) return false;
const fenParsed = V.ParseFen(fen);
);
}
- static GenRandInitFen(randomness) {
- if (randomness == 0) {
+ static GenRandInitFen(options) {
+ if (options.randomness == 0) {
return (
"lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL " +
"w 0 00000000000000"
let pieces1 = { w: new Array(4), b: new Array(4) };
let positions2 = { w: new Array(2), b: new Array(2) };
for (let c of ["w", "b"]) {
- if (c == 'b' && randomness == 1) {
+ if (c == 'b' && options.randomness == 1) {
pieces1['b'] = JSON.parse(JSON.stringify(pieces1['w'])).reverse();
positions2['b'] =
JSON.parse(JSON.stringify(positions2['w'])).reverse()
if (p == V.PAWN) {
// Do not drop on checkmate:
this.play(mv);
- const res = (this.underCheck(oppCol) && !this.atLeastOneMove());
+ const res = (
+ this.underCheck(oppCol) && !this.atLeastOneMove("noReserve")
+ );
this.undo(mv);
if (res) continue;
}
}
// Modified to take promotions into account
- getSlideNJumpMoves([x, y], steps, options) {
+ getSlideNJumpMoves_opt([x, y], steps, options) {
options = options || {};
const color = this.turn;
const oneStep = options.oneStep;
getPotentialGoldMoves(sq) {
const forward = (this.turn == 'w' ? -1 : 1);
- return this.getSlideNJumpMoves(
+ return this.getSlideNJumpMoves_opt(
sq,
V.steps[V.ROOK].concat([ [forward, 1], [forward, -1] ]),
{ oneStep: true }
getPotentialPawnMoves(sq) {
const forward = (this.turn == 'w' ? -1 : 1);
return (
- this.getSlideNJumpMoves(
+ this.getSlideNJumpMoves_opt(
sq,
[[forward, 0]],
{
getPotentialSilverMoves(sq) {
const forward = (this.turn == 'w' ? -1 : 1);
- return this.getSlideNJumpMoves(
+ return this.getSlideNJumpMoves_opt(
sq,
V.steps[V.BISHOP].concat([ [forward, 0] ]),
{
getPotentialKnightMoves(sq) {
const forward = (this.turn == 'w' ? -2 : 2);
- return this.getSlideNJumpMoves(
+ return this.getSlideNJumpMoves_opt(
sq,
[ [forward, 1], [forward, -1] ],
{
getPotentialLanceMoves(sq) {
const forward = (this.turn == 'w' ? -1 : 1);
- return this.getSlideNJumpMoves(
+ return this.getSlideNJumpMoves_opt(
sq,
- [[forward, 0]],
+ [ [forward, 0] ],
{
promote: V.P_LANCE,
force: true
}
getPotentialRookMoves(sq) {
- return this.getSlideNJumpMoves(
+ return this.getSlideNJumpMoves_opt(
sq, V.steps[V.ROOK], { promote: V.P_ROOK });
}
getPotentialBishopMoves(sq) {
- return this.getSlideNJumpMoves(
+ return this.getSlideNJumpMoves_opt(
sq, V.steps[V.BISHOP], { promote: V.P_BISHOP });
}
getPotentialDragonMoves(sq) {
return (
- this.getSlideNJumpMoves(sq, V.steps[V.ROOK]).concat(
- this.getSlideNJumpMoves(sq, V.steps[V.BISHOP], { oneStep: true }))
+ this.getSlideNJumpMoves_opt(sq, V.steps[V.ROOK]).concat(
+ this.getSlideNJumpMoves_opt(sq, V.steps[V.BISHOP], { oneStep: true }))
);
}
getPotentialHorseMoves(sq) {
return (
- this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat(
- this.getSlideNJumpMoves(sq, V.steps[V.ROOK], { oneStep: true }))
+ this.getSlideNJumpMoves_opt(sq, V.steps[V.BISHOP]).concat(
+ this.getSlideNJumpMoves_opt(sq, V.steps[V.ROOK], { oneStep: true }))
);
}
return false;
}
- isAttackedBySilver([x, y], color) {
+ isAttackedBySilver(sq, color) {
const shift = (color == 'w' ? 1 : -1);
- for (let step of V.steps[V.BISHOP].concat([[shift, 0]])) {
- const [i, j] = [x + step[0], y + step[1]];
- if (
- V.OnBoard(i, j) &&
- this.board[i][j] != V.EMPTY &&
- this.getColor(i, j) == color &&
- this.getPiece(i, j) == V.SILVER_G
- ) {
- return true;
- }
- }
- return false;
+ return this.isAttackedBySlideNJump(
+ sq, color, V.SILVER, V.steps[V.BISHOP].concat([ [shift, 0] ]), 1);
}
- isAttackedByPawn([x, y], color) {
+ isAttackedByPawn(sq, color) {
const shift = (color == 'w' ? 1 : -1);
- const [i, j] = [x + shift, y];
- return (
- V.OnBoard(i, j) &&
- this.board[i][j] != V.EMPTY &&
- this.getColor(i, j) == color &&
- this.getPiece(i, j) == V.PAWN
- );
+ return this.isAttackedBySlideNJump(sq, color, V.PAWN, [ [shift, 0] ], 1);
}
isAttackedByKnight(sq, color) {
const forward = (color == 'w' ? 2 : -2);
return this.isAttackedBySlideNJump(
- sq, color, V.KNIGHT, [[forward, 1], [forward, -1]], "oneStep");
+ sq, color, V.KNIGHT, [ [forward, 1], [forward, -1] ], 1);
}
isAttackedByLance(sq, color) {
isAttackedByDragon(sq, color) {
return (
this.isAttackedBySlideNJump(sq, color, V.P_ROOK, V.steps[V.ROOK]) ||
- this.isAttackedBySlideNJump(
- sq, color, V.P_ROOK, V.steps[V.BISHOP], "oneStep")
+ this.isAttackedBySlideNJump(sq, color, V.P_ROOK, V.steps[V.BISHOP], 1)
);
}
isAttackedByHorse(sq, color) {
return (
this.isAttackedBySlideNJump(sq, color, V.P_BISHOP, V.steps[V.BISHOP]) ||
- this.isAttackedBySlideNJump(
- sq, color, V.P_BISHOP, V.steps[V.ROOK], "oneStep")
+ this.isAttackedBySlideNJump(sq, color, V.P_BISHOP, V.steps[V.ROOK], 1)
);
}
+ filterValid(moves) {
+ if (moves.length == 0) return [];
+ const color = this.turn;
+ const lastRanks = (color == 'w' ? [0, 1] : [8, 7]);
+ return moves.filter(m => {
+ if (
+ (m.appear[0].p == V.KNIGHT && lastRanks.includes(m.end.x)) ||
+ ([V.PAWN, V.LANCE].includes(m.appear[0].p) && lastRanks[0] == m.end.x)
+ ) {
+ // Forbid moves resulting in a blocked piece
+ return false;
+ }
+ this.play(m);
+ const res = !this.underCheck(color);
+ this.undo(m);
+ return res;
+ });
+ }
+
getAllValidMoves() {
let moves = super.getAllPotentialMoves();
const color = this.turn;
return this.filterValid(moves);
}
- atLeastOneMove() {
+ atLeastOneMove(noReserve) {
if (!super.atLeastOneMove()) {
- // Search one reserve move
- for (let i = 0; i < V.RESERVE_PIECES.length; i++) {
- let moves = this.filterValid(
- this.getReserveMoves([V.size.x + (this.turn == "w" ? 0 : 1), i])
- );
- if (moves.length > 0) return true;
+ if (!noReserve) {
+ // Search one reserve move
+ for (let i = 0; i < V.RESERVE_PIECES.length; i++) {
+ let moves = this.filterValid(
+ this.getReserveMoves([V.size.x + (this.turn == "w" ? 0 : 1), i])
+ );
+ if (moves.length > 0) return true;
+ }
}
return false;
}