Revert to news button in red, no blinking. Add autoplay option
authorBenjamin Auder <benjamin.auder@somewhere>
Sat, 21 Mar 2020 10:49:53 +0000 (11:49 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Sat, 21 Mar 2020 10:49:53 +0000 (11:49 +0100)
TODO
client/public/images/icons/SOURCE
client/public/images/icons/autoplay.svg [new file with mode: 0644]
client/src/App.vue
client/src/components/BaseGame.vue
client/src/components/MoveList.vue
client/src/views/Game.vue

diff --git a/TODO b/TODO
index 77f3f2d..4a63843 100644 (file)
--- a/TODO
+++ b/TODO
@@ -13,16 +13,6 @@ Goal is still checkmate.
 Take(a)n(d)make : if capture a piece, take its power for the last of the turn and make a move like it.
 If a pawn taken: direction of the capturer.
 
 Take(a)n(d)make : if capture a piece, take its power for the last of the turn and make a move like it.
 If a pawn taken: direction of the capturer.
 
-"Ball" Chess: 9x9 board, ball on center square. 2 queens ?
-To take the ball when it's free you need to capture it.
-To take the ball when it's used, u need to take the piece.
-Goal: bring ball to final rank.
-Possibles passes : soit à une pièce, soit sur une case.
-  --> remplace un déplacement de pièce. Par exemple pion a2 passe à cavalier a4 = 1 coup.
-  --> selon le mode de déplacement standard (donc tout droit pour les pions)
-Pas de notion d'échec ou de mat (?)
-Si une pièce est mat elle donne le ballon (?)
-
 Maxima, Interweave, Roccoco
 
 Synchrone Chess: allow to anticipate en-passant capture as well :)
 Maxima, Interweave, Roccoco
 
 Synchrone Chess: allow to anticipate en-passant capture as well :)
index 88c2502..4d22cab 100644 (file)
@@ -15,3 +15,4 @@ https://www.flaticon.com/free-icon/clear_565313?term=delete&page=1&position=33
 https://www.flaticon.com/free-icon/clear_1632708?term=delete&page=1&position=3
 https://iconscout.com/icon/discord-1
 https://www.onlinewebfonts.com/icon/154680
 https://www.flaticon.com/free-icon/clear_1632708?term=delete&page=1&position=3
 https://iconscout.com/icon/discord-1
 https://www.onlinewebfonts.com/icon/154680
+https://www.flaticon.com/free-icon/bleach_481058?term=triangle&page=1&position=2
diff --git a/client/public/images/icons/autoplay.svg b/client/public/images/icons/autoplay.svg
new file mode 100644 (file)
index 0000000..433826d
--- /dev/null
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 512 512"
+   style="enable-background:new 0 0 512 512;"
+   xml:space="preserve"
+   sodipodi:docname="autoplay.svg"
+   inkscape:version="0.92.4 5da689c313, 2019-01-14"><metadata
+   id="metadata43"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+   id="defs41" /><sodipodi:namedview
+   pagecolor="#ffffff"
+   bordercolor="#666666"
+   borderopacity="1"
+   objecttolerance="10"
+   gridtolerance="10"
+   guidetolerance="10"
+   inkscape:pageopacity="0"
+   inkscape:pageshadow="2"
+   inkscape:window-width="960"
+   inkscape:window-height="1060"
+   id="namedview39"
+   showgrid="false"
+   inkscape:zoom="1.3037281"
+   inkscape:cx="260.33898"
+   inkscape:cy="256"
+   inkscape:window-x="0"
+   inkscape:window-y="20"
+   inkscape:window-maximized="0"
+   inkscape:current-layer="Layer_1" />
+<g
+   id="g6"
+   transform="matrix(1,0,0,1.1667656,0,-42.308422)">
+       <g
+   id="g4">
+               <path
+   d="M 507.521,427.394 282.655,52.617 c -12.074,-20.122 -41.237,-20.122 -53.311,0 L 4.479,427.394 c -12.433,20.72 2.493,47.08 26.655,47.08 h 449.732 c 24.163,0 39.089,-26.36 26.655,-47.08 z"
+   id="path2"
+   inkscape:connector-curvature="0" />
+       </g>
+</g>
+<g
+   id="g8">
+</g>
+<g
+   id="g10">
+</g>
+<g
+   id="g12">
+</g>
+<g
+   id="g14">
+</g>
+<g
+   id="g16">
+</g>
+<g
+   id="g18">
+</g>
+<g
+   id="g20">
+</g>
+<g
+   id="g22">
+</g>
+<g
+   id="g24">
+</g>
+<g
+   id="g26">
+</g>
+<g
+   id="g28">
+</g>
+<g
+   id="g30">
+</g>
+<g
+   id="g32">
+</g>
+<g
+   id="g34">
+</g>
+<g
+   id="g36">
+</g>
+</svg>
\ No newline at end of file
index 15e2f10..25ec25e 100644 (file)
@@ -280,19 +280,10 @@ footer
     padding: 5px 0
 
 .menuitem.somenews
     padding: 5px 0
 
 .menuitem.somenews
