X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FCheckered.js;h=79ea63c44a3fc6bd24b71aebf4d2511031d41d12;hb=2c5d7b20742b802d9c47916915c1114bcfc9a9c3;hp=78b5ef071147173e4a399d5f10d56b8a3a6a891d;hpb=bbf668379ae5980d5068dd76cf907c87ce7ed648;p=vchess.git diff --git a/client/src/variants/Checkered.js b/client/src/variants/Checkered.js index 78b5ef07..79ea63c4 100644 --- a/client/src/variants/Checkered.js +++ b/client/src/variants/Checkered.js @@ -1,6 +1,6 @@ -import { ChessRules } from "@/base_rules"; +import { ChessRules, Move, PiPo } from "@/base_rules"; -export const VariantRules = class CheckeredRules extends ChessRules { +export class CheckeredRules extends ChessRules { static board2fen(b) { const checkered_codes = { p: "s", @@ -44,7 +44,7 @@ export const VariantRules = class CheckeredRules extends ChessRules { super.setOtherVariables(fen); // Local stack of non-capturing checkered moves: this.cmoves = []; - const cmove = fen.split(" ")[5]; + const cmove = V.ParseFen(fen).cmove; if (cmove == "-") this.cmoves.push(null); else { this.cmoves.push({ @@ -65,16 +65,16 @@ export const VariantRules = class CheckeredRules extends ChessRules { static IsGoodFlags(flags) { // 4 for castle + 16 for pawns - return !!flags.match(/^[01]{20,20}$/); + return !!flags.match(/^[a-z]{4,4}[01]{16,16}$/); } setFlags(fenflags) { super.setFlags(fenflags); //castleFlags this.pawnFlags = { - w: [...Array(8).fill(true)], //pawns can move 2 squares? - b: [...Array(8).fill(true)] + w: [...Array(8)], //pawns can move 2 squares? + b: [...Array(8)] }; - const flags = fenflags.substr(4); //skip first 4 digits, for castle + const flags = fenflags.substr(4); //skip first 4 letters, for castle for (let c of ["w", "b"]) { for (let i = 0; i < 8; i++) this.pawnFlags[c][i] = flags.charAt((c == "w" ? 0 : 8) + i) == "1"; @@ -118,7 +118,7 @@ export const VariantRules = class CheckeredRules extends ChessRules { getPotentialMovesFrom([x, y]) { let standardMoves = super.getPotentialMovesFrom([x, y]); const lastRank = this.turn == "w" ? 0 : 7; - // King has to be treated differently (for castles) + // King is treated differently: it never turn checkered if (this.getPiece(x, y) == V.KING) return standardMoves; let moves = []; standardMoves.forEach(m => { @@ -126,8 +126,9 @@ export const VariantRules = class CheckeredRules extends ChessRules { if ( Math.abs(m.end.x - m.start.x) == 2 && !this.pawnFlags[this.turn][m.start.y] - ) + ) { return; //skip forbidden 2-squares jumps + } if ( this.board[m.end.x][m.end.y] == V.EMPTY && m.vanish.length == 2 && @@ -136,14 +137,16 @@ export const VariantRules = class CheckeredRules extends ChessRules { return; //checkered pawns cannot take en-passant } } - if (m.vanish.length == 1) moves.push(m); - // No capture + if (m.vanish.length == 1) + // No capture + moves.push(m); else { // A capture occured (m.vanish.length == 2) m.appear[0].c = "c"; moves.push(m); if ( - m.appear[0].p != m.vanish[1].p && //avoid promotions (already treated): + // Avoid promotions (already treated): + m.appear[0].p != m.vanish[1].p && (m.vanish[0].p != V.PAWN || m.end.x != lastRank) ) { // Add transformation into captured piece @@ -157,73 +160,13 @@ export const VariantRules = class CheckeredRules extends ChessRules { } getPotentialPawnMoves([x, y]) { - const color = this.turn; - let moves = []; - const [sizeX, sizeY] = [V.size.x, V.size.y]; - const shiftX = color == "w" ? -1 : 1; - const startRank = color == "w" ? sizeX - 2 : 1; - const lastRank = color == "w" ? 0 : sizeX - 1; - const pawnColor = this.getColor(x, y); //can be checkered - - const finalPieces = - x + shiftX == lastRank - ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN] - : [V.PAWN]; - if (this.board[x + shiftX][y] == V.EMPTY) { - // One square forward - for (let piece of finalPieces) { - moves.push( - this.getBasicMove([x, y], [x + shiftX, y], { - c: pawnColor, - p: piece - }) - ); - } - if ( - x == startRank && - this.board[x + 2 * shiftX][y] == V.EMPTY - ) { - // Two squares jump - moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y])); - } - } - // Captures - for (let shiftY of [-1, 1]) { - if ( - y + shiftY >= 0 && - y + shiftY < sizeY && - this.board[x + shiftX][y + shiftY] != V.EMPTY && - this.canTake([x, y], [x + shiftX, y + shiftY]) - ) { - for (let piece of finalPieces) { - moves.push( - this.getBasicMove([x, y], [x + shiftX, y + shiftY], { - c: pawnColor, - p: piece - }) - ); - } - } - } - - // En passant - const Lep = this.epSquares.length; - const epSquare = this.epSquares[Lep - 1]; //always at least one element - if ( - !!epSquare && - epSquare.x == x + shiftX && - Math.abs(epSquare.y - y) == 1 - ) { - let enpassantMove = this.getBasicMove([x, y], [epSquare.x, epSquare.y]); - enpassantMove.vanish.push({ - x: x, - y: epSquare.y, - p: "p", - c: this.getColor(x, epSquare.y) + let moves = super.getPotentialPawnMoves([x, y]); + // Post-process: set right color for checkered moves + if (this.getColor(x, y) == 'c') + moves.forEach(m => { + m.appear[0].c = 'c'; //may be done twice if capture + m.vanish[0].c = 'c'; }); - moves.push(enpassantMove); - } - return moves; } @@ -279,7 +222,7 @@ export const VariantRules = class CheckeredRules extends ChessRules { const oppCol = V.GetOppCol(this.turn); for (let i = 0; i < V.size.x; i++) { for (let j = 0; j < V.size.y; j++) { - // NOTE: just testing == color isn't enough because of checkred pieces + // NOTE: just testing == color isn't enough because of checkered pieces if (this.board[i][j] != V.EMPTY && this.getColor(i, j) != oppCol) { const moves = this.getPotentialMovesFrom([i, j]); if (moves.length > 0) { @@ -293,9 +236,22 @@ export const VariantRules = class CheckeredRules extends ChessRules { return false; } + // colors: array, generally 'w' and 'c' or 'b' and 'c' + isAttacked(sq, colors) { + if (!Array.isArray(colors)) colors = [colors]; + return ( + this.isAttackedByPawn(sq, colors) || + this.isAttackedByRook(sq, colors) || + this.isAttackedByKnight(sq, colors) || + this.isAttackedByBishop(sq, colors) || + this.isAttackedByQueen(sq, colors) || + this.isAttackedByKing(sq, colors) + ); + } + isAttackedByPawn([x, y], colors) { for (let c of colors) { - const color = c == "c" ? this.turn : c; + const color = (c == "c" ? this.turn : c); let pawnShift = color == "w" ? 1 : -1; if (x + pawnShift >= 0 && x + pawnShift < 8) { for (let i of [-1, 1]) { @@ -313,6 +269,63 @@ export const VariantRules = class CheckeredRules extends ChessRules { return false; } + isAttackedBySlideNJump([x, y], colors, piece, steps, oneStep) { + for (let step of steps) { + let rx = x + step[0], + ry = y + step[1]; + while (V.OnBoard(rx, ry) && this.board[rx][ry] == V.EMPTY && !oneStep) { + rx += step[0]; + ry += step[1]; + } + if ( + V.OnBoard(rx, ry) && + this.getPiece(rx, ry) === piece && + colors.includes(this.getColor(rx, ry)) + ) { + return true; + } + } + return false; + } + + isAttackedByRook(sq, colors) { + return this.isAttackedBySlideNJump(sq, colors, V.ROOK, V.steps[V.ROOK]); + } + + isAttackedByKnight(sq, colors) { + return this.isAttackedBySlideNJump( + sq, + colors, + V.KNIGHT, + V.steps[V.KNIGHT], + "oneStep" + ); + } + + isAttackedByBishop(sq, colors) { + return this.isAttackedBySlideNJump( + sq, colors, V.BISHOP, V.steps[V.BISHOP]); + } + + isAttackedByQueen(sq, colors) { + return this.isAttackedBySlideNJump( + sq, + colors, + V.QUEEN, + V.steps[V.ROOK].concat(V.steps[V.BISHOP]) + ); + } + + isAttackedByKing(sq, colors) { + return this.isAttackedBySlideNJump( + sq, + colors, + V.KING, + V.steps[V.ROOK].concat(V.steps[V.BISHOP]), + "oneStep" + ); + } + underCheck(color) { return this.isAttacked(this.kingPos[color], [V.GetOppCol(color), "c"]); } @@ -325,25 +338,27 @@ export const VariantRules = class CheckeredRules extends ChessRules { "c" ]); let res = kingAttacked - ? [JSON.parse(JSON.stringify(this.kingPos[color]))] //need to duplicate! + ? [JSON.parse(JSON.stringify(this.kingPos[color]))] : []; this.turn = color; return res; } - updateVariables(move) { - super.updateVariables(move); + postPlay(move) { + super.postPlay(move); // Does this move turn off a 2-squares pawn flag? - const secondRank = [1, 6]; - if (secondRank.includes(move.start.x) && move.vanish[0].p == V.PAWN) + if ([1, 6].includes(move.start.x) && move.vanish[0].p == V.PAWN) this.pawnFlags[move.start.x == 6 ? "w" : "b"][move.start.y] = false; + this.cmoves.push(this.getCmove(move)); } - getCurrentScore() { - if (this.atLeastOneMove()) - // game not over - return "*"; + postUndo(move) { + super.postUndo(move); + this.cmoves.pop(); + } + getCurrentScore() { + if (this.atLeastOneMove()) return "*"; const color = this.turn; // Artifically change turn, for checkered pawns this.turn = V.GetOppCol(this.turn); @@ -374,44 +389,38 @@ export const VariantRules = class CheckeredRules extends ChessRules { } static GenRandInitFen(randomness) { + // Add 16 pawns flags + empty cmove: return ChessRules.GenRandInitFen(randomness) - // Add 16 pawns flags + empty cmove: - .replace(" w 0 1111", " w 0 11111111111111111111 -"); + .slice(0, -2) + "1111111111111111 - -"; } static ParseFen(fen) { - return Object.assign({}, ChessRules.ParseFen(fen), { - cmove: fen.split(" ")[5] - }); + return Object.assign( + ChessRules.ParseFen(fen), + { cmove: fen.split(" ")[5] } + ); } getFen() { const L = this.cmoves.length; - const cmoveFen = !this.cmoves[L - 1] - ? "-" - : ChessRules.CoordsToSquare(this.cmoves[L - 1].start) + - ChessRules.CoordsToSquare(this.cmoves[L - 1].end); + const cmoveFen = + !this.cmoves[L - 1] + ? "-" + : ChessRules.CoordsToSquare(this.cmoves[L - 1].start) + + ChessRules.CoordsToSquare(this.cmoves[L - 1].end); return super.getFen() + " " + cmoveFen; } getFlagsFen() { let fen = super.getFlagsFen(); // Add pawns flags - for (let c of ["w", "b"]) { - for (let i = 0; i < 8; i++) fen += this.pawnFlags[c][i] ? "1" : "0"; - } + for (let c of ["w", "b"]) + for (let i = 0; i < 8; i++) fen += (this.pawnFlags[c][i] ? "1" : "0"); return fen; } - // TODO (design): this cmove update here or in (un)updateVariables ? - play(move) { - this.cmoves.push(this.getCmove(move)); - super.play(move); - } - - undo(move) { - this.cmoves.pop(); - super.undo(move); + static get SEARCH_DEPTH() { + return 2; } getNotation(move) { @@ -421,37 +430,25 @@ export const VariantRules = class CheckeredRules extends ChessRules { return "0-0"; } - // Translate final square const finalSquare = V.CoordsToSquare(move.end); - const piece = this.getPiece(move.start.x, move.start.y); + let notation = ""; if (piece == V.PAWN) { // Pawn move - let notation = ""; if (move.vanish.length > 1) { // Capture const startColumn = V.CoordToColumn(move.start.y); - notation = - startColumn + - "x" + - finalSquare + - "=" + - move.appear[0].p.toUpperCase(); - } //no capture - else { - notation = finalSquare; - if (move.appear.length > 0 && piece != move.appear[0].p) - //promotion - notation += "=" + move.appear[0].p.toUpperCase(); - } - return notation; + notation = startColumn + "x" + finalSquare; + } else notation = finalSquare; + } else { + // Piece movement + notation = + piece.toUpperCase() + + (move.vanish.length > 1 ? "x" : "") + + finalSquare; } - // Piece movement - return ( - piece.toUpperCase() + - (move.vanish.length > 1 ? "x" : "") + - finalSquare + - (move.vanish.length > 1 ? "=" + move.appear[0].p.toUpperCase() : "") - ); + if (move.appear[0].p != move.vanish[0].p) + notation += "=" + move.appear[0].p.toUpperCase(); + return notation; } };