From: Benjamin Auder Date: Tue, 25 Dec 2018 01:08:30 +0000 (+0100) Subject: Simplified underCheck / getCheckSquares logic. Debugging Berolina X-Git-Url: https://git.auder.net/doc/html/css/img/current/pieces/%7B%7B%20pkg.url%20%7D%7D?a=commitdiff_plain;h=f6dbe8e31a3260487664f1e0b50710b3f3efaf5f;p=vchess.git Simplified underCheck / getCheckSquares logic. Debugging Berolina --- diff --git a/public/javascripts/base_rules.js b/public/javascripts/base_rules.js index 6cdae328..0bf5114a 100644 --- a/public/javascripts/base_rules.js +++ b/public/javascripts/base_rules.js @@ -195,16 +195,12 @@ class ChessRules return (this.turn == side && this.getColor(x,y) == side); } - // On which squares is opponent under check after our move ? (for interface) - getCheckSquares(move) + // On which squares is color under check ? (for interface) + getCheckSquares(color) { - this.play(move); - const color = this.turn; //opponent - let res = this.isAttacked(this.kingPos[color], [this.getOppCol(color)]) + return this.isAttacked(this.kingPos[color], [this.getOppCol(color)]) ? [JSON.parse(JSON.stringify(this.kingPos[color]))] //need to duplicate! : []; - this.undo(move); - return res; } ///////////// @@ -766,9 +762,9 @@ class ChessRules //////////////////// // MOVES VALIDATION + // For the interface: possible moves for the current turn from square sq getPossibleMovesFrom(sq) { - // Assuming color is right (already checked) return this.filterValid( this.getPotentialMovesFrom(sq) ); } @@ -777,7 +773,13 @@ class ChessRules { if (moves.length == 0) return []; - return moves.filter(m => { return !this.underCheck(m); }); + const color = this.turn; + return moves.filter(m => { + this.play(m); + const res = !this.underCheck(color); + this.undo(m); + return res; + }); } // Search for all valid moves considering current turn (for engine and game end) @@ -912,14 +914,10 @@ class ChessRules return false; } - // Is current player under check after his move ? - underCheck(move) + // Is color under check after his move ? + underCheck(color) { - const color = this.turn; - this.play(move); - let res = this.isAttacked(this.kingPos[color], [this.getOppCol(color)]); - this.undo(move); - return res; + return this.isAttacked(this.kingPos[color], [this.getOppCol(color)]); } ///////////////// @@ -945,8 +943,8 @@ class ChessRules // Before move is played, update variables + flags updateVariables(move) { - const piece = this.getPiece(move.start.x,move.start.y); - const c = this.turn; + const piece = move.vanish[0].p; + const c = move.vanish[0].c; const firstRank = (c == "w" ? V.size.x-1 : 0); // Update king position + flags @@ -986,6 +984,7 @@ class ChessRules play(move, ingame) { // DEBUG: +// console.log("DO"); // if (!this.states) this.states = []; // if (!ingame) this.states.push(this.getFen()); @@ -1020,6 +1019,7 @@ class ChessRules this.unupdateVariables(move); // DEBUG: +// console.log("UNDO "+this.getNotation(move)); // if (this.getFen() != this.states[this.states.length-1]) // debugger; // this.states.pop(); diff --git a/public/javascripts/components/game.js b/public/javascripts/components/game.js index 3474ea84..c14130b5 100644 --- a/public/javascripts/components/game.js +++ b/public/javascripts/components/game.js @@ -24,7 +24,7 @@ Vue.component('my-game', { incheck: [], pgnTxt: "", hints: (!localStorage["hints"] ? true : localStorage["hints"] === "1"), - color: localStorage["color"] || "lichess", //lichess, chesscom or chesstempo + bcolor: localStorage["bcolor"] || "lichess", //lichess, chesscom or chesstempo // sound level: 0 = no sound, 1 = sound only on newgame, 2 = always sound: parseInt(localStorage["sound"] || "2"), // Web worker to play computer moves without freezing interface: @@ -342,7 +342,7 @@ Vue.component('my-game', { ['board'+sizeY]: true, 'light-square': (i+j)%2==0, 'dark-square': (i+j)%2==1, - [this.color]: true, + [this.bcolor]: true, 'in-shadow': variant=="Dark" && this.score=="*" && !this.vr.enlightened[this.mycolor][ci][cj], 'highlight': showLight && !!lm && _.isMatch(lm.end, {x:ci,y:cj}), @@ -695,7 +695,7 @@ Vue.component('my-game', { h("select", { attrs: { "id": "selectColor" }, - on: { "change": this.setColor }, + on: { "change": this.setBoardColor }, }, [ h("option", @@ -1239,9 +1239,9 @@ Vue.component('my-game', { this.hints = !this.hints; localStorage["hints"] = (this.hints ? "1" : "0"); }, - setColor: function(e) { - this.color = e.target.options[e.target.selectedIndex].value; - localStorage["color"] = this.color; + setBoardColor: function(e) { + this.bcolor = e.target.options[e.target.selectedIndex].value; + localStorage["bcolor"] = this.bcolor; }, setSound: function(e) { this.sound = parseInt(e.target.options[e.target.selectedIndex].value); @@ -1280,7 +1280,7 @@ Vue.component('my-game', { this.endGame(this.mycolor=="w"?"0-1":"1-0"); }, newGame: function(mode, fenInit, color, oppId) { - let fen = fenInit || VariantRules.GenRandInitFen(); + const fen = fenInit || VariantRules.GenRandInitFen(); console.log(fen); //DEBUG if (mode=="human" && !oppId) { @@ -1352,7 +1352,9 @@ Vue.component('my-game', { if (this.mycolor != this.vr.turn) this.playComputerMove(); } - //else: against a (IRL) friend or problem solving: nothing more to do + else if (mode == "friend") + this.mycolor = "w"; //convention... + //else: problem solving: nothing more to do }, continueGame: function(mode) { this.mode = mode; @@ -1364,6 +1366,7 @@ Vue.component('my-game', { const score = localStorage.getItem(prefix+"score"); //set in "endGame()" this.fenStart = localStorage.getItem(prefix+"fenStart"); this.vr = new VariantRules(fen, moves); + this.incheck = this.vr.getCheckSquares(this.vr.turn); if (mode == "human") { this.gameId = localStorage.getItem("gameId"); @@ -1377,13 +1380,6 @@ Vue.component('my-game', { if (this.mycolor != this.vr.turn) this.playComputerMove(); } - if (moves.length > 0) - { - const lastMove = moves[moves.length-1]; - this.vr.undo(lastMove); - this.incheck = this.vr.getCheckSquares(lastMove); - this.vr.play(lastMove, "ingame"); - } if (score != "*") { // Small delay required when continuation run faster than drawing page @@ -1444,6 +1440,7 @@ Vue.component('my-game', { if (this.vr.canIplay(color,startSquare)) this.possibleMoves = this.vr.getPossibleMovesFrom(startSquare); } + console.log(this.possibleMoves); // Next line add moving piece just after current image // (required for Crazyhouse reserve) e.target.parentNode.insertBefore(this.selectedPiece, e.target.nextSibling); @@ -1554,8 +1551,9 @@ Vue.component('my-game', { // TODO: robustify this... if (this.mode == "human" && !!move.computer) return; - this.incheck = this.vr.getCheckSquares(move); //is opponent in check? this.vr.play(move, "ingame"); + // Is opponent in check? + this.incheck = this.vr.getCheckSquares(this.vr.turn); if (this.sound == 2) new Audio("/sounds/move.mp3").play().catch(err => {}); if (this.mode == "computer") @@ -1606,15 +1604,7 @@ Vue.component('my-game', { this.vr.undo(lm); if (this.sound == 2) new Audio("/sounds/undo.mp3").play().catch(err => {}); - const lmBefore = this.vr.lastMove; - if (!!lmBefore) - { - this.vr.undo(lmBefore); - this.incheck = this.vr.getCheckSquares(lmBefore); - this.vr.play(lmBefore, "ingame"); - } - else - this.incheck = []; + this.incheck = this.vr.getCheckSquares(this.vr.turn); } }, }, diff --git a/public/javascripts/variants/Alice.js b/public/javascripts/variants/Alice.js index 1cbfccf3..2be714f0 100644 --- a/public/javascripts/variants/Alice.js +++ b/public/javascripts/variants/Alice.js @@ -160,7 +160,13 @@ class AliceRules extends ChessRules if (moves.length == 0) return []; let sideBoard = [this.getSideBoard(1), this.getSideBoard(2)]; - return moves.filter(m => { return !this.underCheck(m, sideBoard); }); + const color = this.turn; + return moves.filter(m => { + this.playSide(m, sideBoard); //no need to track flags + const res = !this.underCheck(color, sideBoard); + this.undoSide(m, sideBoard); + return res; + }); } getAllValidMoves() @@ -221,24 +227,19 @@ class AliceRules extends ChessRules }); } - underCheck(move, sideBoard) //sideBoard arg always provided + underCheck(color, sideBoard) //sideBoard arg always provided { - 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]] != V.EMPTY ? 1 : 2); let saveBoard = this.board; this.board = sideBoard[mirrorSide-1]; let res = this.isAttacked(kp, [this.getOppCol(color)]); this.board = saveBoard; - this.undoSide(move, sideBoard); return res; } - getCheckSquares(move) + getCheckSquares(color) { - this.play(move); - const color = this.turn; //opponent const pieces = Object.keys(V.ALICE_CODES); const kp = this.kingPos[color]; const mirrorSide = (pieces.includes(this.getPiece(kp[0],kp[1])) ? 1 : 2); @@ -249,7 +250,6 @@ class AliceRules extends ChessRules ? [ JSON.parse(JSON.stringify(this.kingPos[color])) ] : [ ]; this.board = saveBoard; - this.undo(move); return res; } diff --git a/public/javascripts/variants/Antiking.js b/public/javascripts/variants/Antiking.js index 25a9dfcd..ed69ab71 100644 --- a/public/javascripts/variants/Antiking.js +++ b/public/javascripts/variants/Antiking.js @@ -88,25 +88,19 @@ class AntikingRules extends ChessRules V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep"); } - underCheck(move) + underCheck(color) { - const c = this.turn; - const oppCol = this.getOppCol(c); - this.play(move) - let res = this.isAttacked(this.kingPos[c], [oppCol]) - || !this.isAttacked(this.antikingPos[c], [oppCol]); - this.undo(move); + const oppCol = this.getOppCol(color); + let res = this.isAttacked(this.kingPos[color], [oppCol]) + || !this.isAttacked(this.antikingPos[color], [oppCol]); return res; } - getCheckSquares(move) + getCheckSquares(color) { - let res = super.getCheckSquares(move); - this.play(move); - const c = this.turn; - if (!this.isAttacked(this.antikingPos[c], [this.getOppCol(c)])) - res.push(JSON.parse(JSON.stringify(this.antikingPos[c]))); - this.undo(move); + let res = super.getCheckSquares(color); + if (!this.isAttacked(this.antikingPos[color], [this.getOppCol(color)])) + res.push(JSON.parse(JSON.stringify(this.antikingPos[color]))); return res; } diff --git a/public/javascripts/variants/Atomic.js b/public/javascripts/variants/Atomic.js index 666c50b2..2adb9884 100644 --- a/public/javascripts/variants/Atomic.js +++ b/public/javascripts/variants/Atomic.js @@ -102,37 +102,30 @@ class AtomicRules extends ChessRules } } - underCheck(move) + underCheck(color) { - const c = this.turn; - const oppCol = this.getOppCol(c); - this.play(move); + const oppCol = this.getOppCol(color); let res = undefined; // If our king disappeared, move is not valid - if (this.kingPos[c][0] < 0) + if (this.kingPos[color][0] < 0) res = true; // If opponent king disappeared, move is valid else if (this.kingPos[oppCol][0] < 0) res = false; // Otherwise, if we remain under check, move is not valid else - res = this.isAttacked(this.kingPos[c], [oppCol]); - this.undo(move); + res = this.isAttacked(this.kingPos[color], [oppCol]); return res; } - getCheckSquares(move) + getCheckSquares(color) { - const c = this.getOppCol(this.turn); - // King might explode: - const saveKingPos = JSON.parse(JSON.stringify(this.kingPos[c])); - this.play(move); let res = [ ]; - if (this.kingPos[c][0] < 0) - res = [saveKingPos]; - else if (this.isAttacked(this.kingPos[c], [this.getOppCol(c)])) - res = [ JSON.parse(JSON.stringify(this.kingPos[c])) ] - this.undo(move); + if (this.kingPos[color][0] >= 0 //king might have exploded + && this.isAttacked(this.kingPos[color], [this.getOppCol(color)])) + { + res = [ JSON.parse(JSON.stringify(this.kingPos[color])) ] + } return res; } diff --git a/public/javascripts/variants/Berolina.js b/public/javascripts/variants/Berolina.js index c556f517..dc9e2574 100644 --- a/public/javascripts/variants/Berolina.js +++ b/public/javascripts/variants/Berolina.js @@ -18,15 +18,14 @@ class BerolinaRules extends ChessRules if (this.getPiece(sx,sy) == V.PAWN && Math.abs(sx - ex) == 2) { return { - x: ex, + x: (ex + sx)/2, y: (move.end.y + sy)/2 }; } return undefined; //default } - // Special pawn rules: promotions to captured friendly pieces, - // optional on ranks 8-9 and mandatory on rank 10. + // Special pawns movements getPotentialPawnMoves([x,y]) { const color = this.turn; @@ -48,14 +47,12 @@ class BerolinaRules extends ChessRules if (this.board[x+shiftX][y+shiftY] == V.EMPTY) { for (let piece of finalPieces) - { - moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY], - {c:pawnColor,p:piece})); - } - if (x == startRank && this.board[x+2*shiftX][y] == V.EMPTY) + moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY], {c:color,p:piece})); + if (x == startRank && y+2*shiftY>=0 && y+2*shiftY=0 && x+pawnShift 0 && this.oppositeMoves(this.moves[L-1], m)) return false; - return !this.underCheck(m); + this.play(m); + const res = !this.underCheck(color); + this.undo(m); + return res; }); } @@ -176,19 +179,13 @@ class CheckeredRules extends ChessRules return false; } - underCheck(move) + underCheck(color) { - const color = this.turn; - this.play(move); - let res = this.isAttacked(this.kingPos[color], [this.getOppCol(color),'c']); - this.undo(move); - return res; + return this.isAttacked(this.kingPos[color], [this.getOppCol(color),'c']); } - getCheckSquares(move) + getCheckSquares(color) { - this.play(move); - const color = this.turn; // Artifically change turn, for checkered pawns this.turn = this.getOppCol(color); const kingAttacked = this.isAttacked( @@ -197,7 +194,6 @@ class CheckeredRules extends ChessRules ? [JSON.parse(JSON.stringify(this.kingPos[color]))] //need to duplicate! : []; this.turn = color; - this.undo(move); return res; } diff --git a/public/javascripts/variants/Dark.js b/public/javascripts/variants/Dark.js index 4031462c..e3e093b1 100644 --- a/public/javascripts/variants/Dark.js +++ b/public/javascripts/variants/Dark.js @@ -39,6 +39,23 @@ class DarkRules extends ChessRules this.enlightened["b"][move.end.x][move.end.y] = true; } + // Has to be redefined to avoid an infinite loop + getAllValidMoves() + { + const color = this.turn; + const oppCol = this.getOppCol(color); + let potentialMoves = []; + for (let i=0; i