Fix moveList + progress on game navigation system
authorBenjamin Auder <benjamin.auder@somewhere>
Mon, 14 Jan 2019 15:52:55 +0000 (16:52 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Mon, 14 Jan 2019 15:52:55 +0000 (16:52 +0100)
public/javascripts/base_rules.js
public/javascripts/components/game.js
public/javascripts/components/moveList.js
public/javascripts/variant.js
public/javascripts/variants/Marseille.js
public/stylesheets/variant.sass
views/variant.pug

index 4b0b470..7db4cfd 100644 (file)
@@ -1053,6 +1053,8 @@ class ChessRules
                        move.flags = JSON.stringify(this.aggregateFlags()); //save flags (for undo)
                if (V.HasEnpassant)
                        this.epSquares.push( this.getEpSquare(move) );
+               if (!move.color)
+                       move.color = this.turn; //for interface
                V.PlayOnBoard(this.board, move);
                this.turn = V.GetOppCol(this.turn);
                this.movesCount++;
index 594c8c2..4048a3d 100644 (file)
@@ -24,8 +24,10 @@ Vue.component('my-game', {
                        vr: null, //VariantRules object, describing the game state + rules
                        endgameMessage: "",
                        orientation: "w",
+                       fenStart: "",
                        
                        moves: [], //TODO: initialize if gameId is defined...
+                       cursor: 0,
                        // orientation :: button flip
                        // userColor: given by gameId, or fen (if no game Id)
                        // gameOver: known if gameId; otherwise assue false
@@ -47,6 +49,7 @@ Vue.component('my-game', {
                        return this.allowChat && this.mode=='human' && this.score != '*';
                },
                showMoves: function() {
+                       return true;
                        return this.allowMovelist && window.innerWidth >= 768;
                },
                showFen: function() {
@@ -81,6 +84,13 @@ Vue.component('my-game', {
                        </my-chat>
                        <my-board v-bind:vr="vr" :mode="mode" :orientation="orientation" :user-color="mycolor" @play-move="play">
                        </my-board>
+                       <div class="button-group">
+                               <button @click="() => play()">Play</button>
+                               <button @click="() => undo()">Undo</button>
+                               <button @click="flip">Flip</button>
+                               <button @click="gotoBegin">GotoBegin</button>
+                               <button @click="gotoEnd">GotoEnd</button>
+                       </div>
                        <div v-if="showFen && !!vr" id="fen-div" class="section-content">
                                <p id="fen-string" class="text-center">
                                        {{ vr.getFen() }}
@@ -93,18 +103,18 @@ Vue.component('my-game', {
                                        {{ translate("Download PGN") }}
                                </button>
                        </div>
-                       <my-move-list v-if="showMoves" :moves="moves">
+                       <my-move-list v-if="showMoves" :moves="moves" :cursor="cursor" @goto-move="gotoMove">
                        </my-move-list>
                </div>
        `,
        created: function() {
-
-//             console.log(this.fen);
-//             console.log(this.gameId);
                if (!!this.gameId)
                        this.loadGame();
                else if (!!this.fen)
+               {
                        this.vr = new VariantRules(this.fen);
+                       this.fenStart = this.fen;
+               }
                // TODO: after game, archive in indexedDB
                // TODO: this events listener is central. Refactor ? How ?
                const socketMessageListener = msg => {
@@ -316,12 +326,25 @@ Vue.component('my-game', {
                        }, 250);
                },
                play: function(move, programmatic) {
+                       // Forbid playing outside analyze mode when cursor isn't at moves.length-1
+                       if (this.mode != "analyze" && this.cursor < this.moves.length-1)
+                               return;
+                       let navigate = !move;
+                       if (navigate)
+                       {
+                               if (this.cursor == this.moves.length)
+                                       return; //no more moves
+                               move = this.moves[this.cursor];
+                       }
                        if (!!programmatic) //computer or human opponent
                                return this.animateMove(move);
                        // Not programmatic, or animation is over
                        if (!move.notation)
                                move.notation = this.vr.getNotation(move);
+                       if (!move.color)
+                               move.color = this.vr.turn;
                        this.vr.play(move);
+                       this.cursor++;
                        if (!move.fen)
                                move.fen = this.vr.getFen();
                        if (this.sound == 2)
@@ -337,10 +360,13 @@ Vue.component('my-game', {
                                // Send the move to web worker (including his own moves)
                                this.compWorker.postMessage(["newmove",move]);
                        }
-                       if (this.score == "*" || this.mode == "analyze")
+                       if (!navigate && (this.score == "*" || this.mode == "analyze"))
                        {
-                               // Stack move on movesList
-                               this.moves.push(move);
+                               // Stack move on movesList at current cursor
+                               if (this.cursor == this.moves.length)
+                                       this.moves.push(move);
+                               else
+                                       this.moves = this.moves.slice(0,this.cursor-1).concat([move]);
                        }
                        // Is opponent in check?
                        this.incheck = this.vr.getCheckSquares(this.vr.turn);
@@ -355,18 +381,45 @@ Vue.component('my-game', {
                        }
                        else if (this.mode == "computer" && this.vr.turn != this.userColor)
                                this.playComputerMove();
+                       if (navigate)
+                               this.$children[0].$forceUpdate(); //TODO!?
                },
                undo: function(move) {
+                       let navigate = !move;
+                       if (navigate)
+                       {
+                               if (this.cursor == 0)
+                                       return; //no more moves
+                               move = this.moves[this.cursor-1];
+                       }
                        this.vr.undo(move);
+                       this.cursor--;
+                       if (navigate)
+                               this.$children[0].$forceUpdate(); //TODO!?
                        if (this.sound == 2)
                                new Audio("/sounds/undo.mp3").play().catch(err => {});
                        this.incheck = this.vr.getCheckSquares(this.vr.turn);
-                       if (this.mode == "analyze")
+                       if (!navigate && this.mode == "analyze")
                                this.moves.pop();
+                       if (navigate)
+                               this.$forceUpdate(); //TODO!?
+               },
+               gotoMove: function(index) {
+                       this.vr = new VariantRules(this.moves[index].fen);
+                       this.cursor = index+1;
+               },
+               gotoBegin: function() {
+                       this.vr = new VariantRules(this.fenStart);
+                       this.cursor = 0;
+               },
+               gotoEnd: function() {
+                       this.gotoMove(this.moves.length-1);
+               },
+               flip: function() {
+                       this.orientation = V.GetNextCol(this.orientation);
                },
        },
 })
-// cursor + ........
 //TODO: confirm dialog with "opponent offers draw", avec possible bouton "prevent future offers" + bouton "proposer nulle"
 //+ bouton "abort" avec score == "?" + demander confirmation pour toutes ces actions,
 //comme sur lichess
index 3687864..b3c4255 100644 (file)
@@ -1,12 +1,12 @@
 //TODO: component for moves list on the right
 // TODO: generic "getPGN" in the same way (following move.color)
 Vue.component('my-move-list', {
-       props: ["moves"], //TODO: other props for e.g. players names + connected indicator
+       props: ["moves","cursor"], //TODO: other props for e.g. players names + connected indicator
        // --> we could also add turn indicator here
+       // + missing "cursor" prop
        data: function() {
                return {
-                       // if oppid == "computer" then mode = "computer" (otherwise human)
-                       myid: "", //TODO
+                       something: "", //TODO
                };
        },
        // TODO: extend rendering for more than 2 colors: would be a parameter
@@ -14,8 +14,9 @@ Vue.component('my-move-list', {
                if (this.moves.length == 0)
                        return;
                const nbColors = 2;
-               if (this.moves[0].color == "black")
-                       this.moves.unshift({color: "white", notation: "..."});
+               // TODO: name colors "white", "black", "red", "yellow" ?
+               if (this.moves[0].color == "b")
+                       this.moves.unshift({color: "w", notation: "..."});
                let tableContent = [];
                let moveCounter = 0;
                let tableRow = undefined;
@@ -23,45 +24,62 @@ Vue.component('my-move-list', {
                let curCellContent = "";
                for (let i=0; i<this.moves.length; i++)
                {
-                       if (this.moves[i].color == "white")
+                       if (this.moves[i].color == "w")
                        {
-                               if (i == 0 || i>0 && this.moves[i-1].color=="black")
+                               if (i == 0 || i>0 && this.moves[i-1].color=="b")
                                {
                                        if (!!tableRow)
+                                       {
+                                               tableRow.children = moveCells;
                                                tableContent.push(tableRow);
+                                       }
                                        moveCells = [
                                                h(
                                                        "td",
-                                                       { attrs: { innerHTML: (++moveCounter) + "." } }
+                                                       { domProps: { innerHTML: (++moveCounter) + "." } }
                                                )
                                        ];
                                        tableRow = h(
                                                "tr",
-                                               { },
-                                               moveCells
+                                               { }
                                        );
                                        curCellContent = "";
                                }
-                               curCellContent += this.moves[i].notation + ",";
+                       }
+                       curCellContent += this.moves[i].notation;
+                       if (i < this.moves.length-1 && this.moves[i+1].color == this.moves[i].color)
+                               curCellContent += ",";
+                       else //color change
+                       {
                                moveCells.push(
                                        h(
                                                "td",
-                                               { attrs: ..............
+                                               {
+                                                       domProps: { innerHTML: curCellContent },
+                                                       on: { click: () => this.gotoMove(i) },
+                                                       "class": { "highlight-lm": this.cursor-1 == i },
+                                               }
+                                       )
+                               );
+                               curCellContent = "";
                        }
                }
                // Complete last row, which might not be full:
-               if (tableRow.length-1 < nbColors)
+               if (moveCells.length-1 < nbColors)
                {
                        const delta = nbColors - (moveCells.length-1);
                        for (let i=0; i<delta; i++)
                        {
                                moveCells.push(
-                                       "td"
-                                       { attrs: { innerHTML: "" } }
+                                       h(
+                                               "td",
+                                               { domProps: { innerHTML: "" } }
+                                       )
                                );
                        }
-                       tableContent.push(tableRow);
                }
+               tableRow.children = moveCells;
+               tableContent.push(tableRow);
                const movesTable = h(
                        "table",
                        { },
@@ -69,6 +87,9 @@ Vue.component('my-move-list', {
                );
                return movesTable;
        },
-//     methods: {
-//     },
-}
+       methods: {
+               gotoMove: function(index) {
+                       this.$emit("goto-move", index);
+               },
+       },
+})
index 74c4298..f074bae 100644 (file)
@@ -12,7 +12,7 @@ new Vue({
                userColor: "w",
 
                allowChat: false,
-               allowMovelist: false,
+               allowMovelist: true,
                fen: V.GenRandInitFen(),
        },
        created: function() {
index 1adb83f..d38d177 100644 (file)
@@ -19,8 +19,6 @@ class MarseilleRules extends ChessRules
 
        getTurnFen()
        {
-               if (this.startAtFirstMove && this.moves.length==0)
-                       return "w";
                return this.turn + this.subTurn;
        }
 
@@ -56,9 +54,8 @@ class MarseilleRules extends ChessRules
                // Extract subTurn from turn indicator: "w" (first move), or
                // "w1" or "w2" white subturn 1 or 2, and same for black
                const fullTurn = V.ParseFen(fen).turn;
-               this.startAtFirstMove = (fullTurn == "w");
                this.turn = fullTurn[0];
-               this.subTurn = (fullTurn[1] || 1);
+               this.subTurn = (fullTurn[1] || 0); //"w0" = special code for first move in game
        }
 
        getPotentialPawnMoves([x,y])
@@ -144,18 +141,13 @@ class MarseilleRules extends ChessRules
                return moves;
        }
 
-       play(move, ingame)
+       play(move)
        {
-               if (!!ingame)
-               {
-                       move.notation = [this.getNotation(move), this.getLongNotation(move)];
-                       // In this special case, we also need the "move color":
-                       move.color = this.turn;
-               }
                move.flags = JSON.stringify(this.aggregateFlags());
+               move.turn = this.turn + this.subturn;
                V.PlayOnBoard(this.board, move);
                const epSq = this.getEpSquare(move);
-               if (this.startAtFirstMove && this.moves.length == 0)
+               if (this.subTurn == 0) //first move in game
                {
                        this.turn = "b";
                        this.epSquares.push([epSq]);
@@ -179,40 +171,22 @@ class MarseilleRules extends ChessRules
                                this.epSquares.push([epSq]);
                        this.subTurn = 3 - this.subTurn;
                }
-               this.moves.push(move);
                this.updateVariables(move);
-               if (!!ingame)
-                       move.hash = hex_md5(this.getFen());
        }
 
        undo(move)
        {
                this.disaggregateFlags(JSON.parse(move.flags));
                V.UndoOnBoard(this.board, move);
-               if (this.startAtFirstMove && this.moves.length == 1)
-               {
-                       this.turn = "w";
+               if (move.turn[1] == '0' || move.checkOnSubturn1 || this.subTurn == 2)
                        this.epSquares.pop();
-               }
-               else if (move.checkOnSubturn1)
+               else //this.subTurn == 1
                {
-                       this.turn = V.GetOppCol(this.turn);
-                       this.subTurn = 1;
-                       this.epSquares.pop();
-               }
-               else
-               {
-                       if (this.subTurn == 1)
-                       {
-                               this.turn = V.GetOppCol(this.turn);
-                               let lastEpsq = this.epSquares[this.epSquares.length-1];
-                               lastEpsq.pop();
-                       }
-                       else
-                               this.epSquares.pop();
-                       this.subTurn = 3 - this.subTurn;
+                       let lastEpsq = this.epSquares[this.epSquares.length-1];
+                       lastEpsq.pop();
                }
-               this.moves.pop();
+               this.turn = move.turn[0];
+               this.subTurn = parseInt(move.turn[1]);
                this.unupdateVariables(move);
        }
 
@@ -319,6 +293,7 @@ class MarseilleRules extends ChessRules
                return selected;
        }
 
+       // TODO: put this generic version elsewhere
        getPGN(mycolor, score, fenStart, mode)
        {
                let pgn = "";
index 7857085..299320d 100644 (file)
@@ -67,6 +67,9 @@ label.drawer-toggle
 
 // Game section:
 
+td.highlight-lm
+  background-color: purple
+
 button.play
   height: 24px
   margin: 0
index dbdbaba..76d79ae 100644 (file)
@@ -54,5 +54,6 @@ block javascripts
        script(src="/javascripts/components/board.js")
        //script(src="/javascripts/components/problemPreview.js")
        //script(src="/javascripts/components/problems.js")
+       script(src="/javascripts/components/moveList.js")
        script(src="/javascripts/components/game.js")
        script(src="/javascripts/variant.js")