Highlight king in red if undercheck + some improvements
[vchess.git] / public / javascripts / base_rules.js
index 576bdd9..9a4ef91 100644 (file)
@@ -47,9 +47,9 @@ class ChessRules
        // INITIALIZATION
 
        // fen = "position flags epSquare movesCount"
-       constructor(fen)
+       constructor(fen, moves)
        {
-               this.moves = [];
+               this.moves = moves;
                // Use fen string to initialize variables, flags and board
                this.initVariables(fen);
                this.flags = VariantRules.GetFlags(fen);
@@ -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)
@@ -665,20 +691,26 @@ class ChessRules
                move.flags = JSON.stringify(this.flags); //TODO: less costly
                this.updateVariables(move);
 
+               if (!!ingame)
+               {
+                       move.notation = this.getNotation(move);
+                       this.moves.push(move);
+               }
+
                this.epSquares.push( this.getEpSquare(move) );
                VariantRules.PlayOnBoard(this.board, move);
                this.movesCount++;
-
-               if (!!ingame)
-                       this.moves.push(move);
        }
 
-       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)
@@ -706,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 "*";
@@ -776,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++)
@@ -795,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))
@@ -1007,4 +1038,27 @@ class ChessRules
                        return piece.toUpperCase() + (move.vanish.length > 1 ? "x" : "") + finalSquare;
                }
        }
+
+       // The score is already computed when calling this function
+       getPGN(mycolor, score, fenStart)
+       {
+               let pgn = "";
+               pgn += '[Site "vchess.club"]<br>';
+               const d = new Date();
+               pgn += '[Date "' + d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate() + '"]<br>';
+               pgn += '[White "' + (mycolor=='w'?'Myself':'Anonymous') + '"]<br>';
+               pgn += '[Black "' + (mycolor=='b'?'Myself':'Anonymous') + '"]<br>';
+               pgn += '[Fen "' + fenStart + '"]<br>';
+               pgn += '[Result "' + score + '"]<br><br>';
+
+               for (let i=0; i<this.moves.length; i++)
+               {
+                       if (i % 2 == 0)
+                               pgn += ((i/2)+1) + ".";
+                       pgn += this.moves[i].notation + " ";
+               }
+
+               pgn += score;
+               return pgn;
+       }
 }