-  animation: blinkNews 1s infinite;
   color: red
   &:link, &:visited, &:hover
     color: red
 
   color: red
   &:link, &:visited, &:hover
     color: red
 
-@keyframes blinkNews
-  0%, 49%
-    background-color: yellow
-    padding: 3px
-  50%, 100%
-    background-color: grey
-    padding: 3px
-
 // Styles for diagrams and board (partial).
 // TODO: where to put that ?
 
 // Styles for diagrams and board (partial).
 // TODO: where to put that ?
 
index e86c551..cd71fcb 100644 (file)
@@ -30,6 +30,11 @@ div#baseGame
           img.inline(src="/images/icons/play_rev.svg")
         button(v-if="canFlip" @click="flip()")
           img.inline(src="/images/icons/flip.svg")
           img.inline(src="/images/icons/play_rev.svg")
         button(v-if="canFlip" @click="flip()")
           img.inline(src="/images/icons/flip.svg")
+        button(
+          @click="runAutoplay()"
+          :class="{'in-autoplay': autoplay}"
+        )
+          img.inline(src="/images/icons/autoplay.svg")
         button(@click="play()")
           img.inline(src="/images/icons/play.svg")
         button(@click="gotoEnd()")
         button(@click="play()")
           img.inline(src="/images/icons/play.svg")
         button(@click="gotoEnd()")
@@ -83,6 +88,8 @@ export default {
       firstMoveNumber: 0, //for printing
       incheck: [], //for Board
       inMultimove: false,
       firstMoveNumber: 0, //for printing
       incheck: [], //for Board
       inMultimove: false,
+      autoplay: false,
+      autoplayLoop: null,
       inPlay: false,
       stackToPlay: []
     };
       inPlay: false,
       stackToPlay: []
     };
@@ -135,6 +142,9 @@ export default {
     document.getElementById("eogDiv")
       .addEventListener("click", processModalClick);
   },
     document.getElementById("eogDiv")
       .addEventListener("click", processModalClick);
   },
