From: Benjamin Auder <benjamin.auder@somewhere> Date: Fri, 14 Dec 2018 18:30:57 +0000 (+0100) Subject: Code simplification + a few fixes X-Git-Url: https://git.auder.net/%7B%7B%20asset%28%27mixstore/images/img/doc/html/index.html?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; i<rows.length; i++) { let j = 0; @@ -122,7 +121,7 @@ class ChessRules if (!isNaN(num)) j += num; //just shift j else //something at position i,j - board[i][j++] = VariantRules.fen2board(character); + board[i][j++] = V.fen2board(character); } } return board; @@ -141,20 +140,22 @@ class ChessRules /////////////////// // GETTERS, SETTERS - static get size() { return [8,8]; } + static get size() { return {x:8, y:8}; } + // Two next functions return 'undefined' if called on empty square getColor(i,j) { return this.board[i][j].charAt(0); } getPiece(i,j) { return this.board[i][j].charAt(1); } // Color - getOppCol(color) { return color=="w" ? "b" : "w"; } + getOppCol(color) { return (color=="w" ? "b" : "w"); } get lastMove() { const L = this.moves.length; - return L>0 ? 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<V.size.x && y>=0 && y<V.size.y); + } + // Generic method to find possible moves of non-pawn pieces ("sliding or jumping") getSlideNJumpMoves([x,y], steps, oneStep) { const color = this.getColor(x,y); let moves = []; - const [sizeX,sizeY] = VariantRules.size; outerLoop: for (let step of steps) { let i = x + step[0]; let j = y + step[1]; - while (i>=0 && i<sizeX && j>=0 && j<sizeY - && this.board[i][j] == VariantRules.EMPTY) + while (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY) { moves.push(this.getBasicMove([x,y], [i,j])); if (oneStep !== undefined) @@ -288,7 +293,7 @@ class ChessRules i += step[0]; j += step[1]; } - if (i>=0 && i<sizeX && j>=0 && j<sizeY && this.canTake([x,y], [i,j])) + if (V.OnBoard(i,j) && this.canTake([x,y], [i,j])) moves.push(this.getBasicMove([x,y], [i,j])); } return moves; @@ -299,8 +304,7 @@ class ChessRules { const color = this.turn; let moves = []; - const V = VariantRules; - const [sizeX,sizeY] = V.size; + const [sizeX,sizeY] = [V.size.x,V.size.y]; const shift = (color == "w" ? -1 : 1); const firstRank = (color == 'w' ? sizeX-1 : 0); const startRank = (color == "w" ? sizeX-2 : 1); @@ -320,13 +324,13 @@ class ChessRules } } // 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])); } - if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) - && this.board[x+shift][y+1] != V.EMPTY) + if (y<sizeY-1 && 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])); } @@ -342,13 +346,13 @@ class ChessRules if (this.board[x+shift][y] == V.EMPTY) moves.push(this.getBasicMove([x,y], [x+shift,y], {c:pawnColor,p:p})); // 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:pawnColor,p:p})); } - if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) - && this.board[x+shift][y+1] != V.EMPTY) + if (y<sizeY-1 && 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})); } @@ -357,11 +361,11 @@ class ChessRules // En passant const Lep = this.epSquares.length; - const epSquare = Lep>0 ? 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<sizeX; i++) + for (let i=0; i<V.size.x; i++) { - for (let j=0; j<sizeY; j++) + for (let j=0; j<V.size.y; j++) { // Next condition "!= oppCol" = harmless hack to work with checkered variant - if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) != oppCol) + if (this.board[i][j] != V.EMPTY && this.getColor(i,j) != oppCol) Array.prototype.push.apply(potentialMoves, this.getPotentialMovesFrom([i,j])); } } @@ -530,12 +527,11 @@ class ChessRules { const color = this.turn; const oppCol = this.getOppCol(color); - const [sizeX,sizeY] = VariantRules.size; - for (let i=0; i<sizeX; i++) + for (let i=0; i<V.size.x; i++) { - for (let j=0; j<sizeY; j++) + for (let j=0; j<V.size.y; j++) { - if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) != oppCol) + if (this.board[i][j] != V.EMPTY && this.getColor(i,j) != oppCol) { const moves = this.getPotentialMovesFrom([i,j]); if (moves.length > 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<sizeX) + if (x+pawnShift>=0 && x+pawnShift<V.size.x) { for (let i of [-1,1]) { - if (y+i>=0 && y+i<sizeY && this.getPiece(x+pawnShift,y+i)==VariantRules.PAWN + if (y+i>=0 && y+i<V.size.y && this.getPiece(x+pawnShift,y+i)==V.PAWN && this.getColor(x+pawnShift,y+i)==c) { return true; @@ -588,28 +583,25 @@ class ChessRules // Is square x,y attacked by 'colors' rooks ? isAttackedByRook(sq, colors) { - return this.isAttackedBySlideNJump(sq, colors, - VariantRules.ROOK, VariantRules.steps[VariantRules.ROOK]); + return this.isAttackedBySlideNJump(sq, colors, V.ROOK, V.steps[V.ROOK]); } // Is square x,y attacked by 'colors' knights ? isAttackedByKnight(sq, colors) { return this.isAttackedBySlideNJump(sq, colors, - VariantRules.KNIGHT, VariantRules.steps[VariantRules.KNIGHT], "oneStep"); + V.KNIGHT, V.steps[V.KNIGHT], "oneStep"); } // Is square x,y attacked by 'colors' bishops ? isAttackedByBishop(sq, colors) { - return this.isAttackedBySlideNJump(sq, colors, - VariantRules.BISHOP, VariantRules.steps[VariantRules.BISHOP]); + return this.isAttackedBySlideNJump(sq, colors, V.BISHOP, V.steps[V.BISHOP]); } // Is square x,y attacked by 'colors' queens ? isAttackedByQueen(sq, colors) { - const V = VariantRules; return this.isAttackedBySlideNJump(sq, colors, V.QUEEN, V.steps[V.ROOK].concat(V.steps[V.BISHOP])); } @@ -617,7 +609,6 @@ class ChessRules // Is square x,y attacked by 'colors' king(s) ? isAttackedByKing(sq, colors) { - const V = VariantRules; return this.isAttackedBySlideNJump(sq, colors, V.KING, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep"); } @@ -626,19 +617,16 @@ class ChessRules // is x,y attacked by a piece of color in array 'colors' ? isAttackedBySlideNJump([x,y], colors, piece, steps, oneStep) { - const [sizeX,sizeY] = VariantRules.size; for (let step of steps) { let rx = x+step[0], ry = y+step[1]; - while (rx>=0 && rx<sizeX && ry>=0 && ry<sizeY - && this.board[rx][ry] == VariantRules.EMPTY && !oneStep) + while (V.OnBoard(rx,ry) && this.board[rx][ry] == V.EMPTY && !oneStep) { rx += step[0]; ry += step[1]; } - if (rx>=0 && rx<sizeX && ry>=0 && ry<sizeY - && this.board[rx][ry] != VariantRules.EMPTY - && this.getPiece(rx,ry) == piece && colors.includes(this.getColor(rx,ry))) + if (V.OnBoard(rx,ry) && this.getPiece(rx,ry) === piece + && colors.includes(this.getColor(rx,ry))) { return true; } @@ -672,7 +660,7 @@ class ChessRules static PlayOnBoard(board, move) { for (let psq of move.vanish) - board[psq.x][psq.y] = VariantRules.EMPTY; + board[psq.x][psq.y] = V.EMPTY; for (let psq of move.appear) board[psq.x][psq.y] = psq.c + psq.p; } @@ -680,7 +668,7 @@ class ChessRules static UndoOnBoard(board, move) { for (let psq of move.appear) - board[psq.x][psq.y] = VariantRules.EMPTY; + board[psq.x][psq.y] = V.EMPTY; for (let psq of move.vanish) board[psq.x][psq.y] = psq.c + psq.p; } @@ -689,12 +677,11 @@ class ChessRules updateVariables(move) { const piece = this.getPiece(move.start.x,move.start.y); - const c = this.getColor(move.start.x,move.start.y); - const [sizeX,sizeY] = VariantRules.size; - const firstRank = (c == "w" ? sizeX-1 : 0); + const c = this.turn; + const firstRank = (c == "w" ? V.size.x-1 : 0); // Update king position + flags - if (piece == VariantRules.KING && move.appear.length > 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<moves1.length; i++) { @@ -923,7 +916,7 @@ class ChessRules this.play(moves1[i]); // 0.1 * oldEval : heuristic to avoid some bad moves (not all...) moves1[i].eval = 0.1*moves1[i].eval + - this.alphabeta(VariantRules.SEARCH_DEPTH-1, -maxeval, maxeval); + this.alphabeta(V.SEARCH_DEPTH-1, -maxeval, maxeval); this.undo(moves1[i]); } moves1.sort( (a,b) => { 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<sizeX; i++) + for (let i=0; i<V.size.x; i++) { - for (let j=0; j<sizeY; j++) + for (let j=0; j<V.size.y; j++) { - if (this.board[i][j] != VariantRules.EMPTY) + if (this.board[i][j] != V.EMPTY) { const sign = this.getColor(i,j) == "w" ? 1 : -1; - evaluation += sign * VariantRules.VALUES[this.getPiece(i,j)]; + evaluation += sign * V.VALUES[this.getPiece(i,j)]; } } } @@ -1069,13 +1061,12 @@ class ChessRules getBaseFen() { let fen = ""; - let [sizeX,sizeY] = VariantRules.size; - for (let i=0; i<sizeX; i++) + for (let i=0; i<V.size.x; i++) { let emptyCount = 0; - for (let j=0; j<sizeY; j++) + for (let j=0; j<V.size.y; j++) { - if (this.board[i][j] == VariantRules.EMPTY) + if (this.board[i][j] == V.EMPTY) emptyCount++; else { @@ -1085,7 +1076,7 @@ class ChessRules fen += emptyCount; emptyCount = 0; } - fen += VariantRules.board2fen(this.board[i][j]); + fen += V.board2fen(this.board[i][j]); } } if (emptyCount > 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<sizeX; i++) + let sideBoard = doubleArray(V.size.x, V.size.y, ""); + for (let i=0; i<V.size.x; i++) { - for (let j=0; j<sizeY; j++) + for (let j=0; j<V.size.y; j++) sideBoard[i][j] = this.getSquareOccupation(i, j, mirrorSide); } return sideBoard; @@ -90,8 +88,8 @@ class AliceRules extends ChessRules // NOTE: castle & enPassant https://www.chessvariants.com/other.dir/alice.html getPotentialMovesFrom([x,y], sideBoard) { - const pieces = Object.keys(VariantRules.ALICE_CODES); - const codes = Object.keys(VariantRules.ALICE_PIECES); + const pieces = Object.keys(V.ALICE_CODES); + const codes = Object.keys(V.ALICE_PIECES); const mirrorSide = (pieces.includes(this.getPiece(x,y)) ? 1 : 2); // Search valid moves on sideBoard @@ -107,11 +105,11 @@ class AliceRules extends ChessRules // appear[i] must be an empty square on the other board for (let psq of m.appear) { - if (this.getSquareOccupation(psq.x,psq.y,3-mirrorSide) != VariantRules.EMPTY) + if (this.getSquareOccupation(psq.x,psq.y,3-mirrorSide) != V.EMPTY) return false; } } - else if (this.board[m.end.x][m.end.y] != VariantRules.EMPTY) + else if (this.board[m.end.x][m.end.y] != V.EMPTY) { // Attempt to capture const piece = this.getPiece(m.end.x,m.end.y); @@ -125,18 +123,18 @@ class AliceRules extends ChessRules if (mirrorSide==1) { m.appear.forEach(psq => { //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<sizeX; i++) + for (var i=0; i<V.size.x; i++) { - for (var j=0; j<sizeY; j++) + for (var j=0; j<V.size.y; j++) { - if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) == color) + if (this.board[i][j] != V.EMPTY && this.getColor(i,j) == color) { const mirrorSide = - Object.keys(VariantRules.ALICE_CODES).includes(this.getPiece(i,j)) + Object.keys(V.ALICE_CODES).includes(this.getPiece(i,j)) ? 1 : 2; Array.prototype.push.apply(potentialMoves, @@ -189,16 +186,16 @@ class AliceRules extends ChessRules // Play on sideboards [TODO: only one sideBoard required] playSide(move, sideBoard) { - const pieces = Object.keys(VariantRules.ALICE_CODES); + const pieces = Object.keys(V.ALICE_CODES); move.vanish.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.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<sizeX && j>=0 && j<sizeY && this.board[i][j] == VariantRules.EMPTY) + const i = x + step[0]; + const j = y + step[1]; + if (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY) moves.push(this.getBasicMove([x,y], [i,j])); } return moves.concat(this.getCastleMoves([x,y])); @@ -48,11 +46,8 @@ class AtomicRules extends ChessRules isAttacked(sq, colors) { - if (this.getPiece(sq[0],sq[1]) == VariantRules.KING - && this.isAttackedByKing(sq, colors)) - { + if (this.getPiece(sq[0],sq[1]) == V.KING && this.isAttackedByKing(sq, colors)) return false; //king cannot take... - } return (this.isAttackedByPawn(sq, colors) || this.isAttackedByRook(sq, colors) || this.isAttackedByKnight(sq, colors) diff --git a/public/javascripts/variants/Checkered.js b/public/javascripts/variants/Checkered.js index 814d91b8..2d62d4b8 100644 --- a/public/javascripts/variants/Checkered.js +++ b/public/javascripts/variants/Checkered.js @@ -72,16 +72,16 @@ class CheckeredRules extends ChessRules { let standardMoves = super.getPotentialMovesFrom([x,y]); const lastRank = this.turn == "w" ? 0 : 7; - if (this.getPiece(x,y) == VariantRules.KING) + if (this.getPiece(x,y) == V.KING) return standardMoves; //king has to be treated differently (for castles) let moves = []; standardMoves.forEach(m => { - 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<sizeX; i++) + for (let i=0; i<V.size.x; i++) { - for (let j=0; j<sizeY; j++) + for (let j=0; j<V.size.y; j++) { - if (this.board[i][j] != VariantRules.EMPTY) + if (this.board[i][j] != V.EMPTY) { const sqColor = this.getColor(i,j); const sign = sqColor == "w" ? 1 : (sqColor=="b" ? -1 : 0); - evaluation += sign * VariantRules.VALUES[this.getPiece(i,j)]; + evaluation += sign * V.VALUES[this.getPiece(i,j)]; } } } @@ -255,10 +251,10 @@ class CheckeredRules extends ChessRules // Translate final square let 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 piece = this.getPiece(move.start.x, move.start.y); - if (piece == VariantRules.PAWN) + if (piece == V.PAWN) { // Pawn move let notation = ""; diff --git a/public/javascripts/variants/Crazyhouse.js b/public/javascripts/variants/Crazyhouse.js index b297f1fb..bf47197d 100644 --- a/public/javascripts/variants/Crazyhouse.js +++ b/public/javascripts/variants/Crazyhouse.js @@ -4,7 +4,6 @@ class CrazyhouseRules extends ChessRules { super.initVariables(fen); // Also init reserves (used by the interface to show landing pieces) - const V = VariantRules; this.reserve = { "w": @@ -24,53 +23,48 @@ class CrazyhouseRules extends ChessRules [V.QUEEN]: 0, } }; - const [sizeX,sizeY] = VariantRules.size; - this.promoted = doubleArray(sizeX, sizeY, false); + this.promoted = doubleArray(V.size.x, V.size.y, false); // May be a continuation: adjust numbers of pieces in reserve + promoted pieces this.moves.forEach(m => { 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-pawnShift; i++) + const pawnShift = (p==V.PAWN ? 1 : 0); + for (let i=pawnShift; i<V.size.x-pawnShift; i++) { - for (let j=0; j<sizeY; j++) + for (let j=0; j<V.size.y; j++) { - if (this.board[i][j] == VariantRules.EMPTY) + if (this.board[i][j] == V.EMPTY) { let mv = new Move({ appear: [ @@ -94,8 +88,7 @@ class CrazyhouseRules extends ChessRules getPotentialMovesFrom([x,y]) { - const sizeX = VariantRules.size[0]; - if (x >= 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<VariantRules.RESERVE_PIECES.length; i++) - moves = moves.concat(this.getReserveMoves([sizeX+(color=="w"?0:1),i])); + for (let i=0; i<V.RESERVE_PIECES.length; i++) + moves = moves.concat(this.getReserveMoves([V.size.x+(color=="w"?0:1),i])); return this.filterValid(moves); } @@ -118,11 +110,12 @@ class CrazyhouseRules extends ChessRules { if (!super.atLeastOneMove()) { - const sizeX = VariantRules.size[0]; - // Scan for reserve moves - for (let i=0; i<VariantRules.RESERVE_PIECES.length; i++) + const color = this.turn; + // Search one reserve move + for (let i=0; i<V.RESERVE_PIECES.length; i++) { - let moves = this.filterValid(this.getReserveMoves([sizeX,i])); + let moves = this.filterValid( + this.getReserveMoves([V.size.x+(this.turn=="w"?0:1), i]) ); if (moves.length > 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<VariantRules.RESERVE_PIECES.length; i++) + for (let i=0; i<V.RESERVE_PIECES.length; i++) { - const p = VariantRules.RESERVE_PIECES[i]; - evaluation += this.reserve["w"][p] * VariantRules.VALUES[p]; - evaluation -= this.reserve["b"][p] * VariantRules.VALUES[p]; + const p = V.RESERVE_PIECES[i]; + evaluation += this.reserve["w"][p] * V.VALUES[p]; + evaluation -= this.reserve["b"][p] * V.VALUES[p]; } return evaluation; } @@ -196,9 +187,9 @@ class CrazyhouseRules extends ChessRules return super.getNotation(move); // Rebirth: const piece = - (move.appear[0].p != VariantRules.PAWN ? move.appear[0].p.toUpperCase() : ""); + (move.appear[0].p != V.PAWN ? move.appear[0].p.toUpperCase() : ""); 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 piece + "@" + finalSquare; } @@ -207,7 +198,7 @@ class CrazyhouseRules extends ChessRules if (move.vanish.length > 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<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) - && this.board[x+shift][y+1] != V.EMPTY) + if (y<V.size.y-1 && 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})); } @@ -81,7 +78,7 @@ class ExtinctionRules extends ChessRules if (move.appear[0].p != move.vanish[0].p) { this.material[move.appear[0].c][move.appear[0].p]++; - this.material[move.appear[0].c][VariantRules.PAWN]--; + this.material[move.appear[0].c][V.PAWN]--; } if (move.vanish.length==2 && move.appear.length==1) //capture this.material[move.vanish[1].c][move.vanish[1].p]--; @@ -93,7 +90,7 @@ class ExtinctionRules extends ChessRules if (move.appear[0].p != move.vanish[0].p) { this.material[move.appear[0].c][move.appear[0].p]--; - this.material[move.appear[0].c][VariantRules.PAWN]++; + this.material[move.appear[0].c][V.PAWN]++; } if (move.vanish.length==2 && move.appear.length==1) this.material[move.vanish[1].c][move.vanish[1].p]++; @@ -130,7 +127,7 @@ class ExtinctionRules extends ChessRules p => { 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<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) + if (y<V.size.y-1 && this.canTake([x,y], [x+shift,y+1]) && this.board[x+shift][y+1] != V.EMPTY) { moves.push(this.getBasicMove([x,y], [x+shift,y+1], {c:color,p:V.KING})); @@ -45,7 +43,6 @@ class LoserRules extends ChessRules getPotentialKingMoves(sq) { - const V = VariantRules; return this.getSlideNJumpMoves(sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep"); } @@ -55,12 +52,11 @@ class LoserRules extends ChessRules { const color = this.turn; const oppCol = this.getOppCol(color); - const [sizeX,sizeY] = VariantRules.size; - for (let i=0; i<sizeX; i++) + for (let i=0; i<V.size.x; i++) { - for (let j=0; j<sizeY; j++) + for (let j=0; j<V.size.y; j++) { - if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) != oppCol) + if (this.board[i][j] != V.EMPTY && this.getColor(i,j) != oppCol) { const moves = this.getPotentialMovesFrom([i,j]); if (moves.length > 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<sizeX && j>=0 && j<sizeY) + while (V.OnBoard(i,j)) { if (this.board[i][j] != V.EMPTY) { @@ -71,7 +69,7 @@ class MagneticRules extends ChessRules { // Push it until we meet an obstacle or edge of the board let [ii,jj] = [i+step[0],j+step[1]]; - while (ii>=0 && ii<sizeX && jj>=0 && jj<sizeY) + while (V.OnBoard(ii,jj)) { if (this.board[ii][jj] != V.EMPTY) break; @@ -166,9 +164,9 @@ class MagneticRules extends ChessRules { super.updateVariables(move); const c = this.getColor(move.start.x,move.start.y); - if (this.board[move.end.x][move.end.y] != VariantRules.EMPTY + if (this.board[move.end.x][move.end.y] != V.EMPTY && c != this.getColor(move.end.x,move.end.y) - && this.getPiece(move.end.x,move.end.y) == VariantRules.KING) + && this.getPiece(move.end.x,move.end.y) == V.KING) { // We took opponent king ! const oppCol = this.getOppCol(c); diff --git a/public/javascripts/variants/Switching.js b/public/javascripts/variants/Switching.js index cedba3db..ee84e4ca 100644 --- a/public/javascripts/variants/Switching.js +++ b/public/javascripts/variants/Switching.js @@ -6,7 +6,6 @@ class SwitchingRules extends ChessRules const c = this.getColor(x1,y1); //same as color at square 2 const p1 = this.getPiece(x1,y1); const p2 = this.getPiece(x2,y2); - const V = VariantRules; if (p1 == V.KING && p2 == V.ROOK) return []; //avoid duplicate moves (potential conflict with castle) let move = new Move({ @@ -22,8 +21,7 @@ class SwitchingRules extends ChessRules end: {x:x2,y:y2} }); // Move completion: promote switched pawns (as in Magnetic) - const sizeX = VariantRules.size[0]; - const lastRank = (c == "w" ? 0 : sizeX-1); + const lastRank = (c == "w" ? 0 : V.size.x-1); let moves = []; if ((p1==V.PAWN && x2==lastRank) || (p2==V.PAWN && x1==lastRank)) { @@ -55,10 +53,8 @@ class SwitchingRules extends ChessRules { let moves = super.getPotentialMovesFrom([x,y]); // Add switches: respecting chessboard ordering if "computer" is on - const V = VariantRules; const color = this.turn; const piece = this.getPiece(x,y); - const [sizeX,sizeY] = V.size; const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); const kp = this.kingPos[color]; const oppCol = this.getOppCol(color); @@ -67,7 +63,7 @@ class SwitchingRules extends ChessRules let [i,j] = [x+step[0],y+step[1]]; if (!!computer && (i<x || (i==x && j<y))) continue; //only switch with superior indices - if (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j]!=V.EMPTY + if (V.OnBoard(i,j) && this.board[i][j]!=V.EMPTY && this.getColor(i,j)==color && this.getPiece(i,j)!=piece // No switching under check (theoretically non-king pieces could, but not) && !this.isAttacked(kp, [oppCol])) @@ -87,12 +83,11 @@ class SwitchingRules extends ChessRules const color = this.turn; const oppCol = this.getOppCol(color); let potentialMoves = []; - const [sizeX,sizeY] = VariantRules.size; - for (let i=0; i<sizeX; i++) + for (let i=0; i<V.size.x; i++) { - for (let j=0; j<sizeY; j++) + for (let j=0; j<V.size.y; j++) { - if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) == color) + if (this.board[i][j] != V.EMPTY && this.getColor(i,j) == color) { Array.prototype.push.apply(potentialMoves, this.getPotentialMovesFrom([i,j], computer)); @@ -106,7 +101,7 @@ class SwitchingRules extends ChessRules { super.updateVariables(move); if (move.appear.length == 2 && move.vanish.length == 2 - && move.appear[1].p == VariantRules.KING) + && move.appear[1].p == V.KING) { // Switch with the king; not castle, and not handled by main class const color = this.getColor(move.start.x, move.start.y); @@ -118,7 +113,7 @@ class SwitchingRules extends ChessRules { super.unupdateVariables(move); if (move.appear.length == 2 && move.vanish.length == 2 - && move.appear[1].p == VariantRules.KING) + && move.appear[1].p == V.KING) { const color = this.getColor(move.start.x, move.start.y); this.kingPos[color] = [move.appear[0].x, move.appear[0].y]; @@ -132,13 +127,13 @@ class SwitchingRules extends ChessRules if (move.appear.length == 1) return super.getNotation(move); //no switch // Switch or castle - if (move.appear[0].p == VariantRules.KING && move.appear[1].p == VariantRules.ROOK) + if (move.appear[0].p == V.KING && move.appear[1].p == V.ROOK) return (move.end.y < move.start.y ? "0-0-0" : "0-0"); // Switch: const startSquare = - String.fromCharCode(97 + move.start.y) + (VariantRules.size[0]-move.start.x); + String.fromCharCode(97 + move.start.y) + (V.size.x-move.start.x); 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 "S" + startSquare + finalSquare; } } diff --git a/public/javascripts/variants/Ultima.js b/public/javascripts/variants/Ultima.js index ab12c716..04ef29b0 100644 --- a/public/javascripts/variants/Ultima.js +++ b/public/javascripts/variants/Ultima.js @@ -56,14 +56,12 @@ class UltimaRules extends ChessRules const piece = this.getPiece(x,y); const color = this.getColor(x,y); const oppCol = this.getOppCol(color); - const V = VariantRules; const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); - const [sizeX,sizeY] = V.size; outerLoop: for (let step of adjacentSteps) { const [i,j] = [x+step[0],y+step[1]]; - if (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j] != V.EMPTY + if (V.OnBoard(i,j) && this.board[i][j] != V.EMPTY && this.getColor(i,j) == oppCol) { const oppPiece = this.getPiece(i,j); @@ -75,8 +73,8 @@ class UltimaRules extends ChessRules const [i2,j2] = [i+step2[0],j+step2[1]]; if (i2 == x && j2 == y) continue; //skip initial piece! - if (i2>=0 && i2<sizeX && j2>=0 && j2<sizeY - && this.board[i2][j2] != V.EMPTY && this.getColor(i2,j2) == color) + if (V.OnBoard(i2,j2) && this.board[i2][j2] != V.EMPTY + && this.getColor(i2,j2) == color) { if ([V.BISHOP,V.IMMOBILIZER].includes(this.getPiece(i2,j2))) return false; @@ -99,7 +97,7 @@ class UltimaRules extends ChessRules return []; switch (this.getPiece(x,y)) { - case VariantRules.IMMOBILIZER: + case V.IMMOBILIZER: return this.getPotentialImmobilizerMoves([x,y]); default: return super.getPotentialMovesFrom([x,y]); @@ -111,14 +109,12 @@ class UltimaRules extends ChessRules const color = this.getColor(x,y); const piece = this.getPiece(x,y); let moves = []; - const [sizeX,sizeY] = VariantRules.size; outerLoop: for (let step of steps) { let i = x + step[0]; let j = y + step[1]; - while (i>=0 && i<sizeX && j>=0 && j<sizeY - && this.board[i][j] == VariantRules.EMPTY) + while (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY) { moves.push(this.getBasicMove([x,y], [i,j])); if (oneStep !== undefined) @@ -127,11 +123,8 @@ class UltimaRules extends ChessRules j += step[1]; } // Only king can take on occupied square: - if (piece==VariantRules.KING && i>=0 && i<sizeX && j>=0 - && j<sizeY && this.canTake([x,y], [i,j])) - { + if (piece==V.KING && V.OnBoard(i,j) && this.canTake([x,y], [i,j])) moves.push(this.getBasicMove([x,y], [i,j])); - } } return moves; } @@ -139,8 +132,7 @@ class UltimaRules extends ChessRules // Modify capturing moves among listed pawn moves addPawnCaptures(moves, byChameleon) { - const steps = VariantRules.steps[VariantRules.ROOK]; - const [sizeX,sizeY] = VariantRules.size; + const steps = V.steps[V.ROOK]; const color = this.turn; const oppCol = this.getOppCol(color); moves.forEach(m => { @@ -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]<sizeX && sq2[1]>=0 && sq2[1]<sizeY - && this.board[sq2[0]][sq2[1]] != VariantRules.EMPTY + 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]] != VariantRules.EMPTY + 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 == VariantRules.PAWN) + if (!byChameleon || piece1 == V.PAWN) { m.vanish.push(new PiPo({ x:sq1[0], @@ -196,10 +187,10 @@ class UltimaRules extends ChessRules const corner2 = [kp[0], m.end.y]; for (let [i,j] of [corner1,corner2]) { - if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) == oppCol) + if (this.board[i][j] != V.EMPTY && this.getColor(i,j) == oppCol) { const piece = this.getPiece(i,j); - if (!byChameleon || piece == VariantRules.ROOK) + if (!byChameleon || piece == V.ROOK) { m.vanish.push( new PiPo({ x:i, @@ -225,9 +216,7 @@ class UltimaRules extends ChessRules getKnightCaptures(startSquare, byChameleon) { // Look in every direction for captures - const V = VariantRules; const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); - const [sizeX,sizeY] = V.size; const color = this.turn; const oppCol = this.getOppCol(color); let moves = []; @@ -237,12 +226,12 @@ class UltimaRules extends ChessRules for (let step of steps) { let [i,j] = [x+step[0], y+step[1]]; - while (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j]==V.EMPTY) + while (V.OnBoard(i,j) && this.board[i][j]==V.EMPTY) { i += step[0]; j += step[1]; } - if (i<0 || i>=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]<sizeX && cur[1]>=0 && cur[1]<sizeY) + while (V.OnBoard(cur[0],cur[1])) { if (this.board[last[0]][last[1]] != V.EMPTY) { @@ -304,9 +293,8 @@ class UltimaRules extends ChessRules this.addQueenCaptures(moves, "asChameleon"); // Post-processing: merge similar moves, concatenating vanish arrays let mergedMoves = {}; - const [sizeX,sizeY] = VariantRules.size; moves.forEach(m => { - 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<sizeX && j>=0 && j<sizeY - && this.board[i][j] != V.EMPTY && this.getColor(i,j) == oppCol + 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); @@ -378,7 +363,6 @@ class UltimaRules extends ChessRules getPotentialKingMoves(sq) { - const V = VariantRules; return this.getSlideNJumpMoves(sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep"); } @@ -390,38 +374,31 @@ class UltimaRules extends ChessRules // 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 steps = VariantRules.steps[VariantRules.ROOK]; - const [sizeX,sizeY] = VariantRules.size; + 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 (i1>=0 && i1<sizeX && i2>=0 && i2<sizeX - && j1>=0 && j1<sizeY && j2>=0 && j2<sizeY) + if (V.OnBoard(i1,j1) && V.OnBoard(i2,j2)) { - if ((this.board[i1][j1]!=VariantRules.EMPTY - && colors.includes(this.getColor(i1,j1)) - && this.board[i2][j2]==VariantRules.EMPTY) + if ((this.board[i1][j1]!=V.EMPTY && colors.includes(this.getColor(i1,j1)) + && this.board[i2][j2]==V.EMPTY) || - (this.board[i2][j2]!=VariantRules.EMPTY - && colors.includes(this.getColor(i2,j2)) - && this.board[i1][j1]==VariantRules.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]==VariantRules.EMPTY ? [i1,j1] : [i2,j2]); + let [ii,jj] = (this.board[i1][j1]==V.EMPTY ? [i1,j1] : [i2,j2]); let [i3,j3] = [ii+step[0],jj+step[1]]; - while (i3>=0 && i3<sizeX && j3>=0 && j3<sizeY - && this.board[i3][j3]==VariantRules.EMPTY) + while (V.OnBoard(i3,j3) && this.board[i3][j3]==V.EMPTY) { i3 += step[0]; j3 += step[1]; } - if (i3>=0 && i3<sizeX && j3>=0 && j3<sizeY - && colors.includes(this.getColor(i3,j3)) - && this.getPiece(i3,j3) == VariantRules.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; } @@ -436,20 +413,18 @@ class UltimaRules extends ChessRules { // King must be on same column or row, // and a rook should be able to reach a capturing square - const [sizeX,sizeY] = VariantRules.size; // 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) { // Look for the enemy rook (maximum 1) - for (let i=0; i<sizeX; i++) + for (let i=0; i<V.size.x; i++) { - for (let j=0; j<sizeY; j++) + for (let j=0; j<V.size.y; j++) { - if (this.board[i][j] != VariantRules.EMPTY - && colors.includes(this.getColor(i,j)) - && this.getPiece(i,j) == VariantRules.ROOK) + if (this.board[i][j] != V.EMPTY && colors.includes(this.getColor(i,j)) + && this.getPiece(i,j) == V.ROOK) { if (this.isImmobilized([i,j])) return false; //because only one rook @@ -472,25 +447,23 @@ class UltimaRules extends ChessRules { // Square (x,y) must be on same line as a knight, // and there must be empty square(s) behind. - const V = VariantRules; const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); - const [sizeX,sizeY] = V.size; outerLoop: for (let step of steps) { const [i0,j0] = [x+step[0],y+step[1]]; - if (i0>=0 && i0<sizeX && j0>=0 && j0<sizeY && this.board[i0][j0] == V.EMPTY) + if (V.OnBoard(i0,j0) && this.board[i0][j0] == V.EMPTY) { // Try in opposite direction: let [i,j] = [x-step[0],y-step[1]]; - while (i>=0 && i<sizeX && j>=0 && j<sizeY) + while (V.OnBoard(i,j)) { - while (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j] == V.EMPTY) + while (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY) { i -= step[0]; j -= step[1]; } - if (i>=0 && i<sizeX && j>=0 && j<sizeY) + if (V.OnBoard(i,j)) { if (colors.includes(this.getColor(i,j))) { @@ -514,13 +487,11 @@ class UltimaRules extends ChessRules { // We cheat a little here: since this function is used exclusively for king, // it's enough to check the immediate surrounding of the square. - const V = VariantRules; const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); - const [sizeX,sizeY] = V.size; for (let step of adjacentSteps) { const [i,j] = [x+step[0],y+step[1]]; - if (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j]!=V.EMPTY + if (V.OnBoard(i,j) && this.board[i][j]!=V.EMPTY && colors.includes(this.getColor(i,j)) && this.getPiece(i,j) == V.BISHOP) { return true; //bishops are never immobilized @@ -533,14 +504,11 @@ class UltimaRules extends ChessRules { // Square (x,y) must be adjacent to a queen, and the queen must have // some free space in the opposite direction from (x,y) - const V = VariantRules; const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]); - const [sizeX,sizeY] = V.size; for (let step of adjacentSteps) { const sq2 = [x+2*step[0],y+2*step[1]]; - if (sq2[0]>=0 && sq2[0]<sizeX && sq2[1]>=0 && sq2[1]<sizeY - && this.board[sq2[0]][sq2[1]] == V.EMPTY) + if (V.OnBoard(sq2[0],sq2[1]) && this.board[sq2[0]][sq2[1]] == V.EMPTY) { const sq1 = [x+step[0],y+step[1]]; if (this.board[sq1[0]][sq1[1]] != V.EMPTY @@ -560,7 +528,7 @@ class UltimaRules extends ChessRules // Just update king(s) position(s) const piece = this.getPiece(move.start.x,move.start.y); const c = this.getColor(move.start.x,move.start.y); - if (piece == VariantRules.KING && move.appear.length > 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<steps.length; loop++) { const step = steps[loop]; let i = x + step[0]; let j = y + step[1]; - while (i>=0 && i<sizeX && j>=0 && j<sizeY - && this.board[i][j] == VariantRules.EMPTY) + while (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY) { moves.push(this.getBasicMove([x,y], [i,j])); if (!!oneStep) @@ -38,13 +36,11 @@ class ZenRules extends ChessRules { const color = this.getColor(x,y); var moves = []; - const V = VariantRules; const steps = asA != V.PAWN ? (asA==V.QUEEN ? V.steps[V.ROOK].concat(V.steps[V.BISHOP]) : V.steps[asA]) : color=='w' ? [[-1,-1],[-1,1]] : [[1,-1],[1,1]]; const oneStep = (asA==V.KNIGHT || asA==V.PAWN); //we don't capture king - const [sizeX,sizeY] = V.size; - const lastRank = (color == 'w' ? 0 : sizeY-1); + const lastRank = (color == 'w' ? 0 : V.size.x-1); const promotionPieces = [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN]; outerLoop: for (let loop=0; loop<steps.length; loop++) @@ -52,15 +48,15 @@ class ZenRules extends ChessRules const step = steps[loop]; let i = x + step[0]; let j = y + step[1]; - while (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j] == V.EMPTY) + while (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY) { if (oneStep) continue outerLoop; i += step[0]; j += step[1]; } - if (i>=0 && i<sizeX && j>=0 && j<sizeY && - this.getColor(i,j) == this.getOppCol(color) && this.getPiece(i,j) == asA) + if (V.OnBoard(i,j) && this.getColor(i,j) == this.getOppCol(color) + && this.getPiece(i,j) == asA) { // eat! if (this.getPiece(x,y) == V.PAWN && i == lastRank) @@ -85,11 +81,11 @@ class ZenRules extends ChessRules { let moves = []; - Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.PAWN)); - Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.ROOK)); - Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.KNIGHT)); - Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.BISHOP)); - Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.QUEEN)); + Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.PAWN)); + Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.ROOK)); + Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.KNIGHT)); + Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.BISHOP)); + Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.QUEEN)); return moves; } @@ -97,13 +93,12 @@ class ZenRules extends ChessRules getPotentialPawnMoves([x,y]) { const color = this.getColor(x,y); - var moves = []; - var V = VariantRules; - let [sizeX,sizeY] = VariantRules.size; - let shift = (color == 'w' ? -1 : 1); - let startRank = (color == 'w' ? sizeY-2 : 1); - let firstRank = (color == 'w' ? sizeY-1 : 0); - let lastRank = (color == "w" ? 0 : sizeY-1); + let moves = []; + const [sizeX,sizeY] = [V.size.x,V.size.y]; + const shift = (color == 'w' ? -1 : 1); + const startRank = (color == 'w' ? sizeY-2 : 1); + const firstRank = (color == 'w' ? sizeY-1 : 0); + const lastRank = (color == "w" ? 0 : sizeY-1); if (x+shift >= 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")