X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FCoregal.js;h=aa023c1542ec5aa0d96473a51c5dd36caeb4ae79;hb=4313762da3237b04f204e121a20cab3ba7bb5dd2;hp=1a4a4038a031274e6769c528e84136c8a0a25d83;hpb=3f22c2c3939dfd6bd66da26e6d6d9848c6da86d2;p=vchess.git diff --git a/client/src/variants/Coregal.js b/client/src/variants/Coregal.js index 1a4a4038..aa023c15 100644 --- a/client/src/variants/Coregal.js +++ b/client/src/variants/Coregal.js @@ -3,8 +3,9 @@ import { ArrayFun } from "@/utils/array"; import { randInt, sample } from "@/utils/alea"; export class CoregalRules extends ChessRules { + static IsGoodPosition(position) { - if (!super.IsGoodPosition(position)) return false; + if (!ChessRules.IsGoodPosition(position)) return false; const rows = position.split("/"); // Check that at least one queen of each color is there: let queens = {}; @@ -20,8 +21,7 @@ export class CoregalRules extends ChessRules { return !!flags.match(/^[a-z]{8,8}$/); } - // Scanning king position for faster updates is still interesting, - // but no need for INIT_COL_KING because it's given in castle flags. + // Scanning king position for faster updates is still interesting. scanKings(fen) { this.kingPos = { w: [-1, -1], b: [-1, -1] }; const fenRows = V.ParseFen(fen).position.split("/"); @@ -37,7 +37,7 @@ export class CoregalRules extends ChessRules { this.kingPos["w"] = [i, k]; break; default: { - const num = parseInt(fenRows[i].charAt(j)); + const num = parseInt(fenRows[i].charAt(j), 10); if (!isNaN(num)) k += num - 1; } } @@ -46,7 +46,20 @@ export class CoregalRules extends ChessRules { } } - getCheckSquares(color) { + getPPpath(m) { + if ( + m.vanish.length == 2 && + m.appear.length == 2 && + m.vanish[0].p == V.QUEEN + ) { + // Large castle: show castle symbol + return "Coregal/castle"; + } + return super.getPPpath(m); + } + + getCheckSquares() { + const color = this.turn; let squares = []; const oppCol = V.GetOppCol(color); if (this.isAttacked(this.kingPos[color], oppCol)) @@ -65,26 +78,26 @@ export class CoregalRules extends ChessRules { return squares; } - static GenRandInitFen(randomness) { - if (randomness == 0) + static GenRandInitFen(options) { + if (options.randomness == 0) // Castle flags here indicate pieces positions (if can castle) return "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0 adehadeh -"; let pieces = { w: new Array(8), b: new Array(8) }; let flags = ""; for (let c of ["w", "b"]) { - if (c == 'b' && randomness == 1) { + if (c == 'b' && options.randomness == 1) { pieces['b'] = pieces['w']; flags += flags; break; } // Get random squares for king and queen between b and g files - let randIndex = randInt(6); - let kingPos = randIndex + 1; - randIndex = randInt(5); + let randIndex = randInt(6) + 1; + let kingPos = randIndex; + randIndex = randInt(5) + 1; if (randIndex >= kingPos) randIndex++; - let queenPos = randIndex + 1; + let queenPos = randIndex; // Get random squares for rooks to the left and right of the queen // and king: not all squares of the same colors (for bishops). @@ -122,8 +135,10 @@ export class CoregalRules extends ChessRules { if (!!bishop1Options[pos]) delete bishop1Options[pos]; else if (!!bishop2Options[pos]) delete bishop2Options[pos]; }); - const bishop1Pos = parseInt(sample(Object.keys(bishop1Options), 1)[0]); - const bishop2Pos = parseInt(sample(Object.keys(bishop2Options), 1)[0]); + const bishop1Pos = + parseInt(sample(Object.keys(bishop1Options), 1)[0], 10); + const bishop2Pos = + parseInt(sample(Object.keys(bishop2Options), 1)[0], 10); // Knights' positions are now determined const forbidden = [ @@ -140,8 +155,8 @@ export class CoregalRules extends ChessRules { pieces[c][bishop2Pos] = "b"; pieces[c][knight2Pos] = "n"; pieces[c][rook2Pos] = "r"; - flags += - [rook1Pos, queenPos, kingPos, rook2Pos].sort().map(V.CoordToColumn).join(""); + flags += [rook1Pos, queenPos, kingPos, rook2Pos] + .sort().map(V.CoordToColumn).join(""); } // Add turn + flags + enpassant return ( @@ -161,93 +176,39 @@ export class CoregalRules extends ChessRules { } } - getPotentialQueenMoves(sq) { - return super.getPotentialQueenMoves(sq).concat(this.getCastleMoves(sq)); + getPotentialQueenMoves([x, y]) { + let moves = super.getPotentialQueenMoves([x, y]); + const c = this.getColor(x, y); + if (this.castleFlags[c].slice(1, 3).includes(y)) + moves = moves.concat(this.getCastleMoves([x, y])); + return moves; } - getCastleMoves([x, y]) { + getPotentialKingMoves([x, y]) { + let moves = this.getSlideNJumpMoves( + [x, y], V.steps[V.ROOK].concat(V.steps[V.BISHOP]), 1); const c = this.getColor(x, y); - if ( - x != (c == "w" ? V.size.x - 1 : 0) || - !this.castleFlags[c].slice(1, 3).includes(y) - ) { - // x isn't first rank, or piece moved - return []; - } - const castlingPiece = this.getPiece(x, y); + if (this.castleFlags[c].slice(1, 3).includes(y)) + moves = moves.concat(this.getCastleMoves([x, y])); + return moves; + } + getCastleMoves([x, y]) { // Relative position of the selected piece: left or right ? // If left: small castle left, large castle right. // If right: usual situation. + const c = this.getColor(x, y); const relPos = (this.castleFlags[c][1] == y ? "left" : "right"); - // Castling ? - const oppCol = V.GetOppCol(c); - let moves = []; - let i = 0; - // Castling piece, then rook: - const finalSquares = { - 0: (relPos == "left" ? [1, 2] : [2, 3]), - 3: (relPos == "right" ? [6, 5] : [5, 4]) - }; - - // Left, then right castle: - castlingCheck: for (let castleSide of [0, 3]) { - if (this.castleFlags[c][castleSide] >= 8) continue; - - // Rook and castling piece are on initial position - const rookPos = this.castleFlags[c][castleSide]; - - // Nothing on the path of the king ? (and no checks) - const finDist = finalSquares[castleSide][0] - y; - let step = finDist / Math.max(1, Math.abs(finDist)); - i = y; - do { - if ( - 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 || - ![castlingPiece, V.ROOK].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 castling piece and rook? - for (i = 0; i < 2; i++) { - if ( - this.board[x][finalSquares[castleSide][i]] != V.EMPTY && - ![y, rookPos].includes(finalSquares[castleSide][i]) - ) { - continue castlingCheck; - } - } - - // If this code is reached, castle is valid - moves.push( - new Move({ - appear: [ - new PiPo({ x: x, y: finalSquares[castleSide][0], p: castlingPiece, c: c }), - new PiPo({ x: x, y: finalSquares[castleSide][1], p: V.ROOK, c: c }) - ], - vanish: [ - new PiPo({ x: x, y: y, p: castlingPiece, c: c }), - new PiPo({ x: x, y: rookPos, p: V.ROOK, c: c }) - ], - // In this variant, always castle by playing onto the rook - end: { x: x, y: rookPos } - }) - ); - } - + const finalSquares = [ + relPos == "left" ? [1, 2] : [2, 3], + relPos == "right" ? [6, 5] : [5, 4] + ]; + const saveFlags = JSON.stringify(this.castleFlags[c]); + // Alter flags to follow base_rules semantic + this.castleFlags[c] = [0, 3].map(i => this.castleFlags[c][i]); + const moves = super.getCastleMoves([x, y], finalSquares); + this.castleFlags[c] = JSON.parse(saveFlags); return moves; } @@ -268,18 +229,21 @@ export class CoregalRules extends ChessRules { return false; } - updateCastleFlags(move, piece) { + // "twoKings" arg for the similar Twokings variant. + updateCastleFlags(move, piece, twoKings) { const c = V.GetOppCol(this.turn); const firstRank = (c == "w" ? V.size.x - 1 : 0); // Update castling flags if castling pieces moved or were captured const oppCol = V.GetOppCol(c); const oppFirstRank = V.size.x - 1 - firstRank; - if (move.start.x == firstRank && [V.KING, V.QUEEN].includes(piece)) { - if (this.castleFlags[c][1] == move.start.y) - this.castleFlags[c][1] = 8; - else if (this.castleFlags[c][2] == move.start.y) - this.castleFlags[c][2] = 8; - // Else: the flag is already turned off + if (move.start.x == firstRank) { + if (piece == V.KING || (!twoKings && piece == V.QUEEN)) { + if (this.castleFlags[c][1] == move.start.y) + this.castleFlags[c][1] = 8; + else if (this.castleFlags[c][2] == move.start.y) + this.castleFlags[c][2] = 8; + // Else: the flag is already turned off + } } else if ( move.start.x == firstRank && //our rook moves? @@ -289,7 +253,8 @@ export class CoregalRules extends ChessRules { this.castleFlags[c][flagIdx] = 8; } else if ( move.end.x == oppFirstRank && //we took opponent rook? - [this.castleFlags[oppCol][0], this.castleFlags[oppCol][3]].includes(move.end.y) + [this.castleFlags[oppCol][0], this.castleFlags[oppCol][3]] + .includes(move.end.y) ) { const flagIdx = (move.end.y == this.castleFlags[oppCol][0] ? 0 : 3); this.castleFlags[oppCol][flagIdx] = 8; @@ -298,6 +263,10 @@ export class CoregalRules extends ChessRules { // NOTE: do not set queen value to 1000 or so, because there may be several. + static get SEARCH_DEPTH() { + return 2; + } + getNotation(move) { if (move.appear.length == 2) { // Castle: determine the right notation @@ -320,4 +289,5 @@ export class CoregalRules extends ChessRules { } return super.getNotation(move); } + };