Highlight king in red if undercheck + some improvements
authorBenjamin Auder <benjamin.auder@somewhere>
Sat, 17 Nov 2018 17:11:18 +0000 (18:11 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Sat, 17 Nov 2018 17:11:18 +0000 (18:11 +0100)
TODO
public/javascripts/base_rules.js
public/javascripts/components/game.js
public/stylesheets/variant.sass

diff --git a/TODO b/TODO
index 92929ac..dafd7c0 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,2 +1,4 @@
-End of game a bit too verbose: should just say "Black win" ... + show PGN
 Styles must be improved (full width for smartphones, selectable text for PGN...)
+Tooltip text should fade (even when mouse stay on it, especially for small screens)
+Checkered stage 2: switch button at reserve position.
+If a played disconnect right after opponent sent a move, it might be never received: secure this
index de1a0d0..9a4ef91 100644 (file)
@@ -517,6 +517,32 @@ class ChessRules
                // No: if happen on last 1/2 move, could lead to forbidden moves, wrong evals
                return this.filterValid(potentialMoves);
        }
+       
+       // Stop at the first move found
+       atLeastOneMove(color)
+       {
+               const oppCol = this.getOppCol(color);
+               let [sizeX,sizeY] = VariantRules.size;
+               for (var i=0; i<sizeX; i++)
+               {
+                       for (var j=0; j<sizeY; j++)
+                       {
+                               if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) != oppCol)
+                               {
+                                       const moves = this.getPotentialMovesFrom([i,j]);
+                                       if (moves.length > 0)
+                                       {
+                                               for (let i=0; i<moves.length; i++)
+                                               {
+                                                       if (this.filterValid([moves[i]]).length > 0)
+                                                               return true;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               return false;
+       }
 
        // Check if pieces of color 'color' are attacking square x,y
        isAttacked(sq, color)
@@ -676,12 +702,15 @@ class ChessRules
                this.movesCount++;
        }
 
-       undo(move)
+       undo(move, ingame)
        {
                VariantRules.UndoOnBoard(this.board, move);
                this.epSquares.pop();
                this.movesCount--;
 
+               if (!!ingame)
+                       this.moves.pop();
+
                // Update king position, and reset stored/computed flags
                const c = this.getColor(move.start.x,move.start.y);
                if (this.getPiece(move.start.x,move.start.y) == VariantRules.KING)
@@ -709,8 +738,7 @@ class ChessRules
                        }
                }
 
-               // TODO: not required to generate ALL: just need one (callback ? hook ? ...)
-               if (this.getAllValidMoves(color).length > 0)
+               if (this.atLeastOneMove(color))
                {
                        // game not over
                        return "*";
@@ -779,14 +807,14 @@ class ChessRules
                moves1.sort( (a,b) => { return (color=="w" ? 1 : -1) * (b.eval - a.eval); });
 
                // TODO: show current analyzed move for depth 3, allow stopping eval (return moves1[0])
-//             for (let i=0; i<moves1.length; i++)
-//             {
-//                     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(oppCol, color, 2, -1000, 1000);
-//                     this.undo(moves1[i]);
-//             }
-//             moves1.sort( (a,b) => { return (color=="w" ? 1 : -1) * (b.eval - a.eval); });
+               for (let i=0; i<moves1.length; i++)
+               {
+                       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(oppCol, color, 2, -1000, 1000);
+                       this.undo(moves1[i]);
+               }
+               moves1.sort( (a,b) => { return (color=="w" ? 1 : -1) * (b.eval - a.eval); });
 
                let candidates = [0]; //indices of candidates moves
                for (let j=1; j<moves1.length && moves1[j].eval == moves1[0].eval; j++)
@@ -798,7 +826,7 @@ class ChessRules
 
        alphabeta(color, oppCol, depth, alpha, beta)
   {
-               let moves = this.getAllValidMoves(color);
+               const moves = this.getAllValidMoves(color);
                if (moves.length == 0)
                {
                        switch (this.checkGameEnd(color))
index 81ced5b..125aeea 100644 (file)
@@ -16,6 +16,7 @@ Vue.component('my-game', {
                        oppConnected: false,
                        seek: false,
                        fenStart: "",
+                       incheck: false,
                };
        },
        render(h) {
@@ -35,6 +36,8 @@ Vue.component('my-game', {
                                {
                                        on: {
                                                click: () => {
+                                                       if (this.mode == "human")
+                                                               return; //no newgame while playing
                                                        if (this.seek)
                                                                delete localStorage["newgame"]; //cancel game seek
                                                        else
@@ -55,7 +58,13 @@ Vue.component('my-game', {
                                [h('i', { 'class': { "material-icons": true } }, "accessibility")]),
                        h('button',
                                {
-                                       on: { click: () => this.newGame("computer") },
+                                       on: {
+                                               click: () => {
+                                                       if (this.mode == "human")
+                                                               return; //no newgame while playing
+                                                       this.newGame("computer");
+                                               }
+                                       },
                                        attrs: { "aria-label": 'New game VS computer' },
                                        'class': {
                                                "tooltip":true,
@@ -162,7 +171,9 @@ Vue.component('my-game', {
                                                                );
                                                        }
                                                        const lm = this.vr.lastMove;
-                                                       const highlight = !!lm && _.isMatch(lm.end, {x:ci,y:cj}); //&& _.isMatch(lm.start, {x:ci,y:cj})
+                                                       const highlight = !!lm && _.isMatch(lm.end, {x:ci,y:cj});
+                                                       const incheck = this.incheck
+                                                               && _.isEqual(this.vr.kingPos[this.vr.turn], [ci,cj]);
                                                        return h(
                                                                'div',
                                                                {
@@ -171,6 +182,7 @@ Vue.component('my-game', {
                                                                                'light-square': !highlight && (i+j)%2==0,
                                                                                'dark-square': !highlight && (i+j)%2==1,
                                                                                'highlight': highlight,
+                                                                               'incheck': incheck,
                                                                        },
                                                                        attrs: {
                                                                                id: this.getSquareId({x:ci,y:cj}),
@@ -483,6 +495,14 @@ Vue.component('my-game', {
                                this.oppConnected = true;
                                this.mycolor = color;
                                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.underCheck(lastMove, oppCol);
+                                       this.vr.play(lastMove, "ingame");
+                               }
                                delete localStorage["newgame"];
                                this.setStorage(); //in case of interruptions
                        }
@@ -610,6 +630,8 @@ Vue.component('my-game', {
                                this.animateMove(move);
                                return;
                        }
+                       const oppCol = this.vr.getOppCol(this.vr.turn);
+                       this.incheck = this.vr.underCheck(move, oppCol); //is opponent in check?
                        // Not programmatic, or animation is over
                        if (this.mode == "human" && this.vr.turn == this.mycolor)
                        {
index 786d54e..6a8da83 100644 (file)
@@ -7,10 +7,10 @@
   background-color: lightgrey
   font-weight: bold
 
-.playing
+.playing, button.playing:hover
   background-color: #ffcc99
 
-.seek
+.seek, button.seek:hover
   background-color: #cc99ff
 
 // https://stackoverflow.com/questions/5445491/height-equal-to-dynamic-width-css-fluid-layout
@@ -103,7 +103,10 @@ figure.diagram-container > figcaption
   background-color: #b58863
 
 .highlight
-  background-color: #00cc00
+  background-color: #00cc66
+
+.incheck
+  background-color: #cc3300
 
 .light-square-diag
   background-color: #e5e5ca