From 4ec83d3789a69429297710413bf640be51d10e41 Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Sun, 22 Mar 2020 13:10:31 +0100
Subject: [PATCH] Schess: show 'nothing' instead of the moving piece when no
 pocket piece is used

---
 client/public/images/pieces/Schess/oo.svg |  1 +
 client/public/index.html                  |  2 +
 client/src/App.vue                        |  2 +
 client/src/translations/about/en.pug      |  2 +-
 client/src/translations/about/es.pug      |  2 +-
 client/src/translations/about/fr.pug      |  2 +-
 client/src/variants/Schess.js             | 81 +++++++++++++++++------
 7 files changed, 69 insertions(+), 23 deletions(-)
 create mode 100644 client/public/images/pieces/Schess/oo.svg

diff --git a/client/public/images/pieces/Schess/oo.svg b/client/public/images/pieces/Schess/oo.svg
new file mode 100644
index 00000000..08ec9068
--- /dev/null
+++ b/client/public/images/pieces/Schess/oo.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="1" height="1"/>
\ No newline at end of file
diff --git a/client/public/index.html b/client/public/index.html
index 9f03d48d..f93aa0e3 100644
--- a/client/public/index.html
+++ b/client/public/index.html
@@ -4,6 +4,8 @@
     <meta charset="utf-8">
     <title>vchess - club</title>
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="description" content="Play chess variants online">
+    <meta name="robots" content="index,nofollow">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
     <!-- <link rel="stylesheet"
diff --git a/client/src/App.vue b/client/src/App.vue
index 25ec25eb..77059bba 100644
--- a/client/src/App.vue
+++ b/client/src/App.vue
@@ -274,6 +274,8 @@ footer
     border: none
 
 @media screen and (max-width: 420px)
+  .container
+    min-height: calc(100vh - 55px)
   footer
     height: 55px
     display: block
diff --git a/client/src/translations/about/en.pug b/client/src/translations/about/en.pug
index d2d3ecdd..c6b32fba 100644
--- a/client/src/translations/about/en.pug
+++ b/client/src/translations/about/en.pug
@@ -39,7 +39,7 @@ p.
   testing, giving ideas, motivating me to achieve this project.
   Thanks to you all! :-)
 
-h3 Links
+h3 Related links
 
 #links
   a(href="https://greenchess.net/") greenchess.net
diff --git a/client/src/translations/about/es.pug b/client/src/translations/about/es.pug
index 0a628864..eb53940c 100644
--- a/client/src/translations/about/es.pug
+++ b/client/src/translations/about/es.pug
@@ -36,7 +36,7 @@ p
   | completar el proyecto.
   | ¡Gracias a todos!
 
-h3 Enlaces
+h3 Enlaces relacionados
 
 #links
   a(href="https://greenchess.net/") greenchess.net
diff --git a/client/src/translations/about/fr.pug b/client/src/translations/about/fr.pug
index 7f673574..3197837c 100644
--- a/client/src/translations/about/fr.pug
+++ b/client/src/translations/about/fr.pug
@@ -37,7 +37,7 @@ p.
   motivant pour achever le projet.
   Merci à tou-te-s !
 
-h3 Liens
+h3 Liens connexes
 
 #links
   a(href="https://greenchess.net/") greenchess.net
diff --git a/client/src/variants/Schess.js b/client/src/variants/Schess.js
index ebc2c7c2..d2e35288 100644
--- a/client/src/variants/Schess.js
+++ b/client/src/variants/Schess.js
@@ -20,12 +20,16 @@ export class SchessRules extends ChessRules {
     return 'e';
   }
 
+  static get NOTHING() {
+    return 'o';
+  }
+
   static get PIECES() {
     return ChessRules.PIECES.concat([V.HAWK, V.ELEPHANT]);
   }
 
   getPpath(b) {
-    if ([V.HAWK, V.ELEPHANT].includes(b[1])) return "Schess/" + b;
+    if ([V.HAWK, V.ELEPHANT, V.NOTHING].includes(b[1])) return "Schess/" + b;
     return b;
   }
 
@@ -141,12 +145,22 @@ export class SchessRules extends ChessRules {
       default:
         moves = super.getPotentialMovesFrom([x, y]);
     }
+    // For moves presentation when choices:
+    const unshiftNothing = (m) => {
+      const a = m.appear[0];
+      m.appear.unshift(new PiPo({
+        p: V.NOTHING,
+        c: 'o',
+        x: a.x,
+        y: a.y
+      }));
+    };
     // Post-processing: add choices for hawk and elephant,
     // except for moves letting the king under check.
     const color = this.turn;
     if (Object.values(this.pocket[color]).some(v => v > 0)) {
       const firstRank = (color == "w" ? 7 : 0);
-      let pocketMoves = [];
+      let validMoves = [];
       moves.forEach(m => {
         let inCheckAfter = false;
         this.play(m);
@@ -155,16 +169,18 @@ export class SchessRules extends ChessRules {
         if (!inCheckAfter) {
           for (let pp of ['h', 'e']) {
             if (this.pocket[color][pp] > 0) {
+              let shift = (m.appear[0].p == V.NOTHING ? 1 : 0);
               if (
                 m.start.x == firstRank &&
                 this.pieceFlags[color][m.start.y] &&
                 (
-                  m.appear.length == 1 ||
+                  m.appear.length == shift+1 ||
                   // Special castle case: is initial king square free?
-                  ![m.appear[0].y, m.appear[1].y].includes(m.vanish[0].y)
+                  ![m.appear[shift].y, m.appear[shift+1].y].includes(m.vanish[0].y)
                 )
               ) {
                 let pMove = JSON.parse(JSON.stringify(m));
+                if (shift == 1) pMove.appear.shift();
                 // NOTE: unshift instead of push, for choices presentation
                 pMove.appear.unshift(new PiPo({
                   p: pp,
@@ -172,28 +188,34 @@ export class SchessRules extends ChessRules {
                   x: x,
                   y: y
                 }));
-                pocketMoves.push(pMove);
+                validMoves.push(pMove);
+                if (shift == 0) unshiftNothing(m);
               }
+              shift = (m.appear[0].p == V.NOTHING ? 1 : 0);
               if (
-                m.appear.length == 2 &&
-                ![m.appear[0].y, m.appear[1].y].includes(m.vanish[1].y)
+                m.appear.length >= 2 &&
+                m.vanish.length == 2 &&
+                ![m.appear[shift].y, m.appear[shift+1].y].includes(m.vanish[1].y)
               ) {
                 // Special castle case: rook flag was necessarily on
                 let pMove = JSON.parse(JSON.stringify(m));
+                if (shift == 1) pMove.appear.shift();
                 pMove.appear.unshift(new PiPo({
                   p: pp,
                   c: color,
                   x: m.vanish[1].x,
                   y: m.vanish[1].y
                 }));
-                pocketMoves.push(pMove);
+                validMoves.push(pMove);
+                if (shift == 0) unshiftNothing(m);
               }
             }
           }
+          // Unshift, to show the empty square on the left:
+          validMoves.unshift(m);
         }
       });
-      // NOTE: the order matter, for presentation on screen
-      moves = moves.concat(pocketMoves);
+      moves = validMoves;
     }
     return moves;
   }
@@ -244,6 +266,13 @@ export class SchessRules extends ChessRules {
     );
   }
 
+  filterValid(moves) {
+    if (Object.values(this.pocket[this.turn]).some(v => v > 0))
+      // Undercheck tests done in getPotentialMovesFrom()
+      return moves;
+    return super.filterValid(moves);
+  }
+
   prePlay(move) {
     super.prePlay(move);
     if (move.appear.length >= 2) {
@@ -256,8 +285,18 @@ export class SchessRules extends ChessRules {
   }
 
   postPlay(move) {
-    super.postPlay(move);
     const color = move.vanish[0].c;
+    const piece = move.vanish[0].p;
+    // Update king position + flags
+    if (piece == V.KING) {
+      const shift =
+        ([V.HAWK, V.ELEPHANT, V.NOTHING].includes(move.appear[0].p) ? 1 : 0);
+      this.kingPos[color][0] = move.appear[shift].x;
+      this.kingPos[color][1] = move.appear[shift].y;
+      return;
+    }
+    this.updateCastleFlags(move, piece);
+
     const oppCol = V.GetOppCol(color);
     const firstRank = (color == 'w' ? 7 : 0);
     const oppFirstRank = 7 - firstRank;
@@ -266,7 +305,7 @@ export class SchessRules extends ChessRules {
       if (this.pieceFlags[color][move.start.y])
         this.pieceFlags[color][move.start.y] = false;
       // Special castle case:
-      if (move.appear.length >= 2) {
+      if (move.appear.length >= 2 && move.vanish.length == 2) {
         const L = move.appear.length;
         if (move.appear[L-1].p == V.ROOK)
           this.pieceFlags[color][move.vanish[1].y] = false;
@@ -300,14 +339,16 @@ export class SchessRules extends ChessRules {
   }
 
   getNotation(move) {
-    if (
-      move.appear.length >= 2 &&
-      [V.HAWK, V.ELEPHANT].includes(move.appear[0].p)
-    ) {
-      const suffix = "/" + move.appear[0].p.toUpperCase();
-      let cmove = JSON.parse(JSON.stringify(move));
-      cmove.appear.shift();
-      return super.getNotation(cmove) + suffix;
+    if (move.appear.length >= 2) {
+      const pPieceAppear = [V.HAWK, V.ELEPHANT].includes(move.appear[0].p);
+      const nothingAppear = (move.appear[0].p == V.NOTHING);
+      if (pPieceAppear || nothingAppear) {
+        let suffix = "";
+        if (pPieceAppear) suffix = "/" + move.appear[0].p.toUpperCase();
+        let cmove = JSON.parse(JSON.stringify(move));
+        cmove.appear.shift();
+        return super.getNotation(cmove) + suffix;
+      }
     }
     return super.getNotation(move);
   }
-- 
2.44.0