From: Benjamin Auder Date: Tue, 20 Nov 2018 00:26:02 +0000 (+0100) Subject: Generalize code in VariantRules. Considerable speed-up for checkered bot. Prepare... X-Git-Url: https://git.auder.net/js/img/current/doc/screen_pairings_new.png?a=commitdiff_plain;h=46302e643947a66a5593a8eb1140d314effcea95;p=vchess.git Generalize code in VariantRules. Considerable speed-up for checkered bot. Prepare ground for Antiking --- diff --git a/public/javascripts/base_rules.js b/public/javascripts/base_rules.js index 16304953..0868a367 100644 --- a/public/javascripts/base_rules.js +++ b/public/javascripts/base_rules.js @@ -106,7 +106,7 @@ class ChessRules static GetBoard(fen) { let rows = fen.split(" ")[0].split("/"); - let [sizeX,sizeY] = VariantRules.size; + const [sizeX,sizeY] = VariantRules.size; let board = doubleArray(sizeX, sizeY, ""); for (let i=0; i=0 && i=0 && j=0 && i<8 && j>=0 && j<8 && this.canTake(color, this.getColor(i,j))) - moves.push(this.getBasicMove(x, y, i, j)); + if (i>=0 && i<8 && j>=0 && j<8 && this.canTake([x,y], [i,j])) + moves.push(this.getBasicMove([x,y], [i,j])); } return moves; } // What are the pawn moves from square x,y considering color "color" ? - getPotentialPawnMoves(x, y, color) + getPotentialPawnMoves([x,y]) { + const color = this.getColor(x,y); var moves = []; var V = VariantRules; - let [sizeX,sizeY] = VariantRules.size; + const [sizeX,sizeY] = VariantRules.size; let shift = (color == "w" ? -1 : 1); let startRank = (color == "w" ? sizeY-2 : 1); let lastRank = (color == "w" ? 0 : sizeY-1); @@ -297,24 +297,18 @@ class ChessRules // Normal moves if (this.board[x+shift][y] == V.EMPTY) { - moves.push(this.getBasicMove(x, y, x+shift, y)); + moves.push(this.getBasicMove([x,y], [x+shift,y])); if (x==startRank && this.board[x+2*shift][y] == V.EMPTY) { // Two squares jump - moves.push(this.getBasicMove(x, y, x+2*shift, y)); + moves.push(this.getBasicMove([x,y], [x+2*shift,y])); } } // Captures - if (y>0 && this.canTake(this.getColor(x,y), this.getColor(x+shift,y-1)) - && this.board[x+shift][y-1] != V.EMPTY) - { - 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) + moves.push(this.getBasicMove([x,y], [x+shift,y-1])); + if (y { // Normal move if (this.board[x+shift][y] == V.EMPTY) - moves.push(this.getBasicMove(x, y, x+shift, y, p)); + moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:p})); // Captures - if (y>0 && this.canTake(this.getColor(x,y), this.getColor(x+shift,y-1)) - && this.board[x+shift][y-1] != V.EMPTY) - { - moves.push(this.getBasicMove(x, y, x+shift, y-1, p)); - } - if (y0 && 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:p})); + if (y { - return !this.underCheck(m, color); - }); + let color = this.turn; + return moves.filter(m => { return !this.underCheck(m, color); }); } // Search for all valid moves considering current turn (for engine and game end) - getAllValidMoves(color) + getAllValidMoves() { + const color = this.turn; const oppCol = this.getOppCol(color); var potentialMoves = []; let [sizeX,sizeY] = VariantRules.size; @@ -512,8 +493,9 @@ class ChessRules } // Stop at the first move found - atLeastOneMove(color) + atLeastOneMove() { + const color = this.turn; const oppCol = this.getOppCol(color); let [sizeX,sizeY] = VariantRules.size; for (var i=0; i=0 && x+pawnShift<8) + for (let c of colors) { - for (let i of [-1,1]) + let pawnShift = (c=="w" ? 1 : -1); + if (x+pawnShift>=0 && x+pawnShift<8) { - if (y+i>=0 && y+i<8 && this.getPiece(x+pawnShift,y+i)==VariantRules.PAWN - && this.getColor(x+pawnShift,y+i)==c) + for (let i of [-1,1]) { - return true; + if (y+i>=0 && y+i<8 && this.getPiece(x+pawnShift,y+i)==VariantRules.PAWN + && this.getColor(x+pawnShift,y+i)==c) + { + return true; + } } } } @@ -567,42 +552,42 @@ class ChessRules } // Is square x,y attacked by rooks of color c ? - isAttackedByRook(sq, color) + isAttackedByRook(sq, colors) { - return this.isAttackedBySlideNJump(sq, color, + return this.isAttackedBySlideNJump(sq, colors, VariantRules.ROOK, VariantRules.steps[VariantRules.ROOK]); } // Is square x,y attacked by knights of color c ? - isAttackedByKnight(sq, color) + isAttackedByKnight(sq, colors) { - return this.isAttackedBySlideNJump(sq, color, + return this.isAttackedBySlideNJump(sq, colors, VariantRules.KNIGHT, VariantRules.steps[VariantRules.KNIGHT], "oneStep"); } // Is square x,y attacked by bishops of color c ? - isAttackedByBishop(sq, color) + isAttackedByBishop(sq, colors) { - return this.isAttackedBySlideNJump(sq, color, + return this.isAttackedBySlideNJump(sq, colors, VariantRules.BISHOP, VariantRules.steps[VariantRules.BISHOP]); } // Is square x,y attacked by queens of color c ? - isAttackedByQueen(sq, color) + isAttackedByQueen(sq, colors) { - return this.isAttackedBySlideNJump(sq, color, + return this.isAttackedBySlideNJump(sq, colors, VariantRules.QUEEN, VariantRules.steps[VariantRules.QUEEN]); } // Is square x,y attacked by king of color c ? - isAttackedByKing(sq, color) + isAttackedByKing(sq, colors) { - return this.isAttackedBySlideNJump(sq, color, + return this.isAttackedBySlideNJump(sq, colors, VariantRules.KING, VariantRules.steps[VariantRules.QUEEN], "oneStep"); } // Generic method for non-pawn pieces ("sliding or jumping"): is x,y attacked by piece != color ? - isAttackedBySlideNJump([x,y], c,piece,steps,oneStep) + isAttackedBySlideNJump([x,y], colors, piece, steps, oneStep) { for (let step of steps) { @@ -614,7 +599,7 @@ class ChessRules ry += step[1]; } if (rx>=0 && rx<8 && ry>=0 && ry<8 && this.board[rx][ry] != VariantRules.EMPTY - && this.getPiece(rx,ry) == piece && this.getColor(rx,ry) == c) + && this.getPiece(rx,ry) == piece && colors.includes(this.getColor(rx,ry))) { return true; } @@ -623,20 +608,22 @@ class ChessRules } // Is color c under check after move ? - underCheck(move, c) + underCheck(move) { + const color = this.turn; this.play(move); - let res = this.isAttacked(this.kingPos[c], this.getOppCol(c)); + let res = this.isAttacked(this.kingPos[color], this.getOppCol(color)); this.undo(move); return res; } // On which squares is color c under check (after move) ? - getCheckSquares(move, c) + getCheckSquares(move) { this.play(move); - let res = this.isAttacked(this.kingPos[c], this.getOppCol(c)) - ? [ JSON.parse(JSON.stringify(this.kingPos[c])) ] //need to duplicate! + const color = this.turn; + let res = this.isAttacked(this.kingPos[color], this.getOppCol(color)) + ? [ JSON.parse(JSON.stringify(this.kingPos[color])) ] //need to duplicate! : [ ]; this.undo(move); return res; @@ -723,7 +710,7 @@ class ChessRules ////////////// // END OF GAME - checkGameOver(color) + checkGameOver() { // Check for 3 repetitions if (this.moves.length >= 8) @@ -739,19 +726,20 @@ class ChessRules } } - if (this.atLeastOneMove(color)) + if (this.atLeastOneMove()) { // game not over return "*"; } // Game over - return this.checkGameEnd(color); + return this.checkGameEnd(); } - // Useful stand-alone for engine - checkGameEnd(color) + // No moves are possible: compute score + checkGameEnd() { + const color = this.turn; // No valid move: stalemate or checkmate? if (!this.isAttacked(this.kingPos[color], this.getOppCol(color))) return "1/2"; @@ -775,12 +763,12 @@ class ChessRules } // Assumption: at least one legal move - getComputerMove(color) + getComputerMove() { - const oppCol = this.getOppCol(color); + const color = this.turn; // Rank moves using a min-max at depth 2 - let moves1 = this.getAllValidMoves(color); + let moves1 = this.getAllValidMoves(); for (let i=0; i { return (color=="w" ? 1 : -1) * (b.eval - a.eval); }); @@ -825,11 +813,12 @@ class ChessRules return moves1[_.sample(candidates, 1)]; } - alphabeta(color, oppCol, depth, alpha, beta) + alphabeta(depth, alpha, beta) { - if (!this.atLeastOneMove(color)) + const color = this.turn; + if (!this.atLeastOneMove()) { - switch (this.checkGameEnd(color)) + switch (this.checkGameEnd()) { case "1/2": return 0; default: return color=="w" ? -1000 : 1000; @@ -837,14 +826,14 @@ class ChessRules } if (depth == 0) return this.evalPosition(); - const moves = this.getAllValidMoves(color); + const moves = this.getAllValidMoves(); let v = color=="w" ? -1000 : 1000; if (color == "w") { for (let i=0; i= beta) @@ -856,7 +845,7 @@ class ChessRules for (let i=0; i= beta) diff --git a/public/javascripts/components/game.js b/public/javascripts/components/game.js index 147aeafe..8e8e2770 100644 --- a/public/javascripts/components/game.js +++ b/public/javascripts/components/game.js @@ -618,10 +618,9 @@ Vue.component('my-game', { this.seek = false; if (!!moves && moves.length > 0) //imply continuation { - const oppCol = this.vr.turn; const lastMove = moves[moves.length-1]; this.vr.undo(lastMove); - this.incheck = this.vr.getCheckSquares(lastMove, oppCol); + this.incheck = this.vr.getCheckSquares(lastMove); this.vr.play(lastMove, "ingame"); } delete localStorage["newgame"]; @@ -635,8 +634,7 @@ Vue.component('my-game', { } }, playComputerMove: function() { - const compColor = this.mycolor=='w' ? 'b' : 'w'; - const compMove = this.vr.getComputerMove(compColor); + const compMove = this.vr.getComputerMove(); // HACK: avoid selecting elements before they appear on page: setTimeout(() => this.play(compMove, "animate"), 500); }, @@ -751,8 +749,7 @@ Vue.component('my-game', { this.animateMove(move); return; } - const oppCol = this.vr.getOppCol(this.vr.turn); - this.incheck = this.vr.getCheckSquares(move, oppCol); //is opponent in check? + this.incheck = this.vr.getCheckSquares(move); //is opponent in check? // Not programmatic, or animation is over if (this.mode == "human" && this.vr.turn == this.mycolor) this.conn.send(JSON.stringify({code:"newmove", move:move, oppid:this.oppid})); @@ -760,7 +757,7 @@ Vue.component('my-game', { this.vr.play(move, "ingame"); if (this.mode == "human") this.updateStorage(); //after our moves and opponent moves - const eog = this.vr.checkGameOver(this.vr.turn); + const eog = this.vr.checkGameOver(); if (eog != "*") this.endGame(eog); else if (this.mode == "computer" && this.vr.turn != this.mycolor) diff --git a/public/javascripts/variants/Antiking.js b/public/javascripts/variants/Antiking.js index ac25c736..360deafa 100644 --- a/public/javascripts/variants/Antiking.js +++ b/public/javascripts/variants/Antiking.js @@ -7,6 +7,12 @@ class AntikingRules } static get ANTIKING() { return 'a'; } + + initVariables(fen) + { + super.initVariables(fen); + // TODO: initialize this.antikingPos[...] + } canTake(color1, color2, [x,y]) { @@ -26,23 +32,14 @@ class AntikingRules } } -// TODO: generaliser (à moindre coût) base_rules ? Ou spécialiser variantes ? - - getPotentialAntikingMoves(x, y, c) + getPotentialAntikingMoves([x,y]) { // TODO } -// TODO: need to re-think some logic, since antikings capture same color - - isAttacked(sq, color) + isAttacked(sq, colors) { - return (this.isAttackedByPawn(sq, color) - || this.isAttackedByRook(sq, color) - || this.isAttackedByKnight(sq, color) - || this.isAttackedByBishop(sq, color) - || this.isAttackedByQueen(sq, color) - || this.isAttackedByKing(sq, color)); //... + return (super.isAttacked(sq, colors) || this.isAttackedByAntiking(sq, colors)); } isAttackedByAntiking(sq, color) @@ -50,8 +47,9 @@ class AntikingRules // TODO } - underCheck(move, c) + underCheck(move) { + const c = this.turn; this.play(move); let res = this.isAttacked(this.kingPos[c], this.getOppCol(c)); // TODO: also check that antiking is still in check @@ -59,34 +57,18 @@ class AntikingRules return res; } - getCheckSquares(move, c) + getCheckSquares(move) { this.play(move); + const c = this.turn; // TODO let res = this.isAttacked(this.kingPos[c], this.getOppCol(c)) - ? [ JSON.parse(JSON.stringify(this.kingPos[c])) ] //need to duplicate! + ? [ JSON.parse(JSON.stringify(this.kingPos[c])) ] : [ ]; this.undo(move); return res; } - // Apply a move on board - static PlayOnBoard(board, move) - { - for (let psq of move.vanish) - board[psq.x][psq.y] = VariantRules.EMPTY; - for (let psq of move.appear) - board[psq.x][psq.y] = psq.c + psq.p; - } - // Un-apply the played move - static UndoOnBoard(board, move) - { - for (let psq of move.appear) - board[psq.x][psq.y] = VariantRules.EMPTY; - for (let psq of move.vanish) - board[psq.x][psq.y] = psq.c + psq.p; - } - // TODO: need antikingPos as well updateVariables(move) { @@ -106,7 +88,7 @@ class AntikingRules return color == "w" ? "0-1" : "1-0"; } - // Pieces values + // Pieces values (TODO: use Object.assign() + ChessRules.VALUES ?) static get VALUES() { return { 'p': 1, @@ -121,55 +103,8 @@ class AntikingRules static GenRandInitFen() { - // TODO: no need all code, just add an antiking at rondom on 3rd ranks - let pieces = [new Array(8), new Array(8)]; - // Shuffle pieces on first and last rank - for (let c = 0; c <= 1; c++) - { - let positions = _.range(8); - - // Get random squares for bishops - let randIndex = 2 * _.random(3); - let bishop1Pos = positions[randIndex]; - // The second bishop must be on a square of different color - let randIndex_tmp = 2 * _.random(3) + 1; - let bishop2Pos = positions[randIndex_tmp]; - // Remove chosen squares - positions.splice(Math.max(randIndex,randIndex_tmp), 1); - positions.splice(Math.min(randIndex,randIndex_tmp), 1); - - // Get random squares for knights - randIndex = _.random(5); - let knight1Pos = positions[randIndex]; - positions.splice(randIndex, 1); - randIndex = _.random(4); - let knight2Pos = positions[randIndex]; - positions.splice(randIndex, 1); - - // Get random square for queen - randIndex = _.random(3); - let queenPos = positions[randIndex]; - positions.splice(randIndex, 1); - - // Rooks and king positions are now fixed, because of the ordering rook-king-rook - let rook1Pos = positions[0]; - let kingPos = positions[1]; - let rook2Pos = positions[2]; - - // Finally put the shuffled pieces in the board array - pieces[c][rook1Pos] = 'r'; - pieces[c][knight1Pos] = 'n'; - pieces[c][bishop1Pos] = 'b'; - pieces[c][queenPos] = 'q'; - pieces[c][kingPos] = 'k'; - pieces[c][bishop2Pos] = 'b'; - pieces[c][knight2Pos] = 'n'; - pieces[c][rook2Pos] = 'r'; - } - let fen = pieces[0].join("") + - "/pppppppp/8/8/8/8/PPPPPPPP/" + - pieces[1].join("").toUpperCase() + - " 1111"; //add flags - return fen; + let randFen = ChessRules.GenRandInitFen(); + // TODO: just add an antiking at random on 3rd ranks + return randFen; } } diff --git a/public/javascripts/variants/Atomic.js b/public/javascripts/variants/Atomic.js index 0fd7647e..d86ed0e1 100644 --- a/public/javascripts/variants/Atomic.js +++ b/public/javascripts/variants/Atomic.js @@ -1,8 +1,8 @@ class AtomicRules extends ChessRules { - getPotentialMovesFrom([x,y], c, lastMove) + getPotentialMovesFrom([x,y]) { - let moves = super.getPotentialMovesFrom([x,y], c, lastMove); + let moves = super.getPotentialMovesFrom([x,y]); // Handle explosions moves.forEach(m => { @@ -28,7 +28,7 @@ class AtomicRules extends ChessRules return moves; } - getPotentialKingMoves(x, y, c) + getPotentialKingMoves([x,y]) { // King cannot capture: let moves = []; @@ -39,20 +39,20 @@ class AtomicRules extends ChessRules var i = x + step[0]; var j = y + step[1]; if (i>=0 && i=0 && j=0 && i=0 && j=0 && i=0 && j=0 && i<8 && j>=0 && j<8 && this.canTake(color, this.getColor(i,j))) - moves = moves.concat(this.getBasicMove(x, y, i, j)); + if (i>=0 && i<8 && j>=0 && j<8 && this.canTake([x,y], [i,j])) + this.addCaptures([x,y], [i,j], moves); } return moves; } // What are the pawn moves from square x,y considering color "color" ? - getPotentialPawnMoves(x, y, color) + getPotentialPawnMoves([x,y]) { + const color = this.getColor(x,y); var moves = []; var V = VariantRules; let [sizeX,sizeY] = VariantRules.size; @@ -144,24 +115,18 @@ class CheckeredRules extends ChessRules // Normal moves if (this.board[x+shift][y] == V.EMPTY) { - moves.push(this.getBasicMove(x, y, x+shift, y)[0]); + moves.push(this.getBasicMove([x,y], [x+shift,y])); if (x==startRank && this.board[x+2*shift][y] == V.EMPTY && this.flags[1][c][y]) { // Two squares jump - moves.push(this.getBasicMove(x, y, x+2*shift, y)[0]); + moves.push(this.getBasicMove([x,y], [x+2*shift,y])); } } // Captures - if (y>0 && this.canTake(this.getColor(x,y), this.getColor(x+shift,y-1)) - && this.board[x+shift][y-1] != V.EMPTY) - { - moves = moves.concat(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) + this.addCaptures([x,y], [x+shift,y-1], moves); + if (y { // Normal move if (this.board[x+shift][y] == V.EMPTY) - moves.push(this.getBasicMove(x, y, x+shift, y, p)[0]); + moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:p})); // Captures - if (y>0 && this.canTake(this.getColor(x,y), this.getColor(x+shift,y-1)) - && this.board[x+shift][y-1] != V.EMPTY) - { - moves = moves.concat(this.getBasicMove(x, y, x+shift, y-1, p)); - } - if (y0 && 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:'c',p:p})); + if (y { const L = this.moves.length; if (L > 0 && this.oppositeMoves(this.moves[L-1], m)) return false; - return !this.underCheck(m, color); + return !this.underCheck(m); }); } - isAttackedByPawn([x,y], c) - { - const color = (c=="c" ? this.turn : c); - let pawnShift = (color=="w" ? 1 : -1); - if (x+pawnShift>=0 && x+pawnShift<8) - { - for (let i of [-1,1]) - { - if (y+i>=0 && y+i<8 && this.getPiece(x+pawnShift,y+i)==VariantRules.PAWN - && this.getColor(x+pawnShift,y+i)==c) - { - return true; - } - } - } - return false; - } - - underCheck(move, c) + isAttackedByPawn([x,y], colors) + { + for (let c of colors) + { + const color = (c=="c" ? this.turn : c); + let pawnShift = (color=="w" ? 1 : -1); + if (x+pawnShift>=0 && x+pawnShift<8) + { + for (let i of [-1,1]) + { + if (y+i>=0 && y+i<8 && this.getPiece(x+pawnShift,y+i)==VariantRules.PAWN + && this.getColor(x+pawnShift,y+i)==c) + { + return true; + } + } + } + } + return false; + } + + underCheck(move) { - const color = c == 'c' ? this.turn : c; + const color = this.turn; this.play(move); - let res = this.isAttacked(this.kingPos[color], this.getOppCol(color)) - || this.isAttacked(this.kingPos[color], 'c'); //TODO: quite inefficient... + let res = this.isAttacked(this.kingPos[color], [this.getOppCol(color),'c']); this.undo(move); return res; } - getCheckSquares(move, c) + getCheckSquares(move) { this.play(move); + const color = this.turn; this.moves.push(move); //artifically change turn, for checkered pawns (TODO) - const kingAttacked = this.isAttacked(this.kingPos[c], this.getOppCol(c)) - || this.isAttacked(this.kingPos[c], 'c'); + const kingAttacked = this.isAttacked(this.kingPos[color], [this.getOppCol(color),'c']); let res = kingAttacked - ? [ JSON.parse(JSON.stringify(this.kingPos[c])) ] //need to duplicate! + ? [ JSON.parse(JSON.stringify(this.kingPos[color])) ] //need to duplicate! : [ ]; this.moves.pop(); this.undo(move); @@ -387,8 +346,9 @@ class CheckeredRules extends ChessRules this.flags[1][move.start.x==6 ? "w" : "b"][move.start.y] = false; } - checkGameEnd(color) + checkGameEnd() { + const color = this.turn; if (!this.isAttacked(this.kingPos[color], this.getOppCol(color)) && !this.isAttacked(this.kingPos[color], 'c')) { diff --git a/public/javascripts/variants/Zen.js b/public/javascripts/variants/Zen.js index bfc0e0ab..b7f229c3 100644 --- a/public/javascripts/variants/Zen.js +++ b/public/javascripts/variants/Zen.js @@ -7,8 +7,9 @@ class ZenRules extends ChessRules } // TODO: some duplicated code in 2 next functions - getSlideNJumpMoves(x, y, color, steps, oneStep) + getSlideNJumpMoves([x,y], steps, oneStep) { + const color = this.getColor(x,y); var moves = []; let [sizeX,sizeY] = VariantRules.size; outerLoop: @@ -20,8 +21,8 @@ class ZenRules extends ChessRules while (i>=0 && i=0 && j { - moves.push(this.getBasicMove(x, y, i, j, p)); + moves.push(this.getBasicMove([x,y], [i,j], {c:color,p:p})); }); } else { // All other cases - moves.push(this.getBasicMove(x, y, i, j)); + moves.push(this.getBasicMove([x,y], [i,j])); } } } @@ -80,35 +82,31 @@ class ZenRules extends ChessRules } // Find possible captures from a square: look in every direction! - findCaptures(x, y, color) + findCaptures(sq) { var moves = []; // PAWN - Array.prototype.push.apply(moves, - this.findCaptures_aux(x, y, color, VariantRules.PAWN)); + Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.PAWN)); // ROOK - Array.prototype.push.apply(moves, - this.findCaptures_aux(x, y, color, VariantRules.ROOK)); + Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.ROOK)); // KNIGHT - Array.prototype.push.apply(moves, - this.findCaptures_aux(x, y, color, VariantRules.KNIGHT)); + Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.KNIGHT)); // BISHOP - Array.prototype.push.apply(moves, - this.findCaptures_aux(x, y, color, VariantRules.BISHOP)); + Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.BISHOP)); // QUEEN - Array.prototype.push.apply(moves, - this.findCaptures_aux(x, y, color, VariantRules.QUEEN)); + Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.QUEEN)); return moves; } - getPotentialPawnMoves(x, y, color) + getPotentialPawnMoves([x,y]) { + const color = this.getColor(x,y); var moves = []; var V = VariantRules; let [sizeX,sizeY] = VariantRules.size; @@ -122,11 +120,11 @@ class ZenRules extends ChessRules // Normal moves if (this.board[x+shift][y] == V.EMPTY) { - moves.push(this.getBasicMove(x, y, x+shift, y)); + moves.push(this.getBasicMove([x,y], [x+shift,y])); if ([startRank,firstRank].includes(x) && this.board[x+2*shift][y] == V.EMPTY) { //two squares jump - moves.push(this.getBasicMove(x, y, x+2*shift, y)); + moves.push(this.getBasicMove([x,y], [x+2*shift,y])); } } } @@ -138,62 +136,52 @@ class ZenRules extends ChessRules promotionPieces.forEach(p => { // Normal move if (this.board[x+shift][y] == V.EMPTY) - moves.push(this.getBasicMove(x, y, x+shift, y, p)); + moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:p})); }); } // No en passant here // Add "zen" captures - Array.prototype.push.apply(moves, this.findCaptures(x, y, color)); + Array.prototype.push.apply(moves, this.findCaptures([x,y])); return moves; } - getPotentialRookMoves(x, y, color) + getPotentialRookMoves(sq) { - let noCaptures = this.getSlideNJumpMoves( - x, y, color, VariantRules.steps[VariantRules.ROOK]); - let captures = this.findCaptures(x, y, color); + let noCaptures = this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.ROOK]); + let captures = this.findCaptures(sq); return noCaptures.concat(captures); } - getPotentialKnightMoves(x, y, color) + getPotentialKnightMoves(sq) { - let noCaptures = this.getSlideNJumpMoves( - x, y, color, VariantRules.steps[VariantRules.KNIGHT], "oneStep"); - let captures = this.findCaptures(x, y, color); + let noCaptures = this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.KNIGHT], "oneStep"); + let captures = this.findCaptures(sq); return noCaptures.concat(captures); } - getPotentialBishopMoves(x, y, color) + getPotentialBishopMoves(sq) { - let noCaptures = this.getSlideNJumpMoves( - x, y, color, VariantRules.steps[VariantRules.BISHOP]); - let captures = this.findCaptures(x, y, color); + let noCaptures = this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.BISHOP]); + let captures = this.findCaptures(sq); return noCaptures.concat(captures); } - getPotentialQueenMoves(x, y, color) + getPotentialQueenMoves(sq) { - let noCaptures = this.getSlideNJumpMoves( - x, y, color, VariantRules.steps[VariantRules.QUEEN]); - let captures = this.findCaptures(x, y, color); + let noCaptures = this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.QUEEN]); + let captures = this.findCaptures(sq); return noCaptures.concat(captures); } - getPotentialKingMoves(x, y, c) + getPotentialKingMoves(sq) { // Initialize with normal moves - let noCaptures = this.getSlideNJumpMoves( - x, y, c, VariantRules.steps[VariantRules.QUEEN], "oneStep"); - let captures = this.findCaptures(x, y, c); - - let moves = noCaptures - .concat(captures) - .concat(this.getCastleMoves(x, y, c)); - - return moves; + let noCaptures = this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.QUEEN], "oneStep"); + let captures = this.findCaptures(sq); + return noCaptures.concat(captures).concat(this.getCastleMoves(sq)); } getNotation(move)