+  beforeDestroy: function() {
+    if (!!this.autoplayLoop) clearInterval(this.autoplayLoop);
+  },
   methods: {
     focusBg: function() {
       document.getElementById("baseGame").focus();
   methods: {
     focusBg: function() {
       document.getElementById("baseGame").focus();
@@ -263,6 +273,29 @@ export default {
       this.endgameMessage = message;
       document.getElementById("modalEog").checked = true;
     },
       this.endgameMessage = message;
       document.getElementById("modalEog").checked = true;
     },
+    runAutoplay: function() {
+      const infinitePlay = () => {
+        if (this.cursor == this.moves.length - 1) {
+          clearInterval(this.autoplayLoop);
+          this.autoplayLoop = null;
+          this.autoplay = false;
+          return;
+        }
+        if (this.inPlay || this.inMultimove)
+          // Wait next tick
+          return;
+        this.play();
+      };
+      if (this.autoplay) {
+        this.autoplay = false;
+        clearInterval(this.autoplayLoop);
+        this.autoplayLoop = null;
+      } else {
+        this.autoplay = true;
+        infinitePlay();
+        this.autoplayLoop = setInterval(infinitePlay, 1500);
+      }
+    },
     // Animate an elementary move
     animateMove: function(move, callback) {
       let startSquare = document.getElementById(getSquareId(move.start));
     // Animate an elementary move
     animateMove: function(move, callback) {
       let startSquare = document.getElementById(getSquareId(move.start));
@@ -325,12 +358,15 @@ export default {
         this.vr.play(smove);
         this.lastMove = smove;
         if (!this.inMultimove) {
         this.vr.play(smove);
         this.lastMove = smove;
         if (!this.inMultimove) {
-          if (this.cursor < this.moves.length - 1)
-            this.moves = this.moves.slice(0, this.cursor + 1);
-          this.moves.push(smove);
+          // Condition is "!navigate" but we mean "!this.autoplay"
+          if (!navigate) {
+            if (this.cursor < this.moves.length - 1)
+              this.moves = this.moves.slice(0, this.cursor + 1);
+            this.moves.push(smove);
+          }
           this.inMultimove = true; //potentially
           this.cursor++;
           this.inMultimove = true; //potentially
           this.cursor++;
-        } else {
+        } else if (!navigate) {
           // Already in the middle of a multi-move
           const L = this.moves.length;
           if (!Array.isArray(this.moves[L-1]))
           // Already in the middle of a multi-move
           const L = this.moves.length;
           if (!Array.isArray(this.moves[L-1]))
@@ -340,7 +376,10 @@ export default {
         }
       };
       const playMove = () => {
         }
       };
       const playMove = () => {
-        const animate = (V.ShowMoves == "all" && !!received);
+        const animate = (
+          V.ShowMoves == "all" &&
+          (this.autoplay || !!received)
+        );
         if (!Array.isArray(move)) move = [move];
         let moveIdx = 0;
         let self = this;
         if (!Array.isArray(move)) move = [move];
         let moveIdx = 0;
         let self = this;
@@ -387,7 +426,7 @@ export default {
           this.emitFenIfAnalyze();
           this.inMultimove = false;
           this.score = computeScore();
           this.emitFenIfAnalyze();
           this.inMultimove = false;
           this.score = computeScore();
-          if (this.game.mode != "analyze") {
+          if (this.game.mode != "analyze" && !navigate) {
             if (!noemit) {
               // Post-processing (e.g. computer play).
               const L = this.moves.length;
             if (!noemit) {
               // Post-processing (e.g. computer play).
               const L = this.moves.length;
@@ -408,17 +447,19 @@ export default {
         // The move to navigate to is necessarily full:
         if (this.cursor == this.moves.length - 1) return; //no more moves
         move = this.moves[this.cursor + 1];
         // The move to navigate to is necessarily full:
         if (this.cursor == this.moves.length - 1) return; //no more moves
         move = this.moves[this.cursor + 1];
-        // Just play the move:
-        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.score = computeScore();
-          this.emitFenIfAnalyze();
+        if (!this.autoplay) {
+          // Just play the move:
+          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.score = computeScore();
+            this.emitFenIfAnalyze();
+          }
+          this.cursor++;
+          return;
         }
         }
-        this.cursor++;
-        return;
       }
       // Forbid playing outside analyze mode, except if move is received.
       // Sufficient condition because Board already knows which turn it is.
       }
       // Forbid playing outside analyze mode, except if move is received.
       // Sufficient condition because Board already knows which turn it is.
@@ -541,8 +582,11 @@ export default {
     padding-top: 5px
     padding-bottom: 5px
 
     padding-top: 5px
     padding-bottom: 5px
 
+.in-autoplay
+  background-color: #FACF8C
+
 img.inline
 img.inline
-  height: 24px
+  height: 22px
   padding-top: 5px
   @media screen and (max-width: 767px)
     height: 18px
   padding-top: 5px
   @media screen and (max-width: 767px)
     height: 18px
index c4e1998..140b71c 100644 (file)
@@ -193,7 +193,7 @@ export default {
   padding: 5px
 
 img.inline
   padding: 5px
 
 img.inline
-  height: 24px
+  height: 22px
   @media screen and (max-width: 767px)
     height: 18px
 
   @media screen and (max-width: 767px)
     height: 18px
 
index 6339a3c..ddbd330 100644 (file)
@@ -1409,7 +1409,7 @@ button
   margin: 0
   display: inline-flex
   img
   margin: 0
   display: inline-flex
   img
-    height: 24px
+    height: 22px
     display: flex
     @media screen and (max-width: 767px)
       height: 18px
     display: flex
     @media screen and (max-width: 767px)
       height: 18px