Add debug trace for Hiddenqueen
[vchess.git] / client / src / components / ComputerGame.vue
index 941016b..605b3b1 100644 (file)
@@ -1,20 +1,25 @@
 <template lang="pug">
-BaseGame(:game="game" :vr="vr" ref="basegame"
-  @newmove="processMove" @gameover="gameOver")
+BaseGame(
+  ref="basegame"
+  :game="game"
+  @newmove="processMove"
+)
 </template>
 
 <script>
 import BaseGame from "@/components/BaseGame.vue";
 import { store } from "@/store";
+import { CompgameStorage } from "@/utils/compgameStorage";
+import { getScoreMessage } from "@/utils/scoring";
+import { playMove, getFilteredMove } from "@/utils/playUndo";
 import Worker from "worker-loader!@/playCompMove";
-
 export default {
   name: "my-computer-game",
   components: {
-    BaseGame,
+    BaseGame
   },
   // gameInfo: fen + mode + vname
-  // mode: "auto" (game comp vs comp), "versus" (normal) or "analyze"
+  // mode: "auto" (game comp vs comp) or "versus" (normal)
   props: ["gameInfo"],
   data: function() {
     return {
@@ -24,110 +29,106 @@ export default {
       // Web worker to play computer moves without freezing interface:
       timeStart: undefined, //time when computer starts thinking
       compThink: false, //avoid asking a new move while one is being searched
-      compWorker: null,
+      compWorker: null
     };
   },
-  watch: {
-    "gameInfo.fen": function() {
-      this.launchGame();
-    },
-    "gameInfo.score": function(newScore) {
-      if (newScore != "*")
-      {
-        this.game.score = newScore; //user action
-        this.game.mode = "analyze";
-        if (!this.compThink)
-          this.$emit("game-stopped"); //otherwise wait for comp
-      }
-    },
-  },
-  // Modal end of game, and then sub-components
   created: function() {
     // Computer moves web worker logic:
     this.compWorker = new Worker();
     this.compWorker.onmessage = e => {
       let compMove = e.data;
-      if (!compMove)
-      {
-        this.compThink = false;
-        this.$emit("game-stopped"); //no more moves: mate or stalemate
-        return; //after game ends, no more moves, nothing to do
-      }
-      if (!Array.isArray(compMove))
-        compMove = [compMove]; //to deal with MarseilleRules
       // Small delay for the bot to appear "more human"
-      const delay = Math.max(500-(Date.now()-this.timeStart), 0);
+      const minDelay = this.gameInfo.mode == "versus" ? 500 : 1000;
+      const delay = Math.max(minDelay - (Date.now() - this.timeStart), 0);
+      let self = this;
       setTimeout(() => {
-        if (this.currentUrl != document.location.href)
-          return; //page change
-        // NOTE: Dark and 2-moves are incompatible
-        const animate = (this.gameInfo.vname != "Dark");
-        const animDelay = (animate ? 250 : 0);
-        let moveIdx = 0;
-        let self = this;
-        (function executeMove() {
-          self.$refs.basegame.play(compMove[moveIdx++], animate);
-          if (moveIdx >= compMove.length)
-          {
+        if (this.currentUrl != document.location.href) return; //page change
+        self.$refs["basegame"].play(compMove, "received");
+        const animationLength =
+          // 250 = length of animation, 500 = delay between sub-moves
+          // TODO: a callback would be cleaner.
+          250 + (Array.isArray(compMove) ? (compMove.length - 1) * 750 : 0);
+        setTimeout(
+          () => {
             self.compThink = false;
-            if (self.game.score != "*") //user action
-              self.$emit("game-stopped");
-          }
-          else
-            setTimeout(executeMove, 500 + animDelay);
-        })();
+            self.processMove(compMove);
+          },
+          animationLength
+        );
       }, delay);
-    }
-    if (!!this.gameInfo.fen)
-      this.launchGame();
+    };
   },
-  // dans variant.js (plutôt room.js) conn gère aussi les challenges
-  // et les chats dans chat.js. Puis en webRTC, repenser tout ça.
   methods: {
-    launchGame: async function() {
-      const vModule = await import("@/variants/" + this.gameInfo.vname + ".js");
-      window.V = vModule.VariantRules;
-      this.compWorker.postMessage(["scripts",this.gameInfo.vname]);
-      this.compWorker.postMessage(["init",this.gameInfo.fen]);
-      this.vr = new V(this.gameInfo.fen);
-      const mycolor = (Math.random() < 0.5 ? "w" : "b");
-      let players = [{name:"Myself"},{name:"Computer"}];
-      if (mycolor == "b")
-        players = players.reverse();
+    launchGame: function(game) {
+      this.compWorker.postMessage(["scripts", this.gameInfo.vname]);
+      if (!game) {
+        game = {
+          vname: this.gameInfo.vname,
+          fenStart: V.GenRandInitFen(this.st.settings.randomness),
+          moves: []
+        };
+        game.fen = game.fenStart;
+        if (this.gameInfo.mode == "versus") CompgameStorage.add(game);
+      }
+
+// TODO: debug Hiddenqueen
+//game.fen = "rbnqbknr/pppptppp/8/8/8/8/TPPPPPPP/RBNQBKNR w 0 ahah -";
+//game.fenStart = "rbnqbknr/pppptppp/8/8/8/8/TPPPPPPP/RBNQBKNR w 0 ahah -";
+//game.mycolor = 'w';
+
+      if (!game.mycolor) game.mycolor = (Math.random() < 0.5 ? "w" : "b");
+      this.compWorker.postMessage(["init", game.fen]);
+      this.vr = new V(game.fen);
+      game.players = [{ name: "Computer" }, { name: "Computer" }];
+      if (this.gameInfo.mode == "versus")
+        game.players[game.mycolor == 'w' ? 0 : 1] = { name: "Myself" };
+      game.score = "*"; //finished games are removed
+      game.mode = this.gameInfo.mode;
       this.currentUrl = document.location.href; //to avoid playing outside page
-      // NOTE: fen and fenStart are redundant in game object
-      this.game = Object.assign({},
-        this.gameInfo,
-        {
-          fenStart: this.gameInfo.fen,
-          players: players,
-          mycolor: mycolor,
-          score: "*",
-        });
-      this.compWorker.postMessage(["init",this.gameInfo.fen]);
-      if (mycolor != "w" || this.gameInfo.mode == "auto")
+      this.game = game;
+      this.$refs["basegame"].re_setVariables(game);
+      this.compWorker.postMessage(["init", game.fen]);
+      if (this.gameInfo.mode == "auto" || game.mycolor != this.vr.turn)
         this.playComputerMove();
     },
+    // NOTE: a "goto" action could lead to an error when comp is thinking,
+    // but it's OK because from the user viewpoint the game just stops.
     playComputerMove: function() {
       this.timeStart = Date.now();
       this.compThink = true;
       this.compWorker.postMessage(["askmove"]);
     },
-    processMove: function(move) {
+    processMove: function(move, scoreObj) {
+      playMove(move, this.vr);
+      // Maybe the user stopped the game:
+      if (this.game.score != "*") {
+        this.$emit("game-stopped");
+        return;
+      }
+      // This move could have ended the game
+      if (!scoreObj) scoreObj = { score: this.vr.getCurrentScore() };
+      if (scoreObj.score != "*") {
+        this.gameOver(scoreObj.score);
+        return;
+      }
       // Send the move to web worker (including his own moves)
-      this.compWorker.postMessage(["newmove",move]);
-      // subTurn condition for Marseille (and Avalanche) rules
-      if ((!this.vr.subTurn || this.vr.subTurn <= 1)
-        && (this.gameInfo.mode == "auto" || this.vr.turn != this.game.mycolor))
-      {
+      this.compWorker.postMessage(["newmove", move]);
+      if (this.gameInfo.mode == "auto" || this.vr.turn != this.game.mycolor)
         this.playComputerMove();
+      // Finally, update storage:
+      if (this.gameInfo.mode == "versus") {
+        CompgameStorage.update(this.gameInfo.vname, {
+          move: getFilteredMove(move),
+          fen: this.vr.getFen()
+        });
       }
     },
     gameOver: function(score) {
       this.game.score = score;
-      this.game.mode = "analyze";
-      this.$emit("game-over", score); //bubble up to Rules.vue
-    },
-  },
+      this.game.scoreMsg = getScoreMessage(score);
+      // If comp is thinking, let him finish:
+      if (!this.compThink) this.$emit("game-stopped");
+    }
+  }
 };
 </script>