Add Checkered1 + fix last move highlights
[vchess.git] / client / src / components / BaseGame.vue
index 5ab02fa..572c80a 100644 (file)
@@ -205,24 +205,28 @@ export default {
       this.vr = new V(game.fenStart);
       const parsedFen = V.ParseFen(game.fenStart);
       const firstMoveColor = parsedFen.turn;
-      this.firstMoveNumber = Math.floor(parsedFen.movesCount / 2);
+      this.firstMoveNumber = Math.floor(parsedFen.movesCount / 2) + 1;
       let L = this.moves.length;
-      this.moves.forEach(move => {
+      this.moves.forEach((move,idx) => {
         // Strategy working also for multi-moves:
         if (!Array.isArray(move)) move = [move];
-        move.forEach((m,idx) => {
-          m.index = this.vr.movesCount;
+        const Lm = move.length;
+        move.forEach((m,idxM) => {
           m.notation = this.vr.getNotation(m);
           m.unambiguous = V.GetUnambiguousNotation(m);
           this.vr.play(m);
-          if (idx < L - 1 && this.vr.getCheckSquares(this.vr.turn).length > 0)
-            m.notation += "+";
+          const checkSquares = this.vr.getCheckSquares();
+          if (checkSquares.length > 0) m.notation += "+";
+          if (idx == L - 1 && idxM == Lm - 1) {
+            this.incheck = checkSquares;
+            const score = this.vr.getCurrentScore();
+            if (["1-0", "0-1"].includes(score)) m.notation += "#";
+          }
         });
       });
       if (firstMoveColor == "b") {
         // 'start' & 'end' is required for Board component
         this.moves.unshift({
-          index: parsedFen.movesCount,
           notation: "...",
           unambiguous: "...",
           start: { x: -1, y: -1 },
@@ -231,25 +235,13 @@ export default {
         });
         L++;
       }
-      this.positionCursorTo(this.moves.length - 1);
-      this.incheck = this.vr.getCheckSquares(this.vr.turn);
-      const score = this.vr.getCurrentScore();
-      if (L > 0 && this.moves[L - 1].notation != "...") {
-        if (["1-0","0-1"].includes(score)) this.moves[L - 1].notation += "#";
-        else if (this.incheck.length > 0) this.moves[L - 1].notation += "+";
-      }
+      this.positionCursorTo(L - 1);
     },
     positionCursorTo: function(index) {
       this.cursor = index;
-      // Caution: last move in moves array might be a multi-move
-      if (index >= 0) {
-        if (Array.isArray(this.moves[index])) {
-          const L = this.moves[index].length;
-          this.lastMove = this.moves[index][L - 1];
-        } else {
-          this.lastMove = this.moves[index];
-        }
-      } else this.lastMove = null;
+      // Note: last move in moves array might be a multi-move
+      if (index >= 0) this.lastMove = this.moves[index];
+      else this.lastMove = null;
     },
     analyzePosition: function() {
       let newUrl =
@@ -279,23 +271,23 @@ export default {
       pgn += '[Black "' + this.game.players[1].name + '"]\n';
       pgn += '[Fen "' + this.game.fenStart + '"]\n';
       pgn += '[Result "' + this.game.score + '"]\n';
-      if (!!this.game.id) {
-        pgn += '[Cadence "' + this.game.cadence + '"]\n';
+      if (!!this.game.id)
         pgn += '[Url "' + params.serverUrl + '/game/' + this.game.id + '"]\n';
-      }
+      if (!!this.game.cadence)
+        pgn += '[Cadence "' + this.game.cadence + '"]\n';
       pgn += '\n';
       for (let i = 0; i < this.moves.length; i += 2) {
         if (i > 0) pgn += " ";
         // Adjust dots notation for a better display:
         let fullNotation = getFullNotation(this.moves[i]);
         if (fullNotation == "...") fullNotation = "..";
-        pgn += (this.moves[i].index / 2 + 1) + "." + fullNotation;
+        pgn += (i / 2 + this.firstMoveNumber) + "." + fullNotation;
         if (i+1 < this.moves.length)
           pgn += " " + getFullNotation(this.moves[i+1]);
       }
       pgn += "\n\n";
       for (let i = 0; i < this.moves.length; i += 2) {
-        const moveNumber = this.moves[i].index / 2 + 1;
+        const moveNumber = i / 2 + this.firstMoveNumber;
         // Skip "dots move", useless for machine reading:
         if (this.moves[i].notation != "...") {
           pgn += moveNumber + ".w " +
@@ -380,10 +372,15 @@ export default {
     // For Analyse mode:
     emitFenIfAnalyze: function() {
       if (this.game.mode == "analyze") {
-        this.$emit(
-          "fenchange",
-          !!this.lastMove ? this.lastMove.fen : this.game.fenStart
-        );
+        let fen = this.game.fenStart;
+        if (!!this.lastMove) {
+          if (Array.isArray(this.lastMove)) {
+            const L = this.lastMove.length;
+            fen = this.lastMove[L-1].fen;
+          }
+          else fen = this.lastMove.fen;
+        }
+        this.$emit("fenchange", fen);
       }
     },
     clickSquare: function(square) {
@@ -395,6 +392,8 @@ export default {
     play: function(move, received, light, noemit) {
       // Freeze while choices are shown:
       if (this.$refs["board"].choices.length > 0) return;
+      // The board may show some the possible moves: (TODO: bad solution)
+      this.$refs["board"].resetCurrentAttempt();
       if (!!noemit) {
         if (this.inPlay) {
           // Received moves in observed games can arrive too fast:
@@ -408,8 +407,17 @@ export default {
         smove.notation = this.vr.getNotation(smove);
         smove.unambiguous = V.GetUnambiguousNotation(smove);
         this.vr.play(smove);
-        this.lastMove = smove;
+        if (!!this.lastMove) {
+          if (!Array.isArray(this.lastMove))
+            this.lastMove = [this.lastMove, smove];
+          else this.lastMove.push(smove);
+        }
+        // Is opponent (or me) in check?
+        this.incheck = this.vr.getCheckSquares();
+        if (this.incheck.length > 0) smove.notation += "+";
         if (!this.inMultimove) {
+          // First sub-move:
+          this.lastMove = smove;
           // Condition is "!navigate" but we mean "!this.autoplay"
           if (!navigate) {
             if (this.cursor < this.moves.length - 1)
@@ -423,8 +431,7 @@ export default {
           const L = this.moves.length;
           if (!Array.isArray(this.moves[L-1]))
             this.$set(this.moves, L-1, [this.moves[L-1], smove]);
-          else
-            this.$set(this.moves, L-1, this.moves.concat([smove]));
+          else this.moves[L-1].push(smove);
         }
       };
       const playMove = () => {
@@ -438,7 +445,9 @@ export default {
         const initurn = this.vr.turn;
         (function executeMove() {
           const smove = move[moveIdx++];
-          if (animate) {
+          // NOTE: condition "smove.start.x >= 0" required for Dynamo,
+          // because second move may be empty.
+          if (animate && smove.start.x >= 0) {
             self.animateMove(smove, () => {
               playSubmove(smove);
               if (moveIdx < move.length)
@@ -455,8 +464,13 @@ export default {
       const computeScore = () => {
         const score = this.vr.getCurrentScore();
         if (!navigate) {
-          if (["1-0","0-1"].includes(score)) this.lastMove.notation += "#";
-          else if (this.incheck.length > 0) this.lastMove.notation += "+";
+          if (["1-0","0-1"].includes(score)) {
+            if (Array.isArray(this.lastMove)) {
+              const L = this.lastMove.length;
+              this.lastMove[L - 1].notation += "#";
+            }
+            else this.lastMove.notation += "#";
+          }
         }
         if (score != "*" && this.game.mode == "analyze") {
           const message = getScoreMessage(score);
@@ -471,8 +485,6 @@ export default {
           if (!smove.fen)
             // NOTE: only FEN of last sub-move is required (=> setting it here)
             smove.fen = this.vr.getFen();
-          // Is opponent in check?
-          this.incheck = this.vr.getCheckSquares(this.vr.turn);
           this.emitFenIfAnalyze();
           this.inMultimove = false;
           this.score = computeScore();
@@ -502,8 +514,8 @@ export default {
           if (!Array.isArray(move)) move = [move];
           for (let i=0; i < move.length; i++) this.vr.play(move[i]);
           if (!light) {
-            this.lastMove = move[move.length-1];
-            this.incheck = this.vr.getCheckSquares(this.vr.turn);
+            this.lastMove = move;
+            this.incheck = this.vr.getCheckSquares();
             this.score = computeScore();
             this.emitFenIfAnalyze();
           }
@@ -530,11 +542,9 @@ export default {
       const L = this.moves.length;
       let move = this.moves[L-1];
       if (!Array.isArray(move)) move = [move];
-      for (let i=move.length -1; i >= 0; i--) this.vr.undo(move[i]);
+      for (let i = move.length - 1; i >= 0; i--) this.vr.undo(move[i]);
       this.moves.pop();
       this.cursor--;
-      // The board may still show the possible moves: (TODO: bad solution)
-      this.$refs["board"].resetCurrentAttempt();
       this.inMultimove = false;
     },
     cancelLastMove: function() {
@@ -546,9 +556,10 @@ export default {
     undo: function(move, light) {
       // Freeze while choices are shown:
       if (this.$refs["board"].choices.length > 0) return;
+      this.$refs["board"].resetCurrentAttempt();
       if (this.inMultimove) {
         this.cancelCurrentMultimove();
-        this.incheck = this.vr.getCheckSquares(this.vr.turn);
+        this.incheck = this.vr.getCheckSquares();
       } else {
         if (!move) {
           const minCursor =
@@ -558,17 +569,19 @@ export default {
           if (this.cursor < minCursor) return; //no more moves
           move = this.moves[this.cursor];
         }
+        this.$refs["board"].resetCurrentAttempt();
         undoMove(move, this.vr);
         if (light) this.cursor--;
         else {
           this.positionCursorTo(this.cursor - 1);
-          this.incheck = this.vr.getCheckSquares(this.vr.turn);
+          this.incheck = this.vr.getCheckSquares();
           this.emitFenIfAnalyze();
         }
       }
     },
     gotoMove: function(index) {
       if (this.$refs["board"].choices.length > 0) return;
+      this.$refs["board"].resetCurrentAttempt();
       if (this.inMultimove) this.cancelCurrentMultimove();
       if (index == this.cursor) return;
       if (index < this.cursor) {
@@ -582,11 +595,12 @@ export default {
       }
       // NOTE: next line also re-assign cursor, but it's very light
       this.positionCursorTo(index);
-      this.incheck = this.vr.getCheckSquares(this.vr.turn);
+      this.incheck = this.vr.getCheckSquares();
       this.emitFenIfAnalyze();
     },
     gotoBegin: function() {
       if (this.$refs["board"].choices.length > 0) return;
+      this.$refs["board"].resetCurrentAttempt();
       if (this.inMultimove) this.cancelCurrentMultimove();
       const minCursor =
         this.moves.length > 0 && this.moves[0].notation == "..."
@@ -594,11 +608,12 @@ export default {
           : 0;
       while (this.cursor >= minCursor) this.undo(null, null, "light");
       this.lastMove = (minCursor == 1 ? this.moves[0] : null);
-      this.incheck = this.vr.getCheckSquares(this.vr.turn);
+      this.incheck = this.vr.getCheckSquares();
       this.emitFenIfAnalyze();
     },
     gotoEnd: function() {
       if (this.$refs["board"].choices.length > 0) return;
+      this.$refs["board"].resetCurrentAttempt();
       if (this.cursor == this.moves.length - 1) return;
       this.gotoMove(this.moves.length - 1);
       this.emitFenIfAnalyze();