import { randInt } from "@/utils/alea";
export class OmegaRules extends ChessRules {
+
static get PawnSpecs() {
return Object.assign(
{},
);
}
+ static get DarkBottomRight() {
+ return true;
+ }
+
// For space between corners:
static get NOTHING() {
return "xx";
return ([V.CHAMPION, V.WIZARD].includes(b[1]) ? "Omega/" : "") + b;
}
+ // TODO: the wall position should be checked too
static IsGoodPosition(position) {
if (position.length == 0) return false;
const rows = position.split("/");
if (['K','k'].includes(row[i])) kings[row[i]]++;
if (['x'].concat(V.PIECES).includes(row[i].toLowerCase())) sumElts++;
else {
- const num = parseInt(row[i]);
+ const num = parseInt(row[i], 10);
if (isNaN(num)) return false;
sumElts += num;
}
);
}
- static GenRandInitFen(randomness) {
- if (randomness == 0) {
+ static GenRandInitFen(options) {
+ if (options.randomness == 0) {
return (
"wxxxxxxxxxxw/xcrnbqkbnrcx/xppppppppppx/x91x/x91x/x91x/" +
"x91x/x91x/x91x/xPPPPPPPPPPx/xCRNBQKBNRCx/WxxxxxxxxxxW " +
let flags = "";
// Shuffle pieces on first (and last rank if randomness == 2)
for (let c of ["w", "b"]) {
- if (c == 'b' && randomness == 1) {
+ if (c == 'b' && options.randomness == 1) {
pieces['b'] = pieces['w'];
flags += flags;
break;
// The second bishop must be on a square of different color
let randIndex_tmp = 2 * randInt(5) + 1;
const bishop2Pos = positions[randIndex_tmp];
- positions.splice(Math.max(randIndex, randIndex_tmp), 1);
- positions.splice(Math.min(randIndex, randIndex_tmp), 1);
// Get random squares for champions
- randIndex = 2 * randInt(4);
- let bishopSameColorPos = (bishop1Pos % 2 == 0 ? bishop1Pos : bishop2Pos);
- if (randIndex >= bishopSameColorPos) randIndex += 2;
- const champion1Pos = positions[randIndex];
+ let randIndexC = 2 * randInt(4);
+ if (randIndexC >= bishop1Pos) randIndexC += 2;
+ const champion1Pos = positions[randIndexC];
// The second champion must be on a square of different color
- randIndex_tmp = 2 * randInt(4) + 1;
- bishopSameColorPos = (bishop1Pos % 2 == 0 ? bishop1Pos : bishop2Pos);
- if (randIndex_tmp >= bishopSameColorPos) randIndex_tmp += 2;
- const champion2Pos = positions[randIndex_tmp];
- positions.splice(Math.max(randIndex, randIndex_tmp), 1);
- positions.splice(Math.min(randIndex, randIndex_tmp), 1);
+ let randIndex_tmpC = 2 * randInt(4) + 1;
+ if (randIndex_tmpC >= bishop2Pos) randIndex_tmpC += 2;
+ const champion2Pos = positions[randIndex_tmpC];
+
+ let usedIndices = [randIndex, randIndex_tmp, randIndexC, randIndex_tmpC];
+ usedIndices.sort();
+ for (let i = 3; i >= 0; i--) positions.splice(usedIndices[i], 1);
// Get random squares for other pieces
randIndex = randInt(6);
pieces[c][knight2Pos] = "n";
pieces[c][rook2Pos] = "r";
pieces[c][champion2Pos] = "c";
- flags += V.CoordToColumn(rook1Pos) + V.CoordToColumn(rook2Pos);
+ flags += V.CoordToColumn(rook1Pos+1) + V.CoordToColumn(rook2Pos+1);
}
// Add turn + flags + enpassant
return (
return res.slice(0, -1); //remove last comma
}
+ canTake([x1, y1], [x2, y2]) {
+ return (
+ // Cannot take wall :)
+ // NOTE: this check is useful only for pawns where OnBoard() isn't used
+ this.board[x2][y2] != V.NOTHING &&
+ this.getColor(x1, y1) !== this.getColor(x2, y2)
+ );
+ }
+
// En-passant after 2-sq or 3-sq jumps
getEpSquare(moveOrSquare) {
if (!moveOrSquare) return undefined;
getPotentialMovesFrom([x, y]) {
switch (this.getPiece(x, y)) {
- case V.CHAMPION:
- return this.getPotentialChampionMoves([x, y]);
- case V.WIZARD:
- return this.getPotentialWizardMoves([x, y]);
- default:
- return super.getPotentialMovesFrom([x, y]);
+ case V.CHAMPION: return this.getPotentialChampionMoves([x, y]);
+ case V.WIZARD: return this.getPotentialWizardMoves([x, y]);
+ default: return super.getPotentialMovesFrom([x, y]);
}
}
- getEnpassanCaptures([x, y], shiftX) {
+ getEnpassantCaptures([x, y], shiftX) {
const Lep = this.epSquares.length;
const epSquare = this.epSquares[Lep - 1];
let moves = [];
return moves;
}
+ addPawnMoves([x1, y1], [x2, y2], moves) {
+ const color = this.turn;
+ const lastRank = (color == "w" ? 1 : V.size.x - 2);
+ const finalPieces = (x2 == lastRank ? V.PawnSpecs.promotions : [V.PAWN]);
+ for (let piece of finalPieces) {
+ const tr = (piece != V.PAWN ? { c: color, p: piece } : null);
+ moves.push(this.getBasicMove([x1, y1], [x2, y2], tr));
+ }
+ }
+
getPotentialChampionMoves(sq) {
- return this.getSlideNJumpMoves(sq, V.steps[V.CHAMPION], "oneStep");
+ return this.getSlideNJumpMoves(sq, V.steps[V.CHAMPION], 1);
}
getPotentialWizardMoves(sq) {
- return this.getSlideNJumpMoves(sq, V.steps[V.WIZARD], "oneStep");
+ return this.getSlideNJumpMoves(sq, V.steps[V.WIZARD], 1);
}
- getCastleMoves([x, y], castleInCheck) {
- const c = this.getColor(x, y);
- if (x != (c == "w" ? V.size.x - 2 : 1) || 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:
+ getCastleMoves([x, y]) {
const finalSquares = [
[4, 5],
[8, 7]
];
- castlingCheck: for (
- let castleSide = 0;
- castleSide < 2;
- castleSide++ //large, then small
- ) {
- if (this.castleFlags[c][castleSide] >= V.size.y) continue;
- // If this code is reached, rook and king are on initial position
-
- // NOTE: in some variants this is not a rook
- const rookPos = this.castleFlags[c][castleSide];
- 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)) ||
- (this.board[x][i] != V.EMPTY &&
- // NOTE: next check is enough, because of chessboard constraints
- (this.getColor(x, i) != c ||
- ![V.KING, castlingPiece].includes(this.getPiece(x, i))))
- ) {
- continue castlingCheck;
- }
- i += step;
- } while (i != finalSquares[castleSide][0]);
-
- // 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 (
- finalSquares[castleSide][i] != rookPos &&
- this.board[x][finalSquares[castleSide][i]] != V.EMPTY &&
- (
- this.getPiece(x, finalSquares[castleSide][i]) != V.KING ||
- this.getColor(x, finalSquares[castleSide][i]) != c
- )
- ) {
- 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: castlingPiece,
- c: c
- })
- ],
- vanish: [
- new PiPo({ x: x, y: y, p: V.KING, c: c }),
- new PiPo({ x: x, y: rookPos, p: castlingPiece, c: c })
- ],
- end:
- Math.abs(y - rookPos) <= 2
- ? { x: x, y: rookPos }
- : { x: x, y: y + 2 * (castleSide == 0 ? -1 : 1) }
- })
- );
- }
-
- return moves;
+ return super.getCastleMoves([x, y], finalSquares);
}
isAttacked(sq, color) {
isAttackedByWizard(sq, color) {
return (
this.isAttackedBySlideNJump(
- sq, color, V.WIZARD, V.steps[V.WIZARD], "oneStep")
+ sq, color, V.WIZARD, V.steps[V.WIZARD], 1)
);
}
isAttackedByChampion(sq, color) {
return (
this.isAttackedBySlideNJump(
- sq, color, V.CHAMPION, V.steps[V.CHAMPION], "oneStep")
+ sq, color, V.CHAMPION, V.steps[V.CHAMPION], 1)
);
}
}
return evaluation;
}
+
};