Draft Hiddenqueen, Grasshopper and Knightmate chess (rules unwritten)
[vchess.git] / client / src / views / Rules.vue
index a3331d7..556ea86 100644 (file)
@@ -3,61 +3,99 @@ main
   .row
     .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
       .button-group
-        button(@click="clickReadRules") Rules
-        button(v-show="!gameInProgress" @click="() => startGame('auto')")
-          | Sample game
-        button(v-show="!gameInProgress" @click="() => startGame('versus')")
-          | Practice
-        button(v-show="gameInProgress" @click="() => stopGame()")
-          | Stop game
-        button(v-if="display=='rules' && gameInfo.vname!='Dark'"
-            @click="gotoAnalyze")
-          | {{ st.tr["Analyze"] }}
-      .section-content(v-show="display=='rules'" v-html="content")
-  ComputerGame(v-show="display=='computer'" :game-info="gameInfo"
-    @game-over="stopGame" @game-stopped="gameStopped")
+        button(@click="clickReadRules()") {{ st.tr["Rules"] }}
+        button(
+          v-show="!gameInProgress"
+          @click="startGame('auto')"
+        )
+          | {{ st.tr["Example game"] }}
+        button(
+          v-show="!gameInProgress"
+          @click="startGame('versus')"
+        )
+          | {{ st.tr["Practice"] }}
+        button(
+          v-show="gameInProgress"
+          @click="stopGame()"
+        )
+          | {{ st.tr["Stop game"] }}
+        button(
+          v-if="showAnalyzeBtn"
+          @click="gotoAnalyze()"
+        )
+          | {{ st.tr["Analysis mode"] }}
+  .row
+    .col-sm-12.col-md-8.col-md-offset-2.col-lg-6.col-lg-offset-3
+      div(
+        v-show="display=='rules'"
+        v-html="content"
+      )
+  ComputerGame(
+    ref="compgame"
+    v-show="display=='computer'"
+    :game-info="gameInfo"
+    @game-stopped="gameStopped"
+  )
 </template>
 
 <script>
 import ComputerGame from "@/components/ComputerGame.vue";
 import { store } from "@/store";
 import { getDiagram } from "@/utils/printDiagram";
-
+import { CompgameStorage } from "@/utils/compgameStorage";
 export default {
-  name: 'my-rules',
+  name: "my-rules",
   components: {
-    ComputerGame,
+    ComputerGame
   },
   data: function() {
     return {
       st: store.state,
-      content: "",
       display: "rules",
       gameInProgress: false,
       // variables passed to ComputerGame:
       gameInfo: {
-        vname: "_unknown",
+        vname: "",
         mode: "versus",
-        fen: "",
-        score: "*",
-      }
+      },
+      V: null,
     };
   },
   watch: {
-    "$route": function(newRoute) {
-      this.tryChangeVariant(newRoute.params["vname"]);
-    },
+    $route: function(newRoute) {
+      this.re_setVariant(newRoute.params["vname"]);
+    }
   },
-  created: async function() {
+  created: function() {
     // NOTE: variant cannot be set before store is initialized
-    this.tryChangeVariant(this.$route.params["vname"]);
+    this.re_setVariant(this.$route.params["vname"]);
+  },
+  computed: {
+    showAnalyzeBtn: function() {
+      return this.V && this.V.CanAnalyze;
+    },
+    content: function() {
+      if (!this.gameInfo.vname) return ""; //variant not set yet
+      // (AJAX) Request to get rules content (plain text, HTML)
+      return (
+        require("raw-loader!@/translations/rules/" +
+          this.gameInfo.vname +
+          "/" +
+          this.st.lang +
+          ".pug")
+          // Next two lines fix a weird issue after last update (2019-11)
+          .replace(/\\n/g, " ")
+          .replace(/\\"/g, '"')
+          .replace('module.exports = "', "")
+          .replace(/"$/, "")
+          .replace(/(fen:)([^:]*):/g, this.replaceByDiag)
+      );
+    }
   },
   methods: {
     clickReadRules: function() {
-      if (this.display != "rules")
-        this.display = "rules";
-      else if (this.gameInProgress)
-        this.display = "computer";
+      if (this.display != "rules") this.display = "rules";
+      else if (this.gameInProgress) this.display = "computer";
     },
     parseFen(fen) {
       const fenParts = fen.split(" ");
@@ -65,65 +103,65 @@ export default {
         position: fenParts[0],
         marks: fenParts[1],
         orientation: fenParts[2],
-        shadow: fenParts[3],
+        shadow: fenParts[3]
       };
     },
-    tryChangeVariant: async function(vname) {
-      if (!vname || vname == "_unknown")
-        return;
-      this.gameInfo.vname = vname;
-      const vModule = await import("@/variants/" + vname + ".js");
-      window.V = vModule.VariantRules;
-      // Method to replace diagrams in loaded HTML
-      const replaceByDiag = (match, p1, p2) => {
-        const args = this.parseFen(p2);
-        return getDiagram(args);
-      };
-      // (AJAX) Request to get rules content (plain text, HTML)
-      this.content =
-        require("raw-loader!@/translations/rules/" + vname + "/" + this.st.lang + ".pug")
-        // Next two lines fix a weird issue after last update (2019-11)
-        .replace(/\\[n"]/g, " ")
-        .replace('module.exports = "', '').replace(/"$/, "")
-        .replace(/(fen:)([^:]*):/g, replaceByDiag);
+    // Method to replace diagrams in loaded HTML
+    replaceByDiag: function(match, p1, p2) {
+      const args = this.parseFen(p2);
+      return getDiagram(args);
+    },
+    re_setVariant: async function(vname) {
+      await import("@/variants/" + vname + ".js")
+      .then((vModule) => {
+        this.V = window.V = vModule.VariantRules;
+        this.gameInfo.vname = vname;
+      })
+      .catch((err) => {
+        // Soon after component creation, st.tr might be uninitialized.
+        // Set a timeout to let a chance for the message to show translated.
+        const text = "Mispelled variant name";
+        setTimeout(() => {
+          alert(this.st.tr[text] || text);
+          this.$router.replace("/variants");
+        }, 500);
+      });
     },
     startGame: function(mode) {
-      if (this.gameInProgress)
-        return;
+      if (this.gameInProgress) return;
       this.gameInProgress = true;
       this.display = "computer";
       this.gameInfo.mode = mode;
-      this.gameInfo.score = "*";
-      this.gameInfo.fen = V.GenRandInitFen();
+      if (this.gameInfo.mode == "versus") {
+        CompgameStorage.get(this.gameInfo.vname, (game) => {
+          // NOTE: game might be null
+          this.$refs["compgame"].launchGame(game);
+        });
+      } else {
+        this.$refs["compgame"].launchGame();
+      }
     },
-    // user is willing to stop the game:
-    stopGame: function(score) {
-      this.gameInfo.score = score || "?";
+    // user wants to stop the game:
+    stopGame: function() {
+      this.$refs["compgame"].gameOver("?", "Undetermined result");
     },
     // The game is effectively stopped:
     gameStopped: function() {
       this.gameInProgress = false;
+      if (this.gameInfo.mode == "versus")
+        CompgameStorage.remove(this.gameInfo.vname);
     },
     gotoAnalyze: function() {
-      this.$router.push("/analyze/" + this.gameInfo.vname
-        + "/?fen=" + V.GenRandInitFen());
-    },
-  },
+      this.$router.push(
+        "/analyse/" + this.gameInfo.vname + "/?fen=" + V.GenRandInitFen()
+      );
+    }
+  }
 };
 </script>
 
-<style lang="sass" scoped>
-//.section-content
-//  *
-//    margin-left: auto
-//    margin-right: auto
-//    max-width: 767px
-//  figure.diagram-container
-//    max-width: 1000px
-//  @media screen and (max-width: 767px)
-//    max-width: 100%
-//    padding: 0 5px
-
+<!-- NOTE: not scoped here, because HTML is injected (TODO) -->
+<style lang="sass">
 .warn
   padding: 3px
   color: red
@@ -164,6 +202,12 @@ p.boxed
   background-color: #FFCC66
   padding: 5px
 
+.bigfont
+  font-size: 1.2em
+
+.bold
+  font-weight: bold
+
 .stageDelimiter
   color: purple
 
@@ -188,48 +232,4 @@ ul:not(.browser-default)
 
 ul:not(.browser-default) > li
   list-style-type: disc
-
-.light-square-diag
-  background-color: #e5e5ca
-
-.dark-square-diag
-  background-color: #6f8f57
-
-// TODO: following is duplicated (Board.vue)
-div.board
-  float: left
-  height: 0
-  display: inline-block
-  position: relative
-
-div.board8
-  width: 12.5%
-  padding-bottom: 12.5%
-
-div.board10
-  width: 10%
-  padding-bottom: 10%
-
-div.board11
-  width: 9.09%
-  padding-bottom: 9.1%
-
-img.piece
-  width: 100%
-
-img.piece, img.mark-square
-  max-width: 100%
-  height: auto
-  display: block
-
-img.mark-square
-  opacity: 0.6
-  width: 76%
-  position: absolute
-  top: 12%
-  left: 12%
-  opacity: .7
-
-.in-shadow
-  filter: brightness(50%)
 </style>