From: Benjamin Auder Date: Fri, 14 Dec 2018 18:30:57 +0000 (+0100) Subject: Code simplification + a few fixes X-Git-Url: https://git.auder.net/doc/html/%7B%7B%20asset%28%27mixstore/images/img/cross.svg?a=commitdiff_plain;h=0b7d99ecbb5dedc02cd96c457b5fc2962db9b297;p=vchess.git Code simplification + a few fixes --- diff --git a/public/javascripts/base_rules.js b/public/javascripts/base_rules.js index 63b535da..51c9dda8 100644 --- a/public/javascripts/base_rules.js +++ b/public/javascripts/base_rules.js @@ -55,7 +55,7 @@ class ChessRules { this.moves = moves; // Use fen string to initialize variables, flags and board - this.board = VariantRules.GetBoard(fen); + this.board = V.GetBoard(fen); this.setFlags(fen); this.initVariables(fen); } @@ -102,7 +102,7 @@ class ChessRules k++; } } - const epSq = this.moves.length > 0 ? this.getEpSquare(this.lastMove) : undefined; + const epSq = (this.moves.length > 0 ? this.getEpSquare(this.lastMove) : undefined); this.epSquares = [ epSq ]; } @@ -110,8 +110,7 @@ class ChessRules static GetBoard(fen) { let rows = fen.split(" ")[0].split("/"); - const [sizeX,sizeY] = VariantRules.size; - let board = doubleArray(sizeX, sizeY, ""); + let board = doubleArray(V.size.x, V.size.y, ""); for (let i=0; i0 ? this.moves[L-1] : null; + return (L>0 ? this.moves[L-1] : null); } + get turn() { - return this.moves.length%2==0 ? 'w' : 'b'; + return (this.moves.length%2==0 ? 'w' : 'b'); } // Pieces codes @@ -192,7 +193,7 @@ class ChessRules getEpSquare(move) { const [sx,sy,ex] = [move.start.x,move.start.y,move.end.x]; - if (this.getPiece(sx,sy) == VariantRules.PAWN && Math.abs(sx - ex) == 2) + if (this.getPiece(sx,sy) == V.PAWN && Math.abs(sx - ex) == 2) { return { x: (sx + ex)/2, @@ -205,7 +206,7 @@ class ChessRules // Can thing on square1 take thing on square2 canTake([x1,y1], [x2,y2]) { - return this.getColor(x1,y1) != this.getColor(x2,y2); + return this.getColor(x1,y1) !== this.getColor(x2,y2); } /////////////////// @@ -216,17 +217,17 @@ class ChessRules { switch (this.getPiece(x,y)) { - case VariantRules.PAWN: + case V.PAWN: return this.getPotentialPawnMoves([x,y]); - case VariantRules.ROOK: + case V.ROOK: return this.getPotentialRookMoves([x,y]); - case VariantRules.KNIGHT: + case V.KNIGHT: return this.getPotentialKnightMoves([x,y]); - case VariantRules.BISHOP: + case V.BISHOP: return this.getPotentialBishopMoves([x,y]); - case VariantRules.QUEEN: + case V.QUEEN: return this.getPotentialQueenMoves([x,y]); - case VariantRules.KING: + case V.KING: return this.getPotentialKingMoves([x,y]); } } @@ -254,7 +255,7 @@ class ChessRules }); // The opponent piece disappears if we take it - if (this.board[ex][ey] != VariantRules.EMPTY) + if (this.board[ex][ey] != V.EMPTY) { mv.vanish.push( new PiPo({ @@ -268,19 +269,23 @@ class ChessRules return mv; } + // Is (x,y) on the chessboard? + static OnBoard(x,y) + { + return (x>=0 && x=0 && y=0 && i=0 && j=0 && i=0 && j0 && this.canTake([x,y], [x+shift,y-1]) - && this.board[x+shift][y-1] != V.EMPTY) + if (y>0 && this.board[x+shift][y-1] != V.EMPTY + && this.canTake([x,y], [x+shift,y-1])) { moves.push(this.getBasicMove([x,y], [x+shift,y-1])); } - if (y0 && this.canTake([x,y], [x+shift,y-1]) - && this.board[x+shift][y-1] != V.EMPTY) + if (y>0 && this.board[x+shift][y-1] != V.EMPTY + && this.canTake([x,y], [x+shift,y-1])) { moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:pawnColor,p:p})); } - if (y0 ? this.epSquares[Lep-1] : undefined; + const epSquare = (Lep>0 ? this.epSquares[Lep-1] : undefined); if (!!epSquare && epSquare.x == x+shift && Math.abs(epSquare.y - y) == 1) { - let epStep = epSquare.y - y; - var enpassantMove = this.getBasicMove([x,y], [x+shift,y+epStep]); + const epStep = epSquare.y - y; + let enpassantMove = this.getBasicMove([x,y], [x+shift,y+epStep]); enpassantMove.vanish.push({ x: x, y: y+epStep, @@ -377,33 +381,30 @@ class ChessRules // What are the rook moves from square x,y ? getPotentialRookMoves(sq) { - return this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.ROOK]); + return this.getSlideNJumpMoves(sq, V.steps[V.ROOK]); } // What are the knight moves from square x,y ? getPotentialKnightMoves(sq) { - return this.getSlideNJumpMoves( - sq, VariantRules.steps[VariantRules.KNIGHT], "oneStep"); + return this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep"); } // What are the bishop moves from square x,y ? getPotentialBishopMoves(sq) { - return this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.BISHOP]); + return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]); } // What are the queen moves from square x,y ? getPotentialQueenMoves(sq) { - const V = VariantRules; return this.getSlideNJumpMoves(sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP])); } // What are the king moves from square x,y ? getPotentialKingMoves(sq) { - const V = VariantRules; // Initialize with normal moves let moves = this.getSlideNJumpMoves(sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep"); @@ -413,17 +414,14 @@ class ChessRules getCastleMoves([x,y]) { const c = this.getColor(x,y); - const [sizeX,sizeY] = VariantRules.size; - if (x != (c=="w" ? sizeX-1 : 0) || y != this.INIT_COL_KING[c]) + if (x != (c=="w" ? V.size.x-1 : 0) || y != this.INIT_COL_KING[c]) return []; //x isn't first rank, or king has moved (shortcut) - const V = VariantRules; - // Castling ? const oppCol = this.getOppCol(c); let moves = []; let i = 0; - const finalSquares = [ [2,3], [sizeY-2,sizeY-3] ]; //king, then rook + const finalSquares = [ [2,3], [V.size.y-2,V.size.y-3] ]; //king, then rook castlingCheck: for (let castleSide=0; castleSide < 2; castleSide++) //large, then small { @@ -510,13 +508,12 @@ class ChessRules const color = this.turn; const oppCol = this.getOppCol(color); let potentialMoves = []; - const [sizeX,sizeY] = VariantRules.size; - for (let i=0; i 0) @@ -566,15 +562,14 @@ class ChessRules // Is square x,y attacked by 'colors' pawns ? isAttackedByPawn([x,y], colors) { - const [sizeX,sizeY] = VariantRules.size; for (let c of colors) { let pawnShift = (c=="w" ? 1 : -1); - if (x+pawnShift>=0 && x+pawnShift=0 && x+pawnShift=0 && y+i=0 && y+i=0 && rx=0 && ry=0 && rx=0 && ry 0) + if (piece == V.KING && move.appear.length > 0) { this.kingPos[c][0] = move.appear[0].x; this.kingPos[c][1] = move.appear[0].y; @@ -702,7 +689,7 @@ class ChessRules return; } const oppCol = this.getOppCol(c); - const oppFirstRank = (sizeX-1) - firstRank; + const oppFirstRank = (V.size.x-1) - firstRank; if (move.start.x == firstRank //our rook moves? && this.INIT_COL_ROOK[c].includes(move.start.y)) { @@ -723,7 +710,7 @@ class ChessRules { // (Potentially) Reset king position const c = this.getColor(move.start.x,move.start.y); - if (this.getPiece(move.start.x,move.start.y) == VariantRules.KING) + if (this.getPiece(move.start.x,move.start.y) == V.KING) this.kingPos[c] = [move.start.x, move.start.y]; } @@ -746,7 +733,7 @@ class ChessRules this.updateVariables(move); this.moves.push(move); this.epSquares.push( this.getEpSquare(move) ); - VariantRules.PlayOnBoard(this.board, move); + V.PlayOnBoard(this.board, move); if (!!ingame) move.hash = this.getHashState(); @@ -754,7 +741,7 @@ class ChessRules undo(move) { - VariantRules.UndoOnBoard(this.board, move); + V.UndoOnBoard(this.board, move); this.epSquares.pop(); this.moves.pop(); this.unupdateVariables(move); @@ -834,7 +821,7 @@ class ChessRules static get THRESHOLD_MATE() { // At this value or above, the game is over - return VariantRules.INFINITY; + return V.INFINITY; } static get SEARCH_DEPTH() { @@ -845,7 +832,7 @@ class ChessRules // NOTE: works also for extinction chess because depth is 3... getComputerMove() { - const maxeval = VariantRules.INFINITY; + const maxeval = V.INFINITY; const color = this.turn; // Some variants may show a bigger moves list to the human (Switching), // thus the argument "computer" below (which is generally ignored) @@ -855,7 +842,14 @@ class ChessRules for (let i of _.shuffle(_.range(moves1.length))) { this.play(moves1[i]); - const finish = (Math.abs(this.evalPosition()) >= VariantRules.THRESHOLD_MATE); + let finish = (Math.abs(this.evalPosition()) >= V.THRESHOLD_MATE); + if (!finish && !this.atLeastOneMove()) + { + // Try mate (for other variants) + const score = this.checkGameEnd(); + if (score != "1/2") + finish = true; + } this.undo(moves1[i]); if (finish) return moves1[i]; @@ -913,8 +907,7 @@ class ChessRules const timeStart = Date.now(); // Skip depth 3+ if we found a checkmate (or if we are checkmated in 1...) - if (VariantRules.SEARCH_DEPTH >= 3 - && Math.abs(moves1[0].eval) < VariantRules.THRESHOLD_MATE) + if (V.SEARCH_DEPTH >= 3 && Math.abs(moves1[0].eval) < V.THRESHOLD_MATE) { for (let i=0; i { return (color=="w" ? 1 : -1) * (b.eval - a.eval); }); @@ -940,7 +933,7 @@ class ChessRules alphabeta(depth, alpha, beta) { - const maxeval = VariantRules.INFINITY; + const maxeval = V.INFINITY; const color = this.turn; if (!this.atLeastOneMove()) { @@ -986,17 +979,16 @@ class ChessRules evalPosition() { - const [sizeX,sizeY] = VariantRules.size; let evaluation = 0; // Just count material for now - for (let i=0; i 0) @@ -1093,7 +1084,7 @@ class ChessRules // "Flush remainder" fen += emptyCount; } - if (i < sizeX - 1) + if (i < V.size.x - 1) fen += "/"; //separate rows } return fen; @@ -1115,15 +1106,14 @@ class ChessRules // Context: just before move is played, turn hasn't changed getNotation(move) { - if (move.appear.length == 2 && move.appear[0].p == VariantRules.KING) //castle + if (move.appear.length == 2 && move.appear[0].p == V.KING) //castle return (move.end.y < move.start.y ? "0-0-0" : "0-0"); // Translate final square - const finalSquare = - String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x); + const finalSquare = String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x); const piece = this.getPiece(move.start.x, move.start.y); - if (piece == VariantRules.PAWN) + if (piece == V.PAWN) { // Pawn move let notation = ""; @@ -1152,9 +1142,8 @@ class ChessRules getLongNotation(move) { const startSquare = - String.fromCharCode(97 + move.start.y) + (VariantRules.size[0]-move.start.x); - const finalSquare = - String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x); + String.fromCharCode(97 + move.start.y) + (V.size.x-move.start.x); + const finalSquare = String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x); return startSquare + finalSquare; //not encoding move. But short+long is enough } diff --git a/public/javascripts/components/game.js b/public/javascripts/components/game.js index deccd5da..63bf675c 100644 --- a/public/javascripts/components/game.js +++ b/public/javascripts/components/game.js @@ -24,7 +24,7 @@ Vue.component('my-game', { }; }, render(h) { - const [sizeX,sizeY] = VariantRules.size; + const [sizeX,sizeY] = [V.size.x,V.size.y]; const smallScreen = (window.innerWidth <= 420); // Precompute hints squares to facilitate rendering let hintSquares = doubleArray(sizeX, sizeY, false); diff --git a/public/javascripts/components/rules.js b/public/javascripts/components/rules.js index 25f8a3bd..c3107a67 100644 --- a/public/javascripts/components/rules.js +++ b/public/javascripts/components/rules.js @@ -21,7 +21,7 @@ Vue.component('my-rules', { }, methods: { drawDiag: function(fen) { - let [sizeX,sizeY] = VariantRules.size; + let [sizeX,sizeY] = [V.size.x,V.size.y]; let fenParts = fen.split(" "); // Obtain array of pieces images names let board = VariantRules.GetBoard(fenParts[0]); diff --git a/public/javascripts/variants/Alice.js b/public/javascripts/variants/Alice.js index 220fbd40..5e10a059 100644 --- a/public/javascripts/variants/Alice.js +++ b/public/javascripts/variants/Alice.js @@ -65,7 +65,6 @@ class AliceRules extends ChessRules getSquareOccupation(i, j, mirrorSide) { const piece = this.getPiece(i,j); - const V = VariantRules; if (mirrorSide==1 && Object.keys(V.ALICE_CODES).includes(piece)) return this.board[i][j]; else if (mirrorSide==2 && Object.keys(V.ALICE_PIECES).includes(piece)) @@ -77,11 +76,10 @@ class AliceRules extends ChessRules getSideBoard(mirrorSide) { // Build corresponding board from complete board - const [sizeX,sizeY] = VariantRules.size; - let sideBoard = doubleArray(sizeX, sizeY, ""); - for (let i=0; i { //forEach: castling taken into account - psq.p = VariantRules.ALICE_CODES[psq.p]; //goto board2 + psq.p = V.ALICE_CODES[psq.p]; //goto board2 }); } else //move on board2: mark vanishing pieces as Alice { m.vanish.forEach(psq => { - psq.p = VariantRules.ALICE_CODES[psq.p]; + psq.p = V.ALICE_CODES[psq.p]; }); } // Fix en-passant captures - if (m.vanish[0].p == VariantRules.PAWN - && m.vanish.length == 2 && this.board[m.end.x][m.end.y] == VariantRules.EMPTY) + if (m.vanish[0].p == V.PAWN && m.vanish.length == 2 + && this.board[m.end.x][m.end.y] == V.EMPTY) { m.vanish[1].c = this.getOppCol(this.getColor(x,y)); // In the special case of en-passant, if @@ -144,9 +142,9 @@ class AliceRules extends ChessRules // - board2 takes board1 : vanish[1] --> normal let van = m.vanish[1]; if (mirrorSide==1 && codes.includes(this.getPiece(van.x,van.y))) - van.p = VariantRules.ALICE_CODES[van.p]; + van.p = V.ALICE_CODES[van.p]; else if (mirrorSide==2 && pieces.includes(this.getPiece(van.x,van.y))) - van.p = VariantRules.ALICE_PIECES[van.p]; + van.p = V.ALICE_PIECES[van.p]; } return true; }); @@ -166,16 +164,15 @@ class AliceRules extends ChessRules const color = this.turn; const oppCol = this.getOppCol(color); var potentialMoves = []; - let [sizeX,sizeY] = VariantRules.size; let sideBoard = [this.getSideBoard(1), this.getSideBoard(2)]; - for (var i=0; i { const mirrorSide = (pieces.includes(psq.p) ? 1 : 2); - sideBoard[mirrorSide-1][psq.x][psq.y] = VariantRules.EMPTY; + sideBoard[mirrorSide-1][psq.x][psq.y] = V.EMPTY; }); move.appear.forEach(psq => { const mirrorSide = (pieces.includes(psq.p) ? 1 : 2); - const piece = (mirrorSide == 1 ? psq.p : VariantRules.ALICE_PIECES[psq.p]); + const piece = (mirrorSide == 1 ? psq.p : V.ALICE_PIECES[psq.p]); sideBoard[mirrorSide-1][psq.x][psq.y] = psq.c + piece; - if (piece == VariantRules.KING) + if (piece == V.KING) this.kingPos[psq.c] = [psq.x,psq.y]; }); } @@ -206,16 +203,16 @@ class AliceRules extends ChessRules // Undo on sideboards undoSide(move, sideBoard) { - const pieces = Object.keys(VariantRules.ALICE_CODES); + const pieces = Object.keys(V.ALICE_CODES); move.appear.forEach(psq => { const mirrorSide = (pieces.includes(psq.p) ? 1 : 2); - sideBoard[mirrorSide-1][psq.x][psq.y] = VariantRules.EMPTY; + sideBoard[mirrorSide-1][psq.x][psq.y] = V.EMPTY; }); move.vanish.forEach(psq => { const mirrorSide = (pieces.includes(psq.p) ? 1 : 2); - const piece = (mirrorSide == 1 ? psq.p : VariantRules.ALICE_PIECES[psq.p]); + const piece = (mirrorSide == 1 ? psq.p : V.ALICE_PIECES[psq.p]); sideBoard[mirrorSide-1][psq.x][psq.y] = psq.c + piece; - if (piece == VariantRules.KING) + if (piece == V.KING) this.kingPos[psq.c] = [psq.x,psq.y]; }); } @@ -225,7 +222,7 @@ class AliceRules extends ChessRules const color = this.turn; this.playSide(move, sideBoard); //no need to track flags const kp = this.kingPos[color]; - const mirrorSide = sideBoard[0][kp[0]][kp[1]] != VariantRules.EMPTY ? 1 : 2; + const mirrorSide = (sideBoard[0][kp[0]][kp[1]] != V.EMPTY ? 1 : 2); let saveBoard = this.board; this.board = sideBoard[mirrorSide-1]; let res = this.isAttacked(kp, [this.getOppCol(color)]); @@ -238,7 +235,7 @@ class AliceRules extends ChessRules { this.play(move); const color = this.turn; //opponent - const pieces = Object.keys(VariantRules.ALICE_CODES); + const pieces = Object.keys(V.ALICE_CODES); const kp = this.kingPos[color]; const mirrorSide = (pieces.includes(this.getPiece(kp[0],kp[1])) ? 1 : 2); let sideBoard = this.getSideBoard(mirrorSide); @@ -276,7 +273,7 @@ class AliceRules extends ChessRules checkGameEnd() { - const pieces = Object.keys(VariantRules.ALICE_CODES); + const pieces = Object.keys(V.ALICE_CODES); const color = this.turn; const kp = this.kingPos[color]; const mirrorSide = (pieces.includes(this.getPiece(kp[0],kp[1])) ? 1 : 2); @@ -308,7 +305,7 @@ class AliceRules extends ChessRules getNotation(move) { - if (move.appear.length == 2 && move.appear[0].p == VariantRules.KING) + if (move.appear.length == 2 && move.appear[0].p == V.KING) { if (move.end.y < move.start.y) return "0-0-0"; @@ -316,8 +313,7 @@ class AliceRules extends ChessRules return "0-0"; } - const finalSquare = - String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x); + const finalSquare = String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x); const piece = this.getPiece(move.start.x, move.start.y); const captureMark = (move.vanish.length > move.appear.length ? "x" : ""); diff --git a/public/javascripts/variants/Antiking.js b/public/javascripts/variants/Antiking.js index 014a9c89..e7411684 100644 --- a/public/javascripts/variants/Antiking.js +++ b/public/javascripts/variants/Antiking.js @@ -49,7 +49,7 @@ class AntikingRules extends ChessRules { switch (this.getPiece(x,y)) { - case VariantRules.ANTIKING: + case V.ANTIKING: return this.getPotentialAntikingMoves([x,y]); default: return super.getPotentialMovesFrom([x,y]); @@ -58,7 +58,6 @@ class AntikingRules extends ChessRules getPotentialAntikingMoves(sq) { - const V = VariantRules; return this.getSlideNJumpMoves(sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep"); } @@ -70,7 +69,6 @@ class AntikingRules extends ChessRules isAttackedByKing([x,y], colors) { - const V = VariantRules; if (this.getPiece(x,y) == V.ANTIKING) return false; //antiking is not attacked by king return this.isAttackedBySlideNJump([x,y], colors, V.KING, @@ -79,7 +77,6 @@ class AntikingRules extends ChessRules isAttackedByAntiking([x,y], colors) { - const V = VariantRules; if ([V.KING,V.ANTIKING].includes(this.getPiece(x,y))) return false; //(anti)king is not attacked by antiking return this.isAttackedBySlideNJump([x,y], colors, V.ANTIKING, @@ -114,7 +111,7 @@ class AntikingRules extends ChessRules const piece = this.getPiece(move.start.x,move.start.y); const c = this.getColor(move.start.x,move.start.y); // Update antiking position - if (piece == VariantRules.ANTIKING) + if (piece == V.ANTIKING) { this.antikingPos[c][0] = move.appear[0].x; this.antikingPos[c][1] = move.appear[0].y; @@ -125,7 +122,7 @@ class AntikingRules extends ChessRules { super.unupdateVariables(move); const c = this.getColor(move.start.x,move.start.y); - if (this.getPiece(move.start.x,move.start.y) == VariantRules.ANTIKING) + if (this.getPiece(move.start.x,move.start.y) == V.ANTIKING) this.antikingPos[c] = [move.start.x, move.start.y]; } diff --git a/public/javascripts/variants/Atomic.js b/public/javascripts/variants/Atomic.js index 28ee1f26..e2f8ea33 100644 --- a/public/javascripts/variants/Atomic.js +++ b/public/javascripts/variants/Atomic.js @@ -14,8 +14,8 @@ class AtomicRules extends ChessRules { let x = m.end.x + step[0]; let y = m.end.y + step[1]; - if (x>=0 && x<8 && y>=0 && y<8 && this.board[x][y] != VariantRules.EMPTY - && this.getPiece(x,y) != VariantRules.PAWN) + if (V.OnBoard(x,y) && this.board[x][y] != V.EMPTY + && this.getPiece(x,y) != V.PAWN) { m.vanish.push( new PiPo({p:this.getPiece(x,y),c:this.getColor(x,y),x:x,y:y})); @@ -31,16 +31,14 @@ class AtomicRules extends ChessRules getPotentialKingMoves([x,y]) { - const V = VariantRules; // King cannot capture: let moves = []; - let [sizeX,sizeY] = V.size; const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); for (let step of steps) { - var i = x + step[0]; - var j = y + step[1]; - if (i>=0 && i=0 && j { - if (m.vanish[0].p == VariantRules.PAWN) + if (m.vanish[0].p == V.PAWN) { 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] == VariantRules.EMPTY - && m.vanish.length==2 && this.getColor(m.start.x,m.start.y) == 'c') + if (this.board[m.end.x][m.end.y] == V.EMPTY && m.vanish.length==2 + && this.getColor(m.start.x,m.start.y) == 'c') { return; //checkered pawns cannot take en-passant } @@ -94,7 +94,7 @@ class CheckeredRules extends ChessRules m.appear[0].c = "c"; moves.push(m); if (m.appear[0].p != m.vanish[1].p //avoid promotions (already treated): - && (m.vanish[0].p != VariantRules.PAWN || m.end.x != lastRank)) + && (m.vanish[0].p != V.PAWN || m.end.x != lastRank)) { // Add transformation into captured piece let m2 = JSON.parse(JSON.stringify(m)); @@ -147,7 +147,7 @@ class CheckeredRules extends ChessRules { for (let i of [-1,1]) { - if (y+i>=0 && y+i<8 && this.getPiece(x+pawnShift,y+i)==VariantRules.PAWN + if (y+i>=0 && y+i<8 && this.getPiece(x+pawnShift,y+i)==V.PAWN && this.getColor(x+pawnShift,y+i)==c) { return true; @@ -184,13 +184,10 @@ class CheckeredRules extends ChessRules updateVariables(move) { - const c = this.getColor(move.start.x,move.start.y); - if (c != 'c') //checkered not concerned by castle flags - super.updateVariables(move); - - // Does it turn off a 2-squares pawn flag? + super.updateVariables(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 == VariantRules.PAWN) + if (secondRank.includes(move.start.x) && move.vanish[0].p == V.PAWN) this.pawnFlags[move.start.x==6 ? "w" : "b"][move.start.y] = false; } @@ -207,18 +204,17 @@ class CheckeredRules extends ChessRules evalPosition() { - const [sizeX,sizeY] = VariantRules.size; let evaluation = 0; //Just count material for now, considering checkered neutral (...) - for (let i=0; i { this.updateVariables(m); }); } getColor(i,j) { - const sizeX = VariantRules.size[0]; - if (i >= sizeX) - return (i==sizeX ? "w" : "b"); + if (i >= V.size.x) + return (i==V.size.x ? "w" : "b"); return this.board[i][j].charAt(0); } getPiece(i,j) { - const sizeX = VariantRules.size[0]; - if (i >= sizeX) - return VariantRules.RESERVE_PIECES[j]; + if (i >= V.size.x) + return V.RESERVE_PIECES[j]; return this.board[i][j].charAt(1); } // Used by the interface: getReservePpath(color, index) { - return color + VariantRules.RESERVE_PIECES[index]; + return color + V.RESERVE_PIECES[index]; } // Ordering on reserve pieces static get RESERVE_PIECES() { - const V = VariantRules; return [V.PAWN,V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN]; } getReserveMoves([x,y]) { const color = this.turn; - const p = VariantRules.RESERVE_PIECES[y]; + const p = V.RESERVE_PIECES[y]; if (this.reserve[color][p] == 0) return []; let moves = []; - const [sizeX,sizeY] = VariantRules.size; - const pawnShift = (p==VariantRules.PAWN ? 1 : 0); - for (let i=pawnShift; i= sizeX) + if (x >= V.size.x) { // Reserves, outside of board: x == sizeX(+1) return this.getReserveMoves([x,y]); @@ -108,9 +101,8 @@ class CrazyhouseRules extends ChessRules { let moves = super.getAllValidMoves(); const color = this.turn; - const sizeX = VariantRules.size[0]; - for (let i=0; i 0) return true; } @@ -137,7 +130,6 @@ class CrazyhouseRules extends ChessRules if (move.vanish.length == 2 && move.appear.length == 2) return; //skip castle const color = this.turn; - const V = VariantRules; if (move.vanish.length == 0) { this.reserve[color][move.appear[0].p]--; @@ -149,7 +141,7 @@ class CrazyhouseRules extends ChessRules this.promoted[move.end.x][move.end.y] = move.movePromoted || (move.vanish[0].p == V.PAWN && move.appear[0].p != V.PAWN); if (move.capturePromoted) - this.reserve[color][VariantRules.PAWN]++; + this.reserve[color][V.PAWN]++; else if (move.vanish.length == 2) this.reserve[color][move.vanish[1].p]++; } @@ -160,7 +152,6 @@ class CrazyhouseRules extends ChessRules if (move.vanish.length == 2 && move.appear.length == 2) return; const color = this.turn; - const V = VariantRules; if (move.vanish.length == 0) { this.reserve[color][move.appear[0].p]++; @@ -170,7 +161,7 @@ class CrazyhouseRules extends ChessRules this.promoted[move.start.x][move.start.y] = true; this.promoted[move.end.x][move.end.y] = move.capturePromoted; if (move.capturePromoted) - this.reserve[color][VariantRules.PAWN]--; + this.reserve[color][V.PAWN]--; else if (move.vanish.length == 2) this.reserve[color][move.vanish[1].p]--; } @@ -181,11 +172,11 @@ class CrazyhouseRules extends ChessRules { let evaluation = super.evalPosition(); // Add reserves: - for (let i=0; i 0) return super.getLongNotation(move); const finalSquare = - String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x); + String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x); return "@" + finalSquare; } } diff --git a/public/javascripts/variants/Extinction.js b/public/javascripts/variants/Extinction.js index f0ebeabb..2b0aecaa 100644 --- a/public/javascripts/variants/Extinction.js +++ b/public/javascripts/variants/Extinction.js @@ -3,7 +3,6 @@ class ExtinctionRules extends ChessRules initVariables(fen) { super.initVariables(fen); - const V = VariantRules; this.material = { "w": @@ -32,10 +31,8 @@ class ExtinctionRules extends ChessRules let moves = super.getPotentialPawnMoves([x,y]); // Add potential promotions into king const color = this.turn; - const V = VariantRules; - const [sizeX,sizeY] = V.size; const shift = (color == "w" ? -1 : 1); - const lastRank = (color == "w" ? 0 : sizeX-1); + const lastRank = (color == "w" ? 0 : V.size.x-1); if (x+shift == lastRank) { @@ -43,13 +40,13 @@ class ExtinctionRules extends ChessRules if (this.board[x+shift][y] == V.EMPTY) moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:V.KING})); // Captures - if (y>0 && this.canTake([x,y], [x+shift,y-1]) - && this.board[x+shift][y-1] != V.EMPTY) + if (y>0 && this.board[x+shift][y-1] != V.EMPTY + && this.canTake([x,y], [x+shift,y-1])) { moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:color,p:V.KING})); } - if (y { return this.material[color][p] == 0; })) { // Very negative (resp. positive) if white (reps. black) pieces set is incomplete - return (color=="w"?-1:1) * VariantRules.INFINITY; + return (color=="w"?-1:1) * V.INFINITY; } return super.evalPosition(); } diff --git a/public/javascripts/variants/Grand.js b/public/javascripts/variants/Grand.js index 9e1504d9..f5ae0653 100644 --- a/public/javascripts/variants/Grand.js +++ b/public/javascripts/variants/Grand.js @@ -4,7 +4,6 @@ class GrandRules extends ChessRules { static getPpath(b) { - const V = VariantRules; return ([V.MARSHALL,V.CARDINAL].includes(b[1]) ? "Grand/" : "") + b; } @@ -14,7 +13,7 @@ class GrandRules extends ChessRules this.captures = { "w": {}, "b": {} }; //for promotions } - static get size() { return [10,10]; } + static get size() { return {x:10,y:10}; } static get MARSHALL() { return 'm'; } //rook+knight static get CARDINAL() { return 'c'; } //bishop+knight @@ -23,7 +22,7 @@ class GrandRules extends ChessRules getEpSquare(move) { const [sx,sy,ex] = [move.start.x,move.start.y,move.end.x]; - if (this.getPiece(sx,sy) == VariantRules.PAWN && Math.abs(sx - ex) >= 2) + if (this.getPiece(sx,sy) == V.PAWN && Math.abs(sx - ex) >= 2) { const step = (ex-sx) / Math.abs(ex-sx); let res = [{ @@ -46,9 +45,9 @@ class GrandRules extends ChessRules { switch (this.getPiece(x,y)) { - case VariantRules.MARSHALL: + case V.MARSHALL: return this.getPotentialMarshallMoves([x,y]); - case VariantRules.CARDINAL: + case V.CARDINAL: return this.getPotentialCardinalMoves([x,y]); default: return super.getPotentialMovesFrom([x,y]) @@ -61,8 +60,7 @@ class GrandRules extends ChessRules { const color = this.turn; let moves = []; - const V = VariantRules; - const [sizeX,sizeY] = VariantRules.size; + const [sizeX,sizeY] = [V.size.x,V.size.y]; const shift = (color == "w" ? -1 : 1); const startRanks = (color == "w" ? [sizeX-2,sizeX-3] : [1,2]); const lastRanks = (color == "w" ? [0,1,2] : [sizeX-1,sizeX-2,sizeX-3]); @@ -151,14 +149,12 @@ class GrandRules extends ChessRules getPotentialMarshallMoves(sq) { - const V = VariantRules; return this.getSlideNJumpMoves(sq, V.steps[V.ROOK]).concat( this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")); } getPotentialCardinalMoves(sq) { - const V = VariantRules; return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat( this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")); } @@ -172,7 +168,6 @@ class GrandRules extends ChessRules isAttackedByMarshall(sq, colors) { - const V = VariantRules; return this.isAttackedBySlideNJump(sq, colors, V.MARSHALL, V.steps[V.ROOK]) || this.isAttackedBySlideNJump( sq, colors, V.MARSHALL, V.steps[V.KNIGHT], "oneStep"); @@ -180,7 +175,6 @@ class GrandRules extends ChessRules isAttackedByCardinal(sq, colors) { - const V = VariantRules; return this.isAttackedBySlideNJump(sq, colors, V.CARDINAL, V.steps[V.BISHOP]) || this.isAttackedBySlideNJump( sq, colors, V.CARDINAL, V.steps[V.KNIGHT], "oneStep"); @@ -189,8 +183,7 @@ class GrandRules extends ChessRules updateVariables(move) { super.updateVariables(move); - if (move.vanish.length==2 && move.appear.length==1 - && move.vanish[1].p != VariantRules.PAWN) + if (move.vanish.length==2 && move.appear.length==1 && move.vanish[1].p != V.PAWN) { // Capture: update this.captures if (!this.captures[move.vanish[1].c][move.vanish[1].p]) @@ -203,8 +196,7 @@ class GrandRules extends ChessRules unupdateVariables(move) { super.unupdateVariables(move); - if (move.vanish.length==2 && move.appear.length==1 - && move.vanish[1].p != VariantRules.PAWN) + if (move.vanish.length==2 && move.appear.length==1 && move.vanish[1].p != V.PAWN) { this.captures[move.vanish[1].c][move.vanish[1].p] = Math.max(0, this.captures[move.vanish[1].c][move.vanish[1].p]-1); diff --git a/public/javascripts/variants/Loser.js b/public/javascripts/variants/Loser.js index 6a322b9d..3def40a9 100644 --- a/public/javascripts/variants/Loser.js +++ b/public/javascripts/variants/Loser.js @@ -18,10 +18,8 @@ class LoserRules extends ChessRules // Complete with promotion(s) into king, if possible const color = this.turn; - const V = VariantRules; - const [sizeX,sizeY] = VariantRules.size; const shift = (color == "w" ? -1 : 1); - const lastRank = (color == "w" ? 0 : sizeX-1); + const lastRank = (color == "w" ? 0 : V.size.x-1); if (x+shift == lastRank) { // Normal move @@ -33,7 +31,7 @@ class LoserRules extends ChessRules { moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:color,p:V.KING})); } - if (y 0) @@ -88,7 +84,7 @@ class LoserRules extends ChessRules let moves = this.filterValid( this.getPotentialMovesFrom(sq) ); // This is called from interface: we need to know if a capture is possible if (this.atLeastOneCapture()) - moves = VariantRules.KeepCaptures(moves); + moves = V.KeepCaptures(moves); return moves; } @@ -96,7 +92,7 @@ class LoserRules extends ChessRules { let moves = super.getAllValidMoves(); if (moves.some(m => { return m.vanish.length == 2; })) - moves = VariantRules.KeepCaptures(moves); + moves = V.KeepCaptures(moves); return moves; } diff --git a/public/javascripts/variants/Magnetic.js b/public/javascripts/variants/Magnetic.js index ec2c9752..2e90e6c0 100644 --- a/public/javascripts/variants/Magnetic.js +++ b/public/javascripts/variants/Magnetic.js @@ -23,7 +23,6 @@ class MagneticRules extends ChessRules // TODO: job is done multiple times for (normal) promotions. applyMagneticLaws(move) { - const V = VariantRules; if (move.appear[0].p == V.KING && move.appear.length==1) return [move]; //kings are not charged const aIdx = (move.appear[0].p != V.KING ? 0 : 1); //if castling, rook is charged @@ -32,11 +31,10 @@ class MagneticRules extends ChessRules const lastRank = (color=="w" ? 0 : 7); const standardMove = JSON.parse(JSON.stringify(move)); this.play(standardMove); - const [sizeX,sizeY] = V.size; for (let step of [[-1,0],[1,0],[0,-1],[0,1]]) { let [i,j] = [x+step[0],y+step[1]]; - while (i>=0 && i=0 && j=0 && ii=0 && jj=0 && i=0 && j=0 && i=0 && j=0 && i2=0 && j2=0 && i=0 && j=0 && i=0 - && j { @@ -150,17 +142,16 @@ class UltimaRules extends ChessRules for (let step of steps) { const sq2 = [m.end.x+2*step[0],m.end.y+2*step[1]]; - if (sq2[0]>=0 && sq2[0]=0 && sq2[1]=0 && i=0 && j=sizeX || j<0 || j>=sizeY || this.getColor(i,j)==color + if (!V.OnBoard(i,j) || this.getColor(i,j)==color || (!!byChameleon && this.getPiece(i,j)!=V.KNIGHT)) { continue; @@ -254,7 +243,7 @@ class UltimaRules extends ChessRules 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 (cur[0]>=0 && cur[0]=0 && cur[1] { - const key = m.end.x + sizeX * m.end.y; + const key = m.end.x + V.size.x * m.end.y; if (!mergedMoves[key]) mergedMoves[key] = m; else @@ -327,16 +315,13 @@ class UltimaRules extends ChessRules if (moves.length == 0) return; const [x,y] = [moves[0].start.x,moves[0].start.y]; - const V = VariantRules; const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); let capturingDirections = []; const color = this.turn; const oppCol = this.getOppCol(color); - const [sizeX,sizeY] = V.size; adjacentSteps.forEach(step => { const [i,j] = [x+step[0],y+step[1]]; - if (i>=0 && i=0 && j=0 && i1=0 && i2=0 && j1=0 && j2=0 && i3=0 && j3=0 && i3=0 && j3=0 && i0=0 && j0=0 && i=0 && j=0 && i=0 && j=0 && i=0 && j=0 && i=0 && j=0 && sq2[0]=0 && sq2[1] 0) + if (piece == V.KING && move.appear.length > 0) { this.kingPos[c][0] = move.appear[0].x; this.kingPos[c][1] = move.appear[0].y; @@ -642,20 +610,19 @@ class UltimaRules extends ChessRules getNotation(move) { const initialSquare = - String.fromCharCode(97 + move.start.y) + (VariantRules.size[0]-move.start.x); - const finalSquare = - String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x); + String.fromCharCode(97 + move.start.y) + (V.size.x-move.start.x); + const finalSquare = String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x); let notation = undefined; - if (move.appear[0].p == VariantRules.PAWN) + if (move.appear[0].p == V.PAWN) { // Pawn: generally ambiguous short notation, so we use full description notation = "P" + initialSquare + finalSquare; } - else if (move.appear[0].p == VariantRules.KING) + 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 != VariantRules.KING) + if (move.vanish.length > 1 && move.appear[0].p != V.KING) notation += "X"; //capture mark (not describing what is captured...) return notation; } diff --git a/public/javascripts/variants/Wildebeest.js b/public/javascripts/variants/Wildebeest.js index 5bfa87b0..bb478cc2 100644 --- a/public/javascripts/variants/Wildebeest.js +++ b/public/javascripts/variants/Wildebeest.js @@ -2,11 +2,10 @@ class WildebeestRules extends ChessRules { static getPpath(b) { - const V = VariantRules; return ([V.CAMEL,V.WILDEBEEST].includes(b[1]) ? "Wildebeest/" : "") + b; } - static get size() { return [10,11]; } + static get size() { return {x:10,y:11}; } static get CAMEL() { return 'c'; } static get WILDEBEEST() { return 'w'; } @@ -22,7 +21,7 @@ class WildebeestRules extends ChessRules getEpSquare(move) { const [sx,sy,ex] = [move.start.x,move.start.y,move.end.x]; - if (this.getPiece(sx,sy) == VariantRules.PAWN && Math.abs(sx - ex) >= 2) + if (this.getPiece(sx,sy) == V.PAWN && Math.abs(sx - ex) >= 2) { const step = (ex-sx) / Math.abs(ex-sx); let res = [{ @@ -45,9 +44,9 @@ class WildebeestRules extends ChessRules { switch (this.getPiece(x,y)) { - case VariantRules.CAMEL: + case V.CAMEL: return this.getPotentialCamelMoves([x,y]); - case VariantRules.WILDEBEEST: + case V.WILDEBEEST: return this.getPotentialWildebeestMoves([x,y]); default: return super.getPotentialMovesFrom([x,y]) @@ -59,8 +58,7 @@ class WildebeestRules extends ChessRules { const color = this.turn; let moves = []; - const V = VariantRules; - const [sizeX,sizeY] = VariantRules.size; + const [sizeX,sizeY] = [V.size.x,V.size.y]; const shift = (color == "w" ? -1 : 1); const startRanks = (color == "w" ? [sizeX-2,sizeX-3] : [1,2]); const lastRank = (color == "w" ? 0 : sizeX-1); @@ -147,13 +145,11 @@ class WildebeestRules extends ChessRules getPotentialCamelMoves(sq) { - return this.getSlideNJumpMoves( - sq, VariantRules.steps[VariantRules.CAMEL], "oneStep"); + return this.getSlideNJumpMoves(sq, V.steps[V.CAMEL], "oneStep"); } getPotentialWildebeestMoves(sq) { - const V = VariantRules; return this.getSlideNJumpMoves( sq, V.steps[V.KNIGHT].concat(V.steps[V.CAMEL]), "oneStep"); } @@ -168,12 +164,11 @@ class WildebeestRules extends ChessRules isAttackedByCamel(sq, colors) { return this.isAttackedBySlideNJump(sq, colors, - VariantRules.CAMEL, VariantRules.steps[VariantRules.CAMEL], "oneStep"); + V.CAMEL, V.steps[V.CAMEL], "oneStep"); } isAttackedByWildebeest(sq, colors) { - const V = VariantRules; return this.isAttackedBySlideNJump(sq, colors, V.WILDEBEEST, V.steps[V.KNIGHT].concat(V.steps[V.CAMEL]), "oneStep"); } diff --git a/public/javascripts/variants/Zen.js b/public/javascripts/variants/Zen.js index f57ab3c5..64587d20 100644 --- a/public/javascripts/variants/Zen.js +++ b/public/javascripts/variants/Zen.js @@ -11,15 +11,13 @@ class ZenRules extends ChessRules { const color = this.getColor(x,y); let moves = []; - const [sizeX,sizeY] = VariantRules.size; outerLoop: for (let loop=0; loop=0 && i=0 && j=0 && i=0 && j=0 && i=0 && j= 0 && x+shift < sizeX && x+shift != lastRank) { @@ -140,31 +135,27 @@ class ZenRules extends ChessRules getPotentialRookMoves(sq) { - let noCaptures = this.getSlideNJumpMoves( - sq, VariantRules.steps[VariantRules.ROOK]); + let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.ROOK]); let captures = this.findCaptures(sq); return noCaptures.concat(captures); } getPotentialKnightMoves(sq) { - let noCaptures = this.getSlideNJumpMoves( - sq, VariantRules.steps[VariantRules.KNIGHT], "oneStep"); + let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep"); let captures = this.findCaptures(sq); return noCaptures.concat(captures); } getPotentialBishopMoves(sq) { - let noCaptures = this.getSlideNJumpMoves( - sq, VariantRules.steps[VariantRules.BISHOP]); + let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]); let captures = this.findCaptures(sq); return noCaptures.concat(captures); } getPotentialQueenMoves(sq) { - const V = VariantRules; let noCaptures = this.getSlideNJumpMoves( sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP])); let captures = this.findCaptures(sq); @@ -173,7 +164,6 @@ class ZenRules extends ChessRules getPotentialKingMoves(sq) { - const V = VariantRules; // Initialize with normal moves let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep"); @@ -195,15 +185,15 @@ class ZenRules extends ChessRules // Translate initial square (because pieces may fly unusually in this variant!) const initialSquare = - String.fromCharCode(97 + move.start.y) + (VariantRules.size[0]-move.start.x); + String.fromCharCode(97 + move.start.y) + (V.size.x-move.start.x); // Translate final square const finalSquare = - String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x); + String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x); let notation = ""; const piece = this.getPiece(move.start.x, move.start.y); - if (piece == VariantRules.PAWN) + if (piece == V.PAWN) { // pawn move (TODO: enPassant indication) if (move.vanish.length > 1) diff --git a/views/variant.pug b/views/variant.pug index 7de86ca3..a44a3741 100644 --- a/views/variant.pug +++ b/views/variant.pug @@ -23,6 +23,7 @@ block javascripts script(src="/javascripts/variants/" + variant + ".js") script. const VariantRules = #{variant}Rules; + const V = VariantRules; //because this variable is often used const variant = "#{variant}"; script(src="/javascripts/components/rules.js") script(src="/javascripts/components/game.js")