X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FBaroque.js;h=79fc73cec5c0f92ee8610823216a15845bf1ca7d;hb=6808d7a16ec1e761c6a2dffec2281c96953e4d89;hp=88c993a9a0818aa80cbe2b63e5c57525a7d59067;hpb=dac395887d96e2d642b209c6db6aaacc3ffacb34;p=vchess.git diff --git a/client/src/variants/Baroque.js b/client/src/variants/Baroque.js index 88c993a9..79fc73ce 100644 --- a/client/src/variants/Baroque.js +++ b/client/src/variants/Baroque.js @@ -2,54 +2,54 @@ import { ChessRules, PiPo, Move } from "@/base_rules"; import { ArrayFun } from "@/utils/array"; import { randInt } from "@/utils/alea"; -export const VariantRules = class BaroqueRules extends ChessRules -{ - static get HasFlags() { return false; } +export const VariantRules = class BaroqueRules extends ChessRules { + static get HasFlags() { + return false; + } - static get HasEnpassant() { return false; } + static get HasEnpassant() { + return false; + } - static getPpath(b) - { - if (b[1] == "m") //'m' for Immobilizer (I is too similar to 1) + static getPpath(b) { + if (b[1] == "m") + //'m' for Immobilizer (I is too similar to 1) return "Baroque/" + b; return b; //usual piece } - static get PIECES() - { + static get PIECES() { return ChessRules.PIECES.concat([V.IMMOBILIZER]); } // No castling, but checks, so keep track of kings - setOtherVariables(fen) - { - this.kingPos = {'w':[-1,-1], 'b':[-1,-1]}; + setOtherVariables(fen) { + this.kingPos = { w: [-1, -1], b: [-1, -1] }; const fenParts = fen.split(" "); const position = fenParts[0].split("/"); - for (let i=0; i { - if (!!byChameleon && m.start.x!=m.end.x && m.start.y!=m.end.y) - return; //chameleon not moving as pawn + if (!!byChameleon && m.start.x != m.end.x && m.start.y != m.end.y) return; //chameleon not moving as pawn // Try capturing in every direction - for (let step of steps) - { - const sq2 = [m.end.x+2*step[0],m.end.y+2*step[1]]; - if (V.OnBoard(sq2[0],sq2[1]) && this.board[sq2[0]][sq2[1]] != V.EMPTY - && this.getColor(sq2[0],sq2[1]) == color) - { + for (let step of steps) { + const sq2 = [m.end.x + 2 * step[0], m.end.y + 2 * step[1]]; + if ( + V.OnBoard(sq2[0], sq2[1]) && + this.board[sq2[0]][sq2[1]] != V.EMPTY && + this.getColor(sq2[0], sq2[1]) == color + ) { // Potential capture - const sq1 = [m.end.x+step[0],m.end.y+step[1]]; - if (this.board[sq1[0]][sq1[1]] != V.EMPTY - && this.getColor(sq1[0],sq1[1]) == oppCol) - { - const piece1 = this.getPiece(sq1[0],sq1[1]); - if (!byChameleon || piece1 == V.PAWN) - { - m.vanish.push(new PiPo({ - x:sq1[0], - y:sq1[1], - c:oppCol, - p:piece1 - })); + const sq1 = [m.end.x + step[0], m.end.y + step[1]]; + if ( + this.board[sq1[0]][sq1[1]] != V.EMPTY && + this.getColor(sq1[0], sq1[1]) == oppCol + ) { + const piece1 = this.getPiece(sq1[0], sq1[1]); + if (!byChameleon || piece1 == V.PAWN) { + m.vanish.push( + new PiPo({ + x: sq1[0], + y: sq1[1], + c: oppCol, + p: piece1 + }) + ); } } } @@ -174,37 +163,33 @@ export const VariantRules = class BaroqueRules extends ChessRules } // "Pincer" - getPotentialPawnMoves([x,y]) - { - let moves = super.getPotentialRookMoves([x,y]); + getPotentialPawnMoves([x, y]) { + let moves = super.getPotentialRookMoves([x, y]); this.addPawnCaptures(moves); return moves; } - addRookCaptures(moves, byChameleon) - { + addRookCaptures(moves, byChameleon) { const color = this.turn; const oppCol = V.GetOppCol(color); const kp = this.kingPos[color]; moves.forEach(m => { // Check piece-king rectangle (if any) corners for enemy pieces - if (m.end.x == kp[0] || m.end.y == kp[1]) - return; //"flat rectangle" + if (m.end.x == kp[0] || m.end.y == kp[1]) return; //"flat rectangle" const corner1 = [m.end.x, kp[1]]; const corner2 = [kp[0], m.end.y]; - for (let [i,j] of [corner1,corner2]) - { - if (this.board[i][j] != V.EMPTY && this.getColor(i,j) == oppCol) - { - const piece = this.getPiece(i,j); - if (!byChameleon || piece == V.ROOK) - { - m.vanish.push( new PiPo({ - x:i, - y:j, - p:piece, - c:oppCol - }) ); + for (let [i, j] of [corner1, corner2]) { + if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == oppCol) { + const piece = this.getPiece(i, j); + if (!byChameleon || piece == V.ROOK) { + m.vanish.push( + new PiPo({ + x: i, + y: j, + p: piece, + c: oppCol + }) + ); } } } @@ -212,88 +197,84 @@ export const VariantRules = class BaroqueRules extends ChessRules } // Coordinator - getPotentialRookMoves(sq) - { + getPotentialRookMoves(sq) { let moves = super.getPotentialQueenMoves(sq); this.addRookCaptures(moves); return moves; } // Long-leaper - getKnightCaptures(startSquare, byChameleon) - { + getKnightCaptures(startSquare, byChameleon) { // Look in every direction for captures const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); const color = this.turn; const oppCol = V.GetOppCol(color); let moves = []; - const [x,y] = [startSquare[0],startSquare[1]]; - const piece = this.getPiece(x,y); //might be a chameleon! - outerLoop: - for (let step of steps) - { - let [i,j] = [x+step[0], y+step[1]]; - while (V.OnBoard(i,j) && this.board[i][j]==V.EMPTY) - { + const [x, y] = [startSquare[0], startSquare[1]]; + const piece = this.getPiece(x, y); //might be a chameleon! + outerLoop: for (let step of steps) { + let [i, j] = [x + step[0], y + step[1]]; + while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) { i += step[0]; j += step[1]; } - if (!V.OnBoard(i,j) || this.getColor(i,j)==color - || (!!byChameleon && this.getPiece(i,j)!=V.KNIGHT)) - { + if ( + !V.OnBoard(i, j) || + this.getColor(i, j) == color || + (!!byChameleon && this.getPiece(i, j) != V.KNIGHT) + ) { continue; } // last(thing), cur(thing) : stop if "cur" is our color, or beyond board limits, // or if "last" isn't empty and cur neither. Otherwise, if cur is empty then // add move until cur square; if cur is occupied then stop if !!byChameleon and // the square not occupied by a leaper. - let last = [i,j]; - let cur = [i+step[0],j+step[1]]; - let vanished = [ new PiPo({x:x,y:y,c:color,p:piece}) ]; - while (V.OnBoard(cur[0],cur[1])) - { - if (this.board[last[0]][last[1]] != V.EMPTY) - { - const oppPiece = this.getPiece(last[0],last[1]); - if (!!byChameleon && oppPiece != V.KNIGHT) - continue outerLoop; + let last = [i, j]; + let cur = [i + step[0], j + step[1]]; + let vanished = [new PiPo({ x: x, y: y, c: color, p: piece })]; + while (V.OnBoard(cur[0], cur[1])) { + if (this.board[last[0]][last[1]] != V.EMPTY) { + const oppPiece = this.getPiece(last[0], last[1]); + if (!!byChameleon && oppPiece != V.KNIGHT) continue outerLoop; // Something to eat: - vanished.push( new PiPo({x:last[0],y:last[1],c:oppCol,p:oppPiece}) ); + vanished.push( + new PiPo({ x: last[0], y: last[1], c: oppCol, p: oppPiece }) + ); } - if (this.board[cur[0]][cur[1]] != V.EMPTY) - { - if (this.getColor(cur[0],cur[1]) == color - || this.board[last[0]][last[1]] != V.EMPTY) //TODO: redundant test - { + if (this.board[cur[0]][cur[1]] != V.EMPTY) { + if ( + this.getColor(cur[0], cur[1]) == color || + this.board[last[0]][last[1]] != V.EMPTY + ) { + //TODO: redundant test continue outerLoop; } + } else { + moves.push( + new Move({ + appear: [new PiPo({ x: cur[0], y: cur[1], c: color, p: piece })], + vanish: JSON.parse(JSON.stringify(vanished)), //TODO: required? + start: { x: x, y: y }, + end: { x: cur[0], y: cur[1] } + }) + ); } - else - { - moves.push(new Move({ - appear: [ new PiPo({x:cur[0],y:cur[1],c:color,p:piece}) ], - vanish: JSON.parse(JSON.stringify(vanished)), //TODO: required? - start: {x:x,y:y}, - end: {x:cur[0],y:cur[1]} - })); - } - last = [last[0]+step[0],last[1]+step[1]]; - cur = [cur[0]+step[0],cur[1]+step[1]]; + last = [last[0] + step[0], last[1] + step[1]]; + cur = [cur[0] + step[0], cur[1] + step[1]]; } } return moves; } // Long-leaper - getPotentialKnightMoves(sq) - { + getPotentialKnightMoves(sq) { return super.getPotentialQueenMoves(sq).concat(this.getKnightCaptures(sq)); } - getPotentialBishopMoves([x,y]) - { - let moves = super.getPotentialQueenMoves([x,y]) - .concat(this.getKnightCaptures([x,y],"asChameleon")); + getPotentialBishopMoves([x, y]) { + let moves = super + .getPotentialQueenMoves([x, y]) + .concat(this.getKnightCaptures([x, y], "asChameleon")); // No "king capture" because king cannot remain under check this.addPawnCaptures(moves, "asChameleon"); this.addRookCaptures(moves, "asChameleon"); @@ -302,111 +283,119 @@ export const VariantRules = class BaroqueRules extends ChessRules let mergedMoves = {}; moves.forEach(m => { const key = m.end.x + V.size.x * m.end.y; - if (!mergedMoves[key]) - mergedMoves[key] = m; - else - { - for (let i=1; i { moves.push(mergedMoves[k]); }); + Object.keys(mergedMoves).forEach(k => { + moves.push(mergedMoves[k]); + }); return moves; } // Withdrawer - addQueenCaptures(moves, byChameleon) - { - if (moves.length == 0) - return; - const [x,y] = [moves[0].start.x,moves[0].start.y]; + addQueenCaptures(moves, byChameleon) { + if (moves.length == 0) return; + const [x, y] = [moves[0].start.x, moves[0].start.y]; const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); let capturingDirections = []; const color = this.turn; const oppCol = V.GetOppCol(color); adjacentSteps.forEach(step => { - const [i,j] = [x+step[0],y+step[1]]; - if (V.OnBoard(i,j) && this.board[i][j] != V.EMPTY && this.getColor(i,j) == oppCol - && (!byChameleon || this.getPiece(i,j) == V.QUEEN)) - { + const [i, j] = [x + step[0], y + step[1]]; + if ( + V.OnBoard(i, j) && + this.board[i][j] != V.EMPTY && + this.getColor(i, j) == oppCol && + (!byChameleon || this.getPiece(i, j) == V.QUEEN) + ) { capturingDirections.push(step); } }); moves.forEach(m => { const step = [ - m.end.x!=x ? (m.end.x-x)/Math.abs(m.end.x-x) : 0, - m.end.y!=y ? (m.end.y-y)/Math.abs(m.end.y-y) : 0 + m.end.x != x ? (m.end.x - x) / Math.abs(m.end.x - x) : 0, + m.end.y != y ? (m.end.y - y) / Math.abs(m.end.y - y) : 0 ]; // NOTE: includes() and even _.isEqual() functions fail... // TODO: this test should be done only once per direction - if (capturingDirections.some(dir => - { return (dir[0]==-step[0] && dir[1]==-step[1]); })) - { - const [i,j] = [x-step[0],y-step[1]]; - m.vanish.push(new PiPo({ - x:i, - y:j, - p:this.getPiece(i,j), - c:oppCol - })); + if ( + capturingDirections.some(dir => { + return dir[0] == -step[0] && dir[1] == -step[1]; + }) + ) { + const [i, j] = [x - step[0], y - step[1]]; + m.vanish.push( + new PiPo({ + x: i, + y: j, + p: this.getPiece(i, j), + c: oppCol + }) + ); } }); } - getPotentialQueenMoves(sq) - { + getPotentialQueenMoves(sq) { let moves = super.getPotentialQueenMoves(sq); this.addQueenCaptures(moves); return moves; } - getPotentialImmobilizerMoves(sq) - { + getPotentialImmobilizerMoves(sq) { // Immobilizer doesn't capture return super.getPotentialQueenMoves(sq); } - getPotentialKingMoves(sq) - { - return this.getSlideNJumpMoves(sq, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep"); + getPotentialKingMoves(sq) { + return this.getSlideNJumpMoves( + sq, + V.steps[V.ROOK].concat(V.steps[V.BISHOP]), + "oneStep" + ); } // isAttacked() is OK because the immobilizer doesn't take - isAttackedByPawn([x,y], colors) - { + isAttackedByPawn([x, y], colors) { // Square (x,y) must be surroundable by two enemy pieces, // and one of them at least should be a pawn (moving). - const dirs = [ [1,0],[0,1] ]; + const dirs = [ + [1, 0], + [0, 1] + ]; const steps = V.steps[V.ROOK]; - for (let dir of dirs) - { - const [i1,j1] = [x-dir[0],y-dir[1]]; //"before" - const [i2,j2] = [x+dir[0],y+dir[1]]; //"after" - if (V.OnBoard(i1,j1) && V.OnBoard(i2,j2)) - { - if ((this.board[i1][j1]!=V.EMPTY && colors.includes(this.getColor(i1,j1)) - && this.board[i2][j2]==V.EMPTY) - || - (this.board[i2][j2]!=V.EMPTY && colors.includes(this.getColor(i2,j2)) - && this.board[i1][j1]==V.EMPTY)) - { + for (let dir of dirs) { + const [i1, j1] = [x - dir[0], y - dir[1]]; //"before" + const [i2, j2] = [x + dir[0], y + dir[1]]; //"after" + if (V.OnBoard(i1, j1) && V.OnBoard(i2, j2)) { + if ( + (this.board[i1][j1] != V.EMPTY && + colors.includes(this.getColor(i1, j1)) && + this.board[i2][j2] == V.EMPTY) || + (this.board[i2][j2] != V.EMPTY && + colors.includes(this.getColor(i2, j2)) && + this.board[i1][j1] == V.EMPTY) + ) { // Search a movable enemy pawn landing on the empty square - for (let step of steps) - { - let [ii,jj] = (this.board[i1][j1]==V.EMPTY ? [i1,j1] : [i2,j2]); - let [i3,j3] = [ii+step[0],jj+step[1]]; - while (V.OnBoard(i3,j3) && this.board[i3][j3]==V.EMPTY) - { + for (let step of steps) { + let [ii, jj] = this.board[i1][j1] == V.EMPTY ? [i1, j1] : [i2, j2]; + let [i3, j3] = [ii + step[0], jj + step[1]]; + while (V.OnBoard(i3, j3) && this.board[i3][j3] == V.EMPTY) { i3 += step[0]; j3 += step[1]; } - if (V.OnBoard(i3,j3) && colors.includes(this.getColor(i3,j3)) - && this.getPiece(i3,j3) == V.PAWN && !this.isImmobilized([i3,j3])) - { + if ( + V.OnBoard(i3, j3) && + colors.includes(this.getColor(i3, j3)) && + this.getPiece(i3, j3) == V.PAWN && + !this.isImmobilized([i3, j3]) + ) { return true; } } @@ -416,31 +405,30 @@ export const VariantRules = class BaroqueRules extends ChessRules return false; } - isAttackedByRook([x,y], colors) - { + isAttackedByRook([x, y], colors) { // King must be on same column or row, // and a rook should be able to reach a capturing square // colors contains only one element, giving the oppCol and thus king position - const sameRow = (x == this.kingPos[colors[0]][0]); - const sameColumn = (y == this.kingPos[colors[0]][1]); - if (sameRow || sameColumn) - { + const sameRow = x == this.kingPos[colors[0]][0]; + const sameColumn = y == this.kingPos[colors[0]][1]; + if (sameRow || sameColumn) { // Look for the enemy rook (maximum 1) - for (let i=0; i1 ? "x" : "") + finalSquare; - else - notation = move.appear[0].p.toUpperCase() + finalSquare; - if (move.vanish.length > 1 && move.appear[0].p != V.KING) - notation += "X"; //capture mark (not describing what is captured...) + } else if (move.appear[0].p == V.KING) + notation = "K" + (move.vanish.length > 1 ? "x" : "") + finalSquare; + else notation = move.appear[0].p.toUpperCase() + finalSquare; + if (move.vanish.length > 1 && move.appear[0].p != V.KING) notation += "X"; //capture mark (not describing what is captured...) return notation; } -} +};