// NOTE: initial setup differs from the original; see
// https://www.chessvariants.com/large.dir/freeling.html
-export const VariantRules = class GrandRules extends ChessRules {
+export class GrandRules extends ChessRules {
static IsGoodFen(fen) {
if (!ChessRules.IsGoodFen(fen)) return false;
const fenParsed = V.ParseFen(fen);
// 5) Check captures
- if (!fenParsed.captured || !fenParsed.captured.match(/^[0-9]{14,14}$/))
+ if (!fenParsed.captured || !fenParsed.captured.match(/^[0-9]{12,12}$/))
return false;
return true;
}
static IsGoodEnpassant(enpassant) {
- if (enpassant != "-") {
- const squares = enpassant.split(",");
- if (squares.length > 2) return false;
- for (let sq of squares) {
- const ep = V.SquareToCoords(sq);
- if (isNaN(ep.x) || !V.OnBoard(ep)) return false;
- }
- }
+ if (enpassant != "-") return !!enpassant.match(/^([a-j][0-9]{1,2},?)+$/);
return true;
}
static ParseFen(fen) {
const fenParts = fen.split(" ");
- return Object.assign(ChessRules.ParseFen(fen), { captured: fenParts[5] });
+ return Object.assign(
+ ChessRules.ParseFen(fen),
+ { captured: fenParts[5] }
+ );
}
getPpath(b) {
}
getCapturedFen() {
- let counts = [...Array(14).fill(0)];
+ let counts = [...Array(12).fill(0)];
let i = 0;
for (let j = 0; j < V.PIECES.length; j++) {
- if (V.PIECES[j] == V.KING)
- //no king captured
+ if ([V.KING, V.PAWN].includes(V.PIECES[j]))
+ // No king captured, and pawns don't promote in pawns
continue;
- counts[i] = this.captured["w"][V.PIECES[i]];
- counts[7 + i] = this.captured["b"][V.PIECES[i]];
+ counts[i] = this.captured["w"][V.PIECES[j]];
+ counts[6 + i] = this.captured["b"][V.PIECES[j]];
i++;
}
return counts.join("");
// Initialize captured pieces' counts from FEN
this.captured = {
w: {
- [V.PAWN]: parseInt(fenParsed.captured[0]),
- [V.ROOK]: parseInt(fenParsed.captured[1]),
- [V.KNIGHT]: parseInt(fenParsed.captured[2]),
- [V.BISHOP]: parseInt(fenParsed.captured[3]),
- [V.QUEEN]: parseInt(fenParsed.captured[4]),
- [V.MARSHALL]: parseInt(fenParsed.captured[5]),
- [V.CARDINAL]: parseInt(fenParsed.captured[6])
+ [V.ROOK]: parseInt(fenParsed.captured[0]),
+ [V.KNIGHT]: parseInt(fenParsed.captured[1]),
+ [V.BISHOP]: parseInt(fenParsed.captured[2]),
+ [V.QUEEN]: parseInt(fenParsed.captured[3]),
+ [V.MARSHALL]: parseInt(fenParsed.captured[4]),
+ [V.CARDINAL]: parseInt(fenParsed.captured[5])
},
b: {
- [V.PAWN]: parseInt(fenParsed.captured[7]),
- [V.ROOK]: parseInt(fenParsed.captured[8]),
- [V.KNIGHT]: parseInt(fenParsed.captured[9]),
- [V.BISHOP]: parseInt(fenParsed.captured[10]),
- [V.QUEEN]: parseInt(fenParsed.captured[11]),
- [V.MARSHALL]: parseInt(fenParsed.captured[12]),
- [V.CARDINAL]: parseInt(fenParsed.captured[13])
+ [V.ROOK]: parseInt(fenParsed.captured[6]),
+ [V.KNIGHT]: parseInt(fenParsed.captured[7]),
+ [V.BISHOP]: parseInt(fenParsed.captured[8]),
+ [V.QUEEN]: parseInt(fenParsed.captured[9]),
+ [V.MARSHALL]: parseInt(fenParsed.captured[10]),
+ [V.CARDINAL]: parseInt(fenParsed.captured[11])
}
};
}
return { x: 10, y: 10 };
}
+ // Rook + knight:
static get MARSHALL() {
return "m";
- } //rook+knight
+ }
+
+ // Bishop + knight
static get CARDINAL() {
return "c";
- } //bishop+knight
+ }
static get PIECES() {
return ChessRules.PIECES.concat([V.MARSHALL, V.CARDINAL]);
}
];
if (sx + 2 * step != ex) {
- //3-squares move
+ // 3-squares jump
res.push({
x: sx + 2 * step,
y: sy
// En passant
const Lep = this.epSquares.length;
const epSquare = this.epSquares[Lep - 1];
- if (epSquare) {
+ if (!!epSquare) {
for (let epsq of epSquare) {
// TODO: some redundant checks
if (epsq.x == x + shiftX && Math.abs(epsq.y - y) == 1) {
- var enpassantMove = this.getBasicMove([x, y], [epsq.x, epsq.y]);
+ let enpassantMove = this.getBasicMove([x, y], [epsq.x, epsq.y]);
// WARNING: the captured pawn may be diagonally behind us,
// if it's a 3-squares jump and we take on 1st passing square
const px = this.board[x][epsq.y] != V.EMPTY ? x : x - shiftX;
);
}
- isAttacked(sq, colors) {
+ isAttacked(sq, color) {
return (
- super.isAttacked(sq, colors) ||
- this.isAttackedByMarshall(sq, colors) ||
- this.isAttackedByCardinal(sq, colors)
+ super.isAttacked(sq, color) ||
+ this.isAttackedByMarshall(sq, color) ||
+ this.isAttackedByCardinal(sq, color)
);
}
- isAttackedByMarshall(sq, colors) {
+ isAttackedByMarshall(sq, color) {
return (
- this.isAttackedBySlideNJump(sq, colors, V.MARSHALL, V.steps[V.ROOK]) ||
+ this.isAttackedBySlideNJump(sq, color, V.MARSHALL, V.steps[V.ROOK]) ||
this.isAttackedBySlideNJump(
sq,
- colors,
+ color,
V.MARSHALL,
V.steps[V.KNIGHT],
"oneStep"
);
}
- isAttackedByCardinal(sq, colors) {
+ isAttackedByCardinal(sq, color) {
return (
- this.isAttackedBySlideNJump(sq, colors, V.CARDINAL, V.steps[V.BISHOP]) ||
+ this.isAttackedBySlideNJump(sq, color, V.CARDINAL, V.steps[V.BISHOP]) ||
this.isAttackedBySlideNJump(
sq,
- colors,
+ color,
V.CARDINAL,
V.steps[V.KNIGHT],
"oneStep"
postPlay(move) {
super.postPlay(move);
- if (move.vanish.length == 2 && move.appear.length == 1) {
+ if (move.vanish.length == 2 && move.appear.length == 1)
// Capture: update this.captured
this.captured[move.vanish[1].c][move.vanish[1].p]++;
- }
- if (move.vanish[0].p != move.appear[0].p) {
- // Promotion: update this.captured
- this.captured[move.vanish[0].c][move.appear[0].p]--;
- }
}
postUndo(move) {
super.postUndo(move);
if (move.vanish.length == 2 && move.appear.length == 1)
this.captured[move.vanish[1].c][move.vanish[1].p]--;
- if (move.vanish[0].p != move.appear[0].p)
- this.captured[move.vanish[0].c][move.appear[0].p]++;
}
static get VALUES() {
static GenRandInitFen(randomness) {
if (randomness == 0) {
- // No castling in the official initial setup
- return "r8r/1nbqkmcbn1/pppppppppp/10/10/10/10/PPPPPPPPPP/1NBQKMCBN1/R8R " +
- "w 0 zzzz - 00000000000000";
+ return (
+ "r8r/1nbqkmcbn1/pppppppppp/91/91/91/91/PPPPPPPPPP/1NBQKMCBN1/R8R " +
+ // No castling in the official initial setup
+ "w 0 zzzz - 00000000000000"
+ );
}
let pieces = { w: new Array(10), b: new Array(10) };
+ let flags = "";
// Shuffle pieces on first and last rank
for (let c of ["w", "b"]) {
if (c == 'b' && randomness == 1) {
pieces['b'] = pieces['w'];
+ flags += flags;
break;
}
let cardinalPos = positions[randIndex];
positions.splice(randIndex, 1);
- // Rooks and king positions are now fixed, because of the ordering rook-king-rook
+ // Rooks and king positions are now fixed,
+ // because of the ordering rook-king-rook
let rook1Pos = positions[0];
let kingPos = positions[1];
let rook2Pos = positions[2];
pieces[c][bishop2Pos] = "b";
pieces[c][knight2Pos] = "n";
pieces[c][rook2Pos] = "r";
+ flags += V.CoordToColumn(rook1Pos) + V.CoordToColumn(rook2Pos);
}
return (
pieces["b"].join("") +
- "/pppppppppp/10/10/10/10/10/10/PPPPPPPPPP/" +
+ "/pppppppppp/91/91/91/91/91/91/PPPPPPPPPP/" +
pieces["w"].join("").toUpperCase() +
- " w 0 1111 - 00000000000000"
+ " w 0 " + flags + " - 00000000000000"
);
}
};