Simplified underCheck / getCheckSquares logic. Debugging Berolina
authorBenjamin Auder <benjamin.auder@somewhere>
Tue, 25 Dec 2018 01:08:30 +0000 (02:08 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Tue, 25 Dec 2018 01:08:30 +0000 (02:08 +0100)
12 files changed:
public/javascripts/base_rules.js
public/javascripts/components/game.js
public/javascripts/variants/Alice.js
public/javascripts/variants/Antiking.js
public/javascripts/variants/Atomic.js
public/javascripts/variants/Berolina.js
public/javascripts/variants/Checkered.js
public/javascripts/variants/Dark.js
public/javascripts/variants/Extinction.js
public/javascripts/variants/Loser.js
public/javascripts/variants/Magnetic.js
public/javascripts/variants/Upsidedown.js

index 6cdae32..0bf5114 100644 (file)
@@ -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();
index 3474ea8..c14130b 100644 (file)
@@ -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);
                        }
                },
        },
index 1cbfccf..2be714f 100644 (file)
@@ -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;
        }
 
index 25a9dfc..ed69ab7 100644 (file)
@@ -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;
        }
 
index 666c50b..2adb988 100644 (file)
@@ -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;
        }
 
index c556f51..dc9e257 100644 (file)
@@ -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<sizeY
+                                               && this.board[x+2*shiftX][y+2*shiftY] == V.EMPTY)
                                        {
                                                // Two squares jump
-                                               moves.push(this.getBasicMove([x,y], [x+2*shiftX,y+2*shiftY]);
+                                               moves.push(this.getBasicMove([x,y], [x+2*shiftX,y+2*shiftY]));
                                        }
                                }
                        }
@@ -64,10 +61,7 @@ class BerolinaRules extends ChessRules
                                && this.canTake([x,y], [x+shiftX,y]))
                        {
                                for (let piece of finalPieces)
-                               {
-                                       moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY],
-                                               {c:pawnColor,p:piece}));
-                               }
+                                       moves.push(this.getBasicMove([x,y], [x+shiftX,y], {c:color,p:piece}));
                        }
                }
 
@@ -76,18 +70,32 @@ class BerolinaRules extends ChessRules
                const epSquare = this.epSquares[Lep-1]; //always at least one element
                if (!!epSquare && epSquare.x == x+shiftX && epSquare.y == y)
                {
-                       let enpassantMove = this.getBasicMove([x,y], [x+shift,y]);
+                       let enpassantMove = this.getBasicMove([x,y], [x+shiftX,y]);
                        enpassantMove.vanish.push({
                                x: epSquare.x,
-                               y: y,
+                               y: epSquare.y,
                                p: 'p',
-                               c: this.getColor(epSquare.x,y)
+                               c: this.getColor(epSquare.x,epSquare.y)
                        });
                        moves.push(enpassantMove);
                }
 
                return moves;
        }
+
+       isAttackedByPawn([x,y], colors)
+       {
+               for (let c of colors)
+               {
+                       let pawnShift = (c=="w" ? 1 : -1);
+                       if (x+pawnShift>=0 && x+pawnShift<V.size.x)
+                       {
+                               if (this.getPiece(x+pawnShift,y)==V.PAWN && this.getColor(x+pawnShift,y)==c)
+                                       return true;
+                       }
+               }
+               return false;
+       }
 }
 
 const VariantRules = BerolinaRules;
index d73cef4..eee21b8 100644 (file)
@@ -151,7 +151,10 @@ class CheckeredRules extends ChessRules
                        const L = this.moves.length;
                        if (L > 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;
        }
 
index 4031462..e3e093b 100644 (file)
@@ -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<V.size.x; i++)
+               {
+                       for (let j=0; j<V.size.y; j++)
+                       {
+                               if (this.board[i][j] != V.EMPTY && this.getColor(i,j) == color)
+                                       Array.prototype.push.apply(potentialMoves, this.getPotentialMovesFrom([i,j]));
+                       }
+               }
+               return potentialMoves; //because there are no checks
+       }
+
        atLeastOneMove()
        {
                if (this.kingPos[this.turn][0] < 0)
@@ -46,22 +63,14 @@ class DarkRules extends ChessRules
                return true; //TODO: is it right?
        }
 
-       underCheck(move)
+       underCheck(color)
        {
                return false; //there is no check
        }
 
-       getCheckSquares(move)
+       getCheckSquares(color)
        {
-               const c = this.getOppCol(this.turn); //opponent
-               const saveKingPos = this.kingPos[c]; //king might be taken
-               this.play(move);
-               // The only way to be "under check" is to have lost the king (thus game over)
-               let res = this.kingPos[c][0] < 0
-                       ? [JSON.parse(JSON.stringify(saveKingPos))]
-                       : [];
-               this.undo(move);
-               return res;
+               return [];
        }
 
        updateVariables(move)
index bc06162..2f57260 100644 (file)
@@ -64,12 +64,12 @@ class ExtinctionRules extends ChessRules
                return true; //always at least one possible move
        }
 
-       underCheck(move)
+       underCheck(color)
        {
                return false; //there is no check
        }
 
-       getCheckSquares(move)
+       getCheckSquares(color)
        {
                return [];
        }
index e6eb320..dcc5c11 100644 (file)
@@ -87,7 +87,7 @@ class LoserRules extends ChessRules
                return moves;
        }
 
-       underCheck(move)
+       underCheck(color)
        {
                return false; //No notion of check
        }
index 1ccc192..7b0d096 100644 (file)
@@ -139,22 +139,14 @@ class MagneticRules extends ChessRules
                return true; //TODO: is it right?
        }
 
-       underCheck(move)
+       underCheck(color)
        {
                return false; //there is no check
        }
 
        getCheckSquares(move)
        {
-               const c = this.getOppCol(this.turn); //opponent
-               const saveKingPos = this.kingPos[c]; //king might be taken
-               this.play(move);
-               // The only way to be "under check" is to have lost the king (thus game over)
-               let res = this.kingPos[c][0] < 0
-                       ? [JSON.parse(JSON.stringify(saveKingPos))]
-                       : [];
-               this.undo(move);
-               return res;
+               return [];
        }
 
        updateVariables(move)
index aa9a696..f966899 100644 (file)
@@ -1,7 +1,15 @@
-class UpsidedownRules extends ChessRUles
+class UpsidedownRules extends ChessRules
 {
        static HasFlags() { return false; }
 
+       // Forbid two knights moves in a row at moves 1 and 2
+       getPotentialKnightMoves(sq)
+       {
+               // But this will also affect FEN for problems, and...
+               // does it really solve the problem ?
+               //if (this.moves. ...)
+       }
+
        getPotentialKingMoves(sq)
        {
                // No castle
@@ -47,9 +55,9 @@ class UpsidedownRules extends ChessRUles
                        pieces[c][knight2Pos] = 'n';
                        pieces[c][rook2Pos] = 'r';
                }
-               return pieces["w"].join("") +
+               return pieces["w"].join("").toUpperCase() +
                        "/PPPPPPPP/8/8/8/8/pppppppp/" +
-                       pieces["b"].join("").toUpperCase() +
+                       pieces["b"].join("") +
                        " w 1111 -"; //add turn + flags + enpassant
        }
 }