X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FCheckered.js;h=0e089f38048f36b4eab74212e335da00f53f7bc0;hb=3a2a7b5fd3c6bfd0752838094c27e1fb6172d109;hp=0e4f0a0d5c5d7ffa547f3a1ebd413c9678386f5d;hpb=6808d7a16ec1e761c6a2dffec2281c96953e4d89;p=vchess.git diff --git a/client/src/variants/Checkered.js b/client/src/variants/Checkered.js index 0e4f0a0d..0e089f38 100644 --- a/client/src/variants/Checkered.js +++ b/client/src/variants/Checkered.js @@ -1,10 +1,6 @@ import { ChessRules } from "@/base_rules"; export const VariantRules = class CheckeredRules extends ChessRules { - static getPpath(b) { - return b[0] == "c" ? "Checkered/" + b : b; - } - static board2fen(b) { const checkered_codes = { p: "s", @@ -40,11 +36,15 @@ export const VariantRules = class CheckeredRules extends ChessRules { return ChessRules.PIECES.concat(["s", "t", "u", "c", "o"]); } + getPpath(b) { + return (b[0] == "c" ? "Checkered/" : "") + b; + } + setOtherVariables(fen) { 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,7 +65,7 @@ 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) { @@ -74,8 +74,7 @@ export const VariantRules = class CheckeredRules extends ChessRules { w: [...Array(8).fill(true)], //pawns can move 2 squares? b: [...Array(8).fill(true)] }; - if (!fenflags) return; - 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"; @@ -91,6 +90,13 @@ export const VariantRules = class CheckeredRules extends ChessRules { this.pawnFlags = flags[1]; } + getEpSquare(moveOrSquare) { + if (typeof moveOrSquare !== "object" || moveOrSquare.appear[0].c != 'c') + return super.getEpSquare(moveOrSquare); + // Checkered move: no en-passant + return undefined; + } + getCmove(move) { if (move.appear[0].c == "c" && move.vanish.length == 1) return { start: move.start, end: move.end }; @@ -112,7 +118,8 @@ export const VariantRules = class CheckeredRules extends ChessRules { getPotentialMovesFrom([x, y]) { let standardMoves = super.getPotentialMovesFrom([x, y]); const lastRank = this.turn == "w" ? 0 : 7; - if (this.getPiece(x, y) == V.KING) return standardMoves; //king has to be treated differently (for castles) + // King has to be treated differently (for castles) + if (this.getPiece(x, y) == V.KING) return standardMoves; let moves = []; standardMoves.forEach(m => { if (m.vanish[0].p == V.PAWN) { @@ -130,7 +137,7 @@ export const VariantRules = class CheckeredRules extends ChessRules { } } if (m.vanish.length == 1) moves.push(m); - //no capture + // No capture else { // A capture occured (m.vanish.length == 2) m.appear[0].c = "c"; @@ -149,6 +156,77 @@ export const VariantRules = class CheckeredRules extends ChessRules { return moves; } + 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) + }); + moves.push(enpassantMove); + } + + return moves; + } + canIplay(side, [x, y]) { return side == this.turn && [side, "c"].includes(this.getColor(x, y)); } @@ -156,7 +234,7 @@ export const VariantRules = class CheckeredRules extends ChessRules { // Does m2 un-do m1 ? (to disallow undoing checkered moves) oppositeMoves(m1, m2) { return ( - !!m1 && + m1 && m2.appear[0].c == "c" && m2.appear.length == 1 && m2.vanish.length == 1 && @@ -170,8 +248,8 @@ export const VariantRules = class CheckeredRules extends ChessRules { filterValid(moves) { if (moves.length == 0) return []; const color = this.turn; + const L = this.cmoves.length; //at least 1: init from FEN return moves.filter(m => { - const L = this.cmoves.length; //at least 1: init from FEN if (this.oppositeMoves(this.cmoves[L - 1], m)) return false; this.play(m); const res = !this.underCheck(color); @@ -180,6 +258,41 @@ export const VariantRules = class CheckeredRules extends ChessRules { }); } + getAllValidMoves() { + const oppCol = V.GetOppCol(this.turn); + let potentialMoves = []; + 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 + if (this.board[i][j] != V.EMPTY && this.getColor(i, j) != oppCol) { + Array.prototype.push.apply( + potentialMoves, + this.getPotentialMovesFrom([i, j]) + ); + } + } + } + return this.filterValid(potentialMoves); + } + + atLeastOneMove() { + 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 checkered pieces + if (this.board[i][j] != V.EMPTY && this.getColor(i, j) != oppCol) { + const moves = this.getPotentialMovesFrom([i, j]); + if (moves.length > 0) { + for (let k = 0; k < moves.length; k++) { + if (this.filterValid([moves[k]]).length > 0) return true; + } + } + } + } + } + return false; + } + isAttackedByPawn([x, y], colors) { for (let c of colors) { const color = c == "c" ? this.turn : c; @@ -218,12 +331,17 @@ export const VariantRules = class CheckeredRules extends ChessRules { 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)); + } + + postUndo(move) { + super.postUndo(move); + this.cmoves.pop(); } getCurrentScore() { @@ -245,23 +363,25 @@ export const VariantRules = class CheckeredRules extends ChessRules { evalPosition() { let evaluation = 0; - //Just count material for now, considering checkered neutral (...) + // Just count material for now, considering checkered neutral (...) for (let i = 0; i < V.size.x; i++) { for (let j = 0; j < V.size.y; j++) { if (this.board[i][j] != V.EMPTY) { const sqColor = this.getColor(i, j); - const sign = sqColor == "w" ? 1 : sqColor == "b" ? -1 : 0; - evaluation += sign * V.VALUES[this.getPiece(i, j)]; + if (["w","b"].includes(sqColor)) { + const sign = sqColor == "w" ? 1 : -1; + evaluation += sign * V.VALUES[this.getPiece(i, j)]; + } } } } return evaluation; } - static GenRandInitFen() { - const randFen = ChessRules.GenRandInitFen(); + static GenRandInitFen(randomness) { // Add 16 pawns flags + empty cmove: - return randFen.replace(" w 0 1111", " w 0 11111111111111111111 -"); + return ChessRules.GenRandInitFen(randomness) + .slice(0, -2) + "1111111111111111 - -"; } static ParseFen(fen) { @@ -288,15 +408,8 @@ export const VariantRules = class CheckeredRules extends ChessRules { 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) {