X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FHiddenqueen.js;fp=client%2Fsrc%2Fvariants%2FHiddenqueen.js;h=fe34fb28c672d6cd8c586d11e8056d39a7cab7f3;hb=a97bdbda4ecf83645d409b717e36828784d1450d;hp=0000000000000000000000000000000000000000;hpb=e2d2b49c4b8f5228126991ac5cf41086a51a4285;p=vchess.git diff --git a/client/src/variants/Hiddenqueen.js b/client/src/variants/Hiddenqueen.js new file mode 100644 index 00000000..fe34fb28 --- /dev/null +++ b/client/src/variants/Hiddenqueen.js @@ -0,0 +1,155 @@ +import { ChessRules, PiPo, Move } from "@/base_rules"; +import { ArrayFun } from "@/utils/array"; +import { randInt } from "@/utils/alea"; + +export const VariantRules = class HiddenqueenRules extends ChessRules { + // Analyse in Hiddenqueen mode makes no sense + static get CanAnalyze() { + return false; + } + + static get HIDDEN_QUEEN() { + return 't'; + } + + static get PIECES() { + return ChessRules.PIECES.concat(Object.values(V.HIDDEN_CODE)); + } + + getPiece(i, j) { + const piece = this.board[i][j].charAt(1); + if ( + piece != V.HIDDEN_QUEEN || + // 'side' is used to determine what I see: a pawn or a (hidden)queen? + this.getColor(i, j) == this.side + ) { + return piece; + } + return V.PAWN; + } + + getPpath(b, color, score) { + if (b[1] == V.HIDDEN_QUEEN) { + // Supposed to be hidden. + if (score == "*" && (!color || color != b[0])) + return b[0] + "p"; + return "Hiddenqueen/" + b[0] + "t"; + } + return b; + } + + isValidPawnMove(move) { + const color = move.vanish[0].c; + const pawnShift = color == "w" ? -1 : 1; + const startRank = color == "w" ? V.size.x - 2 : 1; + const lastRank = color == "w" ? 0 : V.size.x - 1; + return ( + // The queen is discovered if she reaches the 8th rank, + // even if this would be a technically valid pawn move. + move.end.x != lastRank && + ( + ( + move.end.x - move.start.x == pawnShift && + ( + ( + // Normal move + move.end.y == move.start.y && + this.board[move.end.x][move.end.y] == V.EMPTY + ) + || + ( + // Capture + Math.abs(move.end.y - move.start.y) == 1 && + this.board[move.end.x][move.end.y] != V.EMPTY + ) + ) + ) + || + ( + // Two-spaces initial jump + move.start.x == startRank && + move.end.y == move.start.y && + move.end.x - move.start.x == 2 * pawnShift && + this.board[move.end.x][move.end.y] == V.EMPTY + ) + ) + ); + } + + getPotentialMovesFrom([x, y]) { + if (this.getPiece(x, y) == V.HIDDEN_QUEEN) { + const pawnMoves = super.getPotentialPawnMoves([x, y]); + let queenMoves = super.getPotentialQueenMoves([x, y]); + // Remove from queen moves those corresponding to a pawn move: + queenMoves = queenMoves + .filter(m => !this.isValidPawnMove(m)) + // Hidden queen is revealed if moving like a queen: + .map(m => { + m.appear[0].p = V.QUEEN; + return m; + }); + return pawnMoves.concat(queenMoves); + } + return super.getPotentialMovesFrom([x, y]); + } + + getPossibleMovesFrom(sq) { + this.side = this.turn; + return this.filterValid(this.getPotentialMovesFrom(sq)); + } + + static GenRandInitFen() { + let fen = ChessRules.GenRandInitFen(); + // Place hidden queens at random: + let hiddenQueenPos = randInt(8); + let pawnRank = "PPPPPPPP".split(""); + pawnRank[hiddenQueenPos] = "T"; + fen = fen.replace("PPPPPPPP", pawnRank.join("")); + hiddenQueenPos = randInt(8); + pawnRank = "pppppppp".split(""); + pawnRank[hiddenQueenPos] = "t"; + fen = fen.replace("pppppppp", pawnRank.join("")); + return fen; + } + + updateVariables(move) { + super.updateVariables(move); + if (move.vanish.length == 2 && move.vanish[1].p == V.KING) + // We took opponent king + this.kingPos[this.turn] = [-1, -1]; + } + + unupdateVariables(move) { + super.unupdateVariables(move); + const c = move.vanish[0].c; + const oppCol = V.GetOppCol(c); + if (this.kingPos[oppCol][0] < 0) + // Last move took opponent's king: + this.kingPos[oppCol] = [move.vanish[1].x, move.vanish[1].y]; + } + + getCurrentScore() { + const color = this.turn; + if (this.kingPos[color][0] < 0) + // King disappeared + return color == "w" ? "0-1" : "1-0"; + return super.getCurrentScore(); + } + + // Search is biased, so not really needed to explore deeply + static get SEARCH_DEPTH() { + return 2; + } + + static get VALUES() { + return Object.assign( + { t: 9 }, + ChessRules.VALUES + ); + } + + getComputerMove() { + this.side = this.turn; + return super.getComputerMove(); + } +};