Computer mode in rules section almost OK
authorBenjamin Auder <benjamin.auder@somewhere>
Tue, 15 Jan 2019 00:25:23 +0000 (01:25 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Tue, 15 Jan 2019 00:25:23 +0000 (01:25 +0100)
20 files changed:
_tmp/TODO [moved from TODO with 67% similarity]
_tmp/hexaboard_test.html [moved from hexaboard_test.html with 76% similarity]
models/Problem.js
public/javascripts/components/board.js
public/javascripts/components/game.js
public/javascripts/components/problems.js
public/javascripts/components/rules.js
public/javascripts/utils/squareId.js [new file with mode: 0644]
public/javascripts/variant.js
reflexions [deleted file]
routes/all.js
routes/challenge.js
routes/index.js
routes/messages.js
routes/playing.js
routes/problems.js
routes/users.js
routes/variant.js
views/modalSettings.pug
views/variant.pug

diff --git a/TODO b/_tmp/TODO
similarity index 67%
rename from TODO
rename to _tmp/TODO
index 7ea4813..cb4b8a9 100644 (file)
--- a/TODO
+++ b/_tmp/TODO
@@ -1,4 +1,11 @@
-Sur index, introduction menu remplacé par "mes parties", montrant parties (corr) en cours toutes variantes confondues
+tell opponent that I got the move, for him to start timer (and lose...)
+  --> no, not needed and impossible if everybody is offline
+       ==> just store this time locally (cheating possible but...)
+board2, board3, board4
+VariantRules2, 3 et 4 aussi
+fetch challenges and corr games from server at startup (room)
+but forbid anonymous to start corr games or accept challenges
+
 Dans variant page, "mes parties" peut toujours contenir corr + importées (deux onglets)
 En fin de partie (observée ou non), bouton "import game" en + de "download game" ==> directement dans indexedDB
 --> sursis de 7 jours pour les parties par correspondance, qui sont encore chargées depuis le serveur
@@ -8,7 +15,6 @@ mat en 2 échiqueté : brnkr3/pppp1p1p/4ps2/8/2P2P2/P1qP4/2c1s1PP/R1K5
 
 // TODO: decodeURIComponent() for GET/DELETE parameters
 
-1) Finish problems tab
 2) Integrate computer play into rules tab
 3) Allow correspondance play (no need for P2P: online moves through the server (which also store them))
 4) Write my-games tab (included current/finished/imported)
@@ -27,32 +33,20 @@ Increase code line length to 100 or more?
 Chat button should be more apparent after game ends (color ?)
 Reinforce security for problems upload (how ?)
 
-The mode switch between human/computer/friend (+ problem) is a mess
-(example: finished computer game, ongoing friend game, reload, friend game is unreachable)
-
 Later:
-Let choice of time control, allow correspondance play, several games at the same time
+Let choice of time control, allow correspondance play, several corr games at the same time
 ==> need to use indexedDB instead of localStorage. Maybe with Dexie https://dexie.org/
 Each user would have a unique identifier stored in the client DB.
 Allow to cancel games (if opponent doesn't connect again)
-Identity would be browser-based: different games on smartphone, home computer, work computer... (why not ?)
-Index might still look the same, and variant page would have another tab "Games"
-==> running, and finished (which can be deleted from local memory)
-(A true analysis mode could be implemented also, to navigate in completed games --> use a button)
+Live games storage would be browser-based: different games on smartphone, home computer, work computer... (why not ?)
+==> (at most 1) running, and finished (which can be deleted from local memory)
 Allow challenging a specific player (by his chosen name)
-But keep the random pairings as main playing way + always playing in ZEN mode,
-except when accepting an individual challenge.
+But keep the random pairings as main playing way + always playing in ZEN mode
 
 style menu : surligner onglet courant
 
 Interface :
  - newGame: une modalBox à paramètres, timeControl, type d'adversaire ==> "new Game")
- - friend-->renommé en 'analyse' et devenant un vrai mode analyse (on garde ces trois modes ?)
-
-problèmes : récupérer 20 ou 50 depuis le serveur, puis les afficher un par un en les analysant directement,
-comme sur le site de ProgramFOX ==> présentation unifiée échiquier avec instructions dessus et soluce cachée dessous
-
-==> il faut pouvoir faire "new Interface(variables)" pour lancer une analyse de problème sans repasser par le mode jeu...
 
 Importer des parties : nécessite de parser le PGN produit (possible, un peu pénible)
 mais permettrait mode analyse (avec bouton "analyse", comme sur ancien site).
@@ -61,13 +55,13 @@ espagnol : jugada ou movimiento ?
 fin de la partida au lieu de final de partida ?
 
 Bouton new game ==> human only. Indiquer adversaire (éventuellement), cadence (ou "infini")
-Mode analyse : accessible à tout moment d'une partie (HH, ou computer) terminée.
+Mode analyse : accessible à tout moment d'une partie (HH, ou computer) terminée + bouton "analyze from here" (sur parties observées)
 
 Coordonnées sur échiquier: sur cases, à gauche (verticale) ou en bas (horizontale)
 
 Import game : en local dans indexedDb, affichage dans "Games --> Imported"
 
-Checkered : si intervention d'un 3eme joueur, initialiser son temps à la moyenne des temps restants des deux autres...
+Checkered : si intervention d'un 3eme joueur, initialiser son temps à la moyenne des temps restants des deux autres... ?
 
 Mode contre ordinateur : seulement accessible depuis onglet "Rules" (son principal intérêt)
 
similarity index 76%
rename from hexaboard_test.html
rename to _tmp/hexaboard_test.html
index 800e189..86abc2e 100644 (file)
@@ -37,13 +37,21 @@ for(var a=0;a<8;a++) {
        }}
 }}
 
+let x=100, y=100, size=40;
+ctx.beginPath();
+ctx.moveTo(x + size * Math.cos(0), y + size * Math.sin(0));
+for (let side=0; side < 7; side++) {
+       ctx.lineTo(x + size * Math.cos(side * 2 * Math.PI / 6), y + size * Math.sin(side * 2 * Math.PI / 6));
+}
+ctx.fillStyle = "#333333";
+ctx.fill();
+
 var img = new Image();
 img.onload = function() {
            ctx.drawImage(img, 0, 0, 60, 60);
 }
 img.src = "public/images/pieces/wb.svg";
 
-       
 </script>
 
 </body>
index 7858676..7ac92f7 100644 (file)
@@ -11,50 +11,34 @@ var db = require("../utils/database");
  */
 
 // TODO: callback ?
-exports.create = function(vname, fen, instructions, solution)
-{
-       db.serialize(function() {
-               const vidQuery =
-                       "SELECT id " +
-                       "FROM Variants " +
-                       "WHERE name = '" + vname + "'";
-               db.get(vidQuery, (err,variant) => {
-                       const insertQuery =
-                               "INSERT INTO Problems (added, vid, fen, instructions, solution) VALUES " +
-                               "(" +
-                                       Date.now() + "," +
-                                       variant.id + "," +
-                                       fen + "," +
-                                       instructions + "," +
-                                       solution +
-                               ")";
-                       db.run(insertQuery);
-               });
-       });
-}
-
-exports.getById = function(id, callback)
+exports.create = function(vid, fen, instructions, solution)
 {
        db.serialize(function() {
                const query =
-                       "SELECT * FROM Problems " +
-                       "WHERE id ='" + id + "'";
-               db.get(query, callback);
+                       "INSERT INTO Problems (added, vid, fen, instructions, solution) VALUES " +
+                       "(" +
+                               Date.now() + "," +
+                               vid + "," +
+                               fen + "," +
+                               instructions + "," +
+                               solution +
+                       ")";
+               db.run(query);
        });
 }
 
-exports.getOne = function(vname, pid, callback)
+exports.getOne = function(id, callback)
 {
        db.serialize(function() {
                const query =
                        "SELECT * " +
                        "FROM Problems " +
-                       "WHERE id = " + pid;
+                       "WHERE id = " + id;
                db.get(query, callback);
        });
 }
 
-exports.fetchN = function(vname, uid, type, directionStr, lastDt, MaxNbProblems, callback)
+exports.fetchN = function(vid, uid, type, directionStr, lastDt, MaxNbProblems, callback)
 {
        db.serialize(function() {
                let typeLine = "";
@@ -62,7 +46,7 @@ exports.fetchN = function(vname, uid, type, directionStr, lastDt, MaxNbProblems,
                        typeLine = "AND id " + (type=="others" ? "!=" : "=") + " " + uid;
                const query =
                        "SELECT * FROM Problems " +
-                       "WHERE vid = (SELECT id FROM Variants WHERE name = '" + vname + "') " +
+                       "WHERE vid = " + vid +
                        "  AND added " + directionStr + " " + lastDt + " " + typeLine + " " +
                        "ORDER BY added " + (directionStr=="<" ? "DESC " : "") +
                        "LIMIT " + MaxNbProblems;
index 0399410..5a75f29 100644 (file)
@@ -142,7 +142,7 @@ Vue.component('my-board', {
                                                                        'incheck': showLight && incheckSq[ci][cj],
                                                                },
                                                                attrs: {
-                                                                       id: this.getSquareId({x:ci,y:cj}),
+                                                                       id: getSquareId({x:ci,y:cj}),
                                                                },
                                                        },
                                                        elems
@@ -161,7 +161,7 @@ Vue.component('my-board', {
                                myReservePiecesArray.push(h('div',
                                {
                                        'class': {'board':true, ['board'+sizeY]:true},
-                                       attrs: { id: this.getSquareId({x:sizeX+shiftIdx,y:i}) }
+                                       attrs: { id: getSquareId({x:sizeX+shiftIdx,y:i}) }
                                },
                                [
                                        h('img',
@@ -185,7 +185,7 @@ Vue.component('my-board', {
                                oppReservePiecesArray.push(h('div',
                                {
                                        'class': {'board':true, ['board'+sizeY]:true},
-                                       attrs: { id: this.getSquareId({x:sizeX+(1-shiftIdx),y:i}) }
+                                       attrs: { id: getSquareId({x:sizeX+(1-shiftIdx),y:i}) }
                                },
                                [
                                        h('img',
@@ -251,16 +251,6 @@ Vue.component('my-board', {
                );
        },
        methods: {
-               // Get the identifier of a HTML square from its numeric coordinates o.x,o.y.
-               getSquareId: function(o) {
-                       // NOTE: a separator is required to allow any size of board
-                       return  "sq-" + o.x + "-" + o.y;
-               },
-               // Inverse function
-               getSquareFromId: function(id) {
-                       let idParts = id.split('-');
-                       return [parseInt(idParts[1]), parseInt(idParts[2])];
-               },
                mousedown: function(e) {
                        e = e || window.event;
                        let ingame = false;
@@ -291,7 +281,7 @@ Vue.component('my-board', {
                                this.selectedPiece.style.top = 0;
                                this.selectedPiece.style.display = "inline-block";
                                this.selectedPiece.style.zIndex = 3000;
-                               const startSquare = this.getSquareFromId(e.target.parentNode.id);
+                               const startSquare = getSquareFromId(e.target.parentNode.id);
                                this.possibleMoves = [];
                                const color = this.mode=="analyze" || this.gameOver
                                        ? this.vr.turn
@@ -337,7 +327,7 @@ Vue.component('my-board', {
                                return;
                        }
                        // OK: process move attempt
-                       let endSquare = this.getSquareFromId(landing.id);
+                       let endSquare = getSquareFromId(landing.id);
                        let moves = this.findMatchingMoves(endSquare);
                        this.possibleMoves = [];
                        if (moves.length > 1)
index edd17c4..c411b09 100644 (file)
@@ -4,12 +4,10 @@
 Vue.component('my-game', {
        // gameId: to find the game in storage (assumption: it exists)
        // fen: to start from a FEN without identifiers (analyze mode)
-       props: ["conn","gameId","fen","mode","allowChat","allowMovelist"],
+       props: ["conn","gameId","fen","mode","allowChat","allowMovelist","queryHash","settings"],
        data: function() {
                return {
                        oppConnected: false, //TODO?
-                       // sound level: 0 = no sound, 1 = sound only on newgame, 2 = always
-                       sound: parseInt(localStorage["sound"] || "2"),
                        // Web worker to play computer moves without freezing interface:
                        compWorker: new Worker('/javascripts/playCompMove.js'),
                        timeStart: undefined, //time when computer starts thinking
@@ -17,10 +15,9 @@ Vue.component('my-game', {
                        endgameMessage: "",
                        orientation: "w",
 
-                       // if oppid == "computer" then mode = "computer" (otherwise human)
                        oppid: "", //opponent ID in case of HH game
                        score: "*", //'*' means 'unfinished'
-                       // userColor: given by gameId, or fen (if no game Id)
+                       // userColor: given by gameId, or fen in problems mode (if no game Id)...
                        mycolor: "w",
                        fenStart: "",
                        moves: [], //TODO: initialize if gameId is defined...
@@ -31,10 +28,30 @@ Vue.component('my-game', {
        watch: {
                fen: function(newFen) {
                        this.vr = new VariantRules(newFen);
+                       this.moves = [];
+                       this.cursor = 0;
+                       this.fenStart = newFen;
+                       this.score = "*";
+                       if (this.mode == "analyze")
+                       {
+                               this.mycolor = V.ParseFen(newFen).turn;
+                               this.orientation = "w"; //convention (TODO?!)
+                       }
+                       else if (this.mode == "computer") //only other alternative (HH with gameId)
+                       {
+                               this.mycolor = (Math.random() < 0.5 ? "w" : "b");
+                               this.orientation = this.mycolor;
+                               this.compWorker.postMessage(["init",newFen]);
+                       }
                },
                gameId: function() {
                        this.loadGame();
                },
+               queryHash: function(newQhash) {
+                       // New query hash = "id=42"; get 42 as gameId
+                       this.gameId = parseInt(newQhash.substr(2));
+                       this.loadGame();
+               },
        },
        computed: {
                showChat: function() {
@@ -65,7 +82,9 @@ Vue.component('my-game', {
                        </div>
                        <my-chat v-if="showChat">
                        </my-chat>
-                       <my-board v-bind:vr="vr" :last-move="lastMove" :mode="mode" :orientation="orientation" :user-color="mycolor" @play-move="play">
+                       <my-board v-bind:vr="vr" :last-move="lastMove" :mode="mode"
+                               :orientation="orientation" :user-color="mycolor" :settings="settings"
+                               @play-move="play">
                        </my-board>
                        <div class="button-group">
                                <button @click="() => play()">Play</button>
@@ -175,8 +194,11 @@ Vue.component('my-game', {
                        this.conn.addEventListener('message', socketMessageListener);
                        this.conn.addEventListener('close', socketCloseListener);
                };
-               this.conn.onmessage = socketMessageListener;
-               this.conn.onclose = socketCloseListener;
+               if (!!this.conn)
+               {
+                       this.conn.onmessage = socketMessageListener;
+                       this.conn.onclose = socketCloseListener;
+               }
 
                // Computer moves web worker logic: (TODO: also for observers in HH games)
                this.compWorker.postMessage(["scripts",variant.name]);
@@ -318,20 +340,20 @@ Vue.component('my-game', {
                        this.compWorker.postMessage(["askmove"]);
                },
                animateMove: function(move) {
-                       let startSquare = document.getElementById(this.getSquareId(move.start));
-                       let endSquare = document.getElementById(this.getSquareId(move.end));
+                       let startSquare = document.getElementById(getSquareId(move.start));
+                       let endSquare = document.getElementById(getSquareId(move.end));
                        let rectStart = startSquare.getBoundingClientRect();
                        let rectEnd = endSquare.getBoundingClientRect();
                        let translation = {x:rectEnd.x-rectStart.x, y:rectEnd.y-rectStart.y};
                        let movingPiece =
-                               document.querySelector("#" + this.getSquareId(move.start) + " > img.piece");
+                               document.querySelector("#" + getSquareId(move.start) + " > img.piece");
                        // HACK for animation (with positive translate, image slides "under background")
                        // Possible improvement: just alter squares on the piece's way...
                        squares = document.getElementsByClassName("board");
                        for (let i=0; i<squares.length; i++)
                        {
                                let square = squares.item(i);
-                               if (square.id != this.getSquareId(move.start))
+                               if (square.id != getSquareId(move.start))
                                        square.style.zIndex = "-1";
                        }
                        movingPiece.style.transform = "translate(" + translation.x + "px," +
@@ -368,12 +390,12 @@ Vue.component('my-game', {
                        this.lastMove = move;
                        if (!move.fen)
                                move.fen = this.vr.getFen();
-                       if (this.sound == 2)
+                       if (this.settings.sound == 2)
                                new Audio("/sounds/move.mp3").play().catch(err => {});
                        if (this.mode == "human")
                        {
                                updateStorage(move); //after our moves and opponent moves
-                               if (this.vr.turn == this.userColor)
+                               if (this.vr.turn == this.mycolor)
                                        this.conn.send(JSON.stringify({code:"newmove", move:move, oppid:this.oppid}));
                        }
                        else if (this.mode == "computer")
@@ -400,7 +422,7 @@ Vue.component('my-game', {
                                        this.showScoreMsg(score);
                                // TODO: notify end of game (give score)
                        }
-                       else if (this.mode == "computer" && this.vr.turn != this.userColor)
+                       else if (this.mode == "computer" && this.vr.turn != this.mycolor)
                                this.playComputerMove();
                        // https://vuejs.org/v2/guide/list.html#Caveats (also for undo)
                        if (navigate)
@@ -419,7 +441,7 @@ Vue.component('my-game', {
                        this.lastMove = (this.cursor > 0 ? this.moves[this.cursor-1] : undefined);
                        if (navigate)
                                this.$children[0].$forceUpdate(); //TODO!?
-                       if (this.sound == 2)
+                       if (this.settings.sound == 2)
                                new Audio("/sounds/undo.mp3").play().catch(err => {});
                        this.incheck = this.vr.getCheckSquares(this.vr.turn);
                        if (!navigate && this.mode == "analyze")
index cf2cd07..00ea769 100644 (file)
@@ -1,4 +1,5 @@
 Vue.component('my-problems', {
+       props: ["queryHash","settings"],
        data: function () {
                return {
                        userId: user.id,
@@ -38,7 +39,7 @@ Vue.component('my-problems', {
                                                {{ curProb.instructions }}
                                        </p>
                                </div>
-                               <my-game :fen="curProb.fen" :mode="analyze" :allowMovelist="true">
+                               <my-game :fen="curProb.fen" :mode="analyze" :allowMovelist="true" :settings="settings">
                                </my-board>
                                <div id="solution-div" class="section-content">
                                        <h3 class="clickable" @click="showSolution = !showSolution">
@@ -128,10 +129,24 @@ Vue.component('my-problems', {
                        </div>
                </div>
        `,
+       watch: {
+               queryHash: function(newQhash) {
+                       if (!!newQhash)
+                       {
+                               // New query hash = "id=42"; get 42 as problem ID
+                               const pid = parseInt(newQhash.substr(2));
+                               this.showProblem(pid);
+                       }
+                       else
+                               this.curProb = null; //(back to) list display
+               },
+       },
        created: function() {
-               // TODO: adapt this, #problems:28 ? (for example)
-               if (location.hash.length > 0)
-                       this.showProblem(location.hash.slice(1));
+               if (!!this.queryHash)
+               {
+                       const pid = parseInt(this.queryHash.substr(2));
+                       this.showProblem(pid);
+               }
                else
                        this.firstFetch();
        },
@@ -249,7 +264,7 @@ Vue.component('my-problems', {
                                }
                        }
                        ajax(
-                               "/problems/" + variant.name, //TODO: use variant._id ?
+                               "/problems/" + variant.id,
                                "GET",
                                {
                                        type: type,
@@ -284,7 +299,7 @@ Vue.component('my-problems', {
                },
                deleteProblem: function(pid) {
                        ajax(
-                               "/problems/" + variant.name + "/" + pid, //TODO: with variant.id ?
+                               "/problems/" + variant.id + "/" + pid,
                                "DELETE",
                                response => {
                                        // Delete problem from the list on client side
@@ -297,7 +312,7 @@ Vue.component('my-problems', {
                sendProblem: function() {
                        // Send it to the server and close modal
                        ajax(
-                               "/problems/" + variant.name, //TODO: with variant.id ?
+                               "/problems/" + variant.id,
                                (this.modalProb.id > 0 ? "PUT" : "POST"),
                                this.modalProb,
                                response => {
index 02d3a0c..e9df1ec 100644 (file)
@@ -1,11 +1,33 @@
 // Load rules on variant page
 Vue.component('my-rules', {
+       props: ["settings"],
        data: function() {
-               return { content: "" };
+               return {
+                       content: "",
+                       display: "rules",
+                       mode: "computer",
+                       mycolor: "w",
+                       allowMovelist: true,
+                       fen: "",
+               };
        },
+       
+       // TODO: third button "see a sample game" (comp VS comp)
+       
        template: `
                <div class="col-sm-12 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
-                       <div v-html="content" class="section-content"></div>
+                       <div class="button-group">
+                               <button @click="display='rules'">
+                                       Read the rules
+                               </button>
+                               <button @click="startComputerGame()">
+                                       Beat the computer!
+                               </button>
+                       </div>
+                       <div v-show="display=='rules'" v-html="content" class="section-content"></div>
+                       <my-game v-show="display=='computer'" :mycolor="mycolor" :settings="settings"
+                               :allow-movelist="allowMovelist" :mode="mode" :fen="fen">
+                       </my-game>
                </div>
        `,
        mounted: function() {
@@ -28,5 +50,9 @@ Vue.component('my-rules', {
                                shadow: fenParts[3],
                        };
                },
+               startComputerGame: function() {
+                       this.fen = V.GenRandInitFen();
+                       this.display = "computer";
+               },
        },
 })
diff --git a/public/javascripts/utils/squareId.js b/public/javascripts/utils/squareId.js
new file mode 100644 (file)
index 0000000..a3423f7
--- /dev/null
@@ -0,0 +1,12 @@
+// Get the identifier of a HTML square from its numeric coordinates o.x,o.y.
+function getSquareId(o)
+{
+       // NOTE: a separator is required to allow any size of board
+       return  "sq-" + o.x + "-" + o.y;
+}
+
+// Inverse function
+function getSquareFromId(id) {
+       let idParts = id.split('-');
+       return [parseInt(idParts[1]), parseInt(idParts[2])];
+}
index c1ba857..606c1b9 100644 (file)
@@ -3,23 +3,36 @@ new Vue({
        data: {
                display: "undefined", //default to main hall; see "created()" function
                gameid: undefined, //...yet
-       
+               queryHash: "",
                conn: null,
 
+               // Settings initialized with values from localStorage
+               settings:       {
+                       bcolor: localStorage["bcolor"] || "lichess",
+                       sound: parseInt(localStorage["sound"]) || 2,
+                       hints: parseInt(localStorage["hints"]) || 1,
+                       coords: !!eval(localStorage["coords"]),
+                       highlight: !!eval(localStorage["highlight"]),
+                       sqSize: parseInt(localStorage["sqSize"]),
+               },
+
                // TEMPORARY: DEBUG
                mode: "analyze",
                orientation: "w",
                userColor: "w",
-
                allowChat: false,
                allowMovelist: true,
                fen: V.GenRandInitFen(),
        },
        created: function() {
-               // TODO: navigation becomes a little more complex
-               this.setDisplay();
+               if (!!localStorage["variant"])
+               {
+                       location.hash = "#game?id=" + localStorage["gameId"];
+                       this.display = location.hash.substr(1);
+               }
+               else
+                       this.setDisplay();
                window.onhashchange = this.setDisplay;
-
                this.myid = "abcdefghij";
 //console.log(this.myid + " " + variant);
                        //myid: localStorage.getItem("myid"), //our ID, always set
@@ -33,45 +46,30 @@ new Vue({
                //this.vr = new VariantRules( V.GenRandInitFen() );
        },
        methods: {
+               updateSettings: function(event) {
+                       const propName =
+                               event.target.id.substr(3).replace(/^\w/, c => c.toLowerCase())
+                       localStorage[propName] = ["highlight","coords"].includes(propName)
+                               ? event.target.checked
+                               : event.target.value;
+               },
                setDisplay: function() {
-
-//TODO: prevent set display if there is a running game
-
+                       // Prevent set display if there is a running game
+                       if (!!localStorage["variant"])
+                               return;
                        if (!location.hash)
                                location.hash = "#room"; //default
-                       this.display = location.hash.substr(1);
+                       const hashParts = location.hash.substr(1).split("?");
+                       this.display = hashParts[0];
+                       this.queryHash = hashParts[1]; //may be empty, undefined...
                        // Close menu on small screens:
                        let menuToggle = document.getElementById("drawer-control");
                        if (!!menuToggle)
                                menuToggle.checked = false;
                },
-
-               // TEMPORARY: DEBUG (duplicate code)
-               play: function(move) {
-                       // Not programmatic, or animation is over
-                       if (!move.notation)
-                               move.notation = this.vr.getNotation(move);
-                       this.vr.play(move);
-                       if (!move.fen)
-                               move.fen = this.vr.getFen();
-                       if (this.sound == 2)
-                               new Audio("/sounds/move.mp3").play().catch(err => {});
-                       // Is opponent in check?
-                       this.incheck = this.vr.getCheckSquares(this.vr.turn);
-                       const score = this.vr.getCurrentScore();
-               },
-               undo: function(move) {
-                       this.vr.undo(move);
-                       if (this.sound == 2)
-                               new Audio("/sounds/undo.mp3").play().catch(err => {});
-                       this.incheck = this.vr.getCheckSquares(this.vr.turn);
-               },
        },
 });
                
 //const continuation = (localStorage.getItem("variant") === variant.name);
 //                     if (continuation) //game VS human has priority
 //                             this.continueGame("human");
-
-// TODO:
-// si quand on arrive il y a une continuation "humaine" : display="game" et retour à la partie !
diff --git a/reflexions b/reflexions
deleted file mode 100644 (file)
index 82e5980..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-tell opponent that I got the move, for him to start timer (and lose...)
-  --> no, not needed and impossible if everybody is offline
-       ==> just store this time locally (cheating possible but...)
-board2, board3, board4
-VariantRules2, 3 et 4 aussi
-fetch challenges and corr games from server at startup (room)
-but forbid anonymous to start corr games or accept challenges
index 3e989f7..0989b3f 100644 (file)
@@ -2,10 +2,10 @@ var router = require("express").Router();
 
 router.use("/", require("./index"));
 router.use("/", require("./users"));
-router.use("/", require("./problems"));
 router.use("/", require("./messages"));
-//router.use("/", require("./challenge"));
 //router.use("/", require("./playing"));
+//router.use("/", require("./challenge"));
+router.use("/", require("./problems"));
 router.use("/", require("./variant"));
 
 module.exports = router;
index 47aaad6..1a4d22b 100644 (file)
@@ -1,3 +1,5 @@
+// TODO: adapt this (from Mongo to SQLite, and challenge format changed) for corr play
+
 var router = require("express").Router();
 var ObjectID = require("bson-objectid");
 var ChallengeModel = require('../models/Challenge');
@@ -5,8 +7,6 @@ var UserModel = require('../models/User');
 var ObjectID = require("bson-objectid");
 var access = require("../utils/access");
 
-// Only AJAX requests here (from variant page and index)
-
 // variant page
 router.get("/challengesbyvariant", access.logged, access.ajax, (req,res) => {
        if (req.query["uid"] != req.user._id)
index 0ed5b07..d510068 100644 (file)
@@ -1,3 +1,5 @@
+// Main index page
+
 let router = require("express").Router();
 const VariantModel = require("../models/Variant");
 const selectLanguage = require("../utils/language.js");
index 9a72f5e..74ec8bd 100644 (file)
@@ -1,3 +1,5 @@
+// Router for contact form sending
+
 let router = require("express").Router();
 const mailer = require(__dirname.replace("/routes", "/utils/mailer"));
 
index 7af0a1b..3bdfa35 100644 (file)
@@ -1,3 +1,5 @@
+// TODO: adapt for correspondance play
+
 var router = require("express").Router();
 var UserModel = require("../models/User");
 var GameModel = require('../models/Game');
index adb75da..3434f0c 100644 (file)
@@ -6,11 +6,27 @@ const ProblemModel = require("../models/Problem");
 const sanitizeHtml = require('sanitize-html');
 const MaxNbProblems = 20;
 
-// Get one problem
-router.get("/problems/:vname([a-zA-Z0-9]+)/:pnum([0-9]+)", access.ajax, (req,res) => {
-       const vname = req.params["vname"];
-       const pnum = req.params["pnum"];
-       ProblemModel.getOne(vname, pnum, (err,problem) => {
+function sanitizeUserInput(fen, instructions, solution)
+{
+       if (!fen.match(/^[a-zA-Z0-9, /-]*$/))
+               return "Bad characters in FEN string";
+       instructions = sanitizeHtml(instructions);
+       solution = sanitizeHtml(solution);
+       if (instructions.length == 0)
+               return "Empty instructions";
+       if (solution.length == 0)
+               return "Empty solution";
+       return {
+               fen: fen,
+               instructions: instructions,
+               solution: solution
+       };
+}
+
+// Get one problem (TODO: vid unused, here for URL de-ambiguification)
+router.get("/problems/:vid([0-9]+)/:id([0-9]+)", access.ajax, (req,res) => {
+       const pid = req.params["id"];
+       ProblemModel.getOne(pid, (err,problem) => {
                if (!!err)
                        return res.json(err);
                return res.json({problem: problem});
@@ -18,8 +34,8 @@ router.get("/problems/:vname([a-zA-Z0-9]+)/:pnum([0-9]+)", access.ajax, (req,res
 });
 
 // Fetch N previous or next problems
-router.get("/problems/:vname([a-zA-Z0-9]+)", access.ajax, (req,res) => {
-       const vname = req.params["vname"];
+router.get("/problems/:vid([0-9]+)", access.ajax, (req,res) => {
+       const vid = req.params["vid"];
        const directionStr = (req.query.direction == "forward" ? ">" : "<");
        const lastDt = req.query.last_dt;
        const type = req.query.type;
@@ -27,7 +43,7 @@ router.get("/problems/:vname([a-zA-Z0-9]+)", access.ajax, (req,res) => {
                return res.json({errmsg: "Bad timestamp"});
        if (!["others","mine"].includes(type))
                return res.json({errmsg: "Bad type"});
-       ProblemModel.fetchN(vname, req.userId, type, directionStr, lastDt, MaxNbProblems,
+       ProblemModel.fetchN(vid, req.userId, type, directionStr, lastDt, MaxNbProblems,
                (err,problems) => {
                        if (!!err)
                                return res.json(err);
@@ -36,30 +52,13 @@ router.get("/problems/:vname([a-zA-Z0-9]+)", access.ajax, (req,res) => {
        );
 });
 
-function sanitizeUserInput(fen, instructions, solution)
-{
-       if (!fen.match(/^[a-zA-Z0-9, /-]*$/))
-               return "Bad characters in FEN string";
-       instructions = sanitizeHtml(instructions);
-       solution = sanitizeHtml(solution);
-       if (instructions.length == 0)
-               return "Empty instructions";
-       if (solution.length == 0)
-               return "Empty solution";
-       return {
-               fen: fen,
-               instructions: instructions,
-               solution: solution
-       };
-}
-
 // Upload a problem (sanitize inputs)
-router.post("/problems/:vname([a-zA-Z0-9]+)", access.logged, access.ajax, (req,res) => {
-       const vname = req.params["vname"];
+router.post("/problems/:vid([0-9]+)", access.logged, access.ajax, (req,res) => {
+       const vid = req.params["vid"];
        const s = sanitizeUserInput(req.body["fen"], req.body["instructions"], req.body["solution"]);
        if (typeof s === "string")
                return res.json({errmsg: s});
-  ProblemModel.create(vname, s.fen, s.instructions, s.solution);
+  ProblemModel.create(vid, s.fen, s.instructions, s.solution);
        res.json({});
 });
 
index 9639ad5..9c88d08 100644 (file)
@@ -1,3 +1,5 @@
+// AJAX methods to get, create, update or delete a user
+
 var router = require("express").Router();
 var UserModel = require('../models/User');
 var sendEmail = require('../utils/mailer');
@@ -25,8 +27,6 @@ function setAndSendLoginToken(subject, to, res)
        });
 }
 
-// AJAX user life cycle...
-
 router.post('/register', access.unlogged, access.ajax, (req,res) => {
        const name = req.body.name;
        const email = req.body.email;
index f45c959..cfb6341 100644 (file)
@@ -1,11 +1,13 @@
+// (any) variant page (with room, games, problems ...)
+
 let router = require("express").Router();
 const createError = require('http-errors');
 const VariantModel = require("../models/Variant");
 const selectLanguage = require("../utils/language.js");
 const access = require("../utils/access");
 
-router.get("/:variant([a-zA-Z0-9]+)", (req,res,next) => {
-       const vname = req.params["variant"];
+router.get("/:vname([a-zA-Z0-9]+)", (req,res,next) => {
+       const vname = req.params["vname"];
        VariantModel.getByName(vname, (err,variant) => {
                if (!!err)
                        return next(err);
index 9398a77..3c22c35 100644 (file)
@@ -1,26 +1,35 @@
 input#modalSettings.modal(type="checkbox")
 div(role="dialog" aria-labelledby="settingsTitle")
-       .card.smallpad(onChange="blabla(event)")
+       .card.smallpad(@change="updateSettings")
                label.modal-close(for="modalSettings")
                h3#settingsTitle.section= translations["Preferences"]
-               // taille echiquier : TODO
                fieldset
-                       label(for="setHints")= translations["Show hints?"]
-                       // TODO: this.hints will not work. Idea: query storage in a generic way ?
-                       // --> getValue("hints") par exemple
-                       input#setHints(type="checkbox" checked=this.hints)
+                       label(for="setSqSize")= translations["Square size (in pixels). 0 for 'adaptative'"]
+                       input#setSqSize(type="number" v-model="settings.sqSize")
+               fieldset
+                       label(for="selectHints")= translations["Show move hints?"]
+                       select#setHints(v-model="settings.hints")
+                               option(value="0")= translations["None"]
+                               option(value="1")= translations["Moves from a square"]
+                               option(value="2")= translations["Pieces which can move"]
+               fieldset
+                       label(for="setHighlight")= translations["Highlight squares? (Last move & checks)"]
+                       input#setHighlight(type="checkbox" v-model="settings.highlight")
+               fieldset
+                       label(for="setCoords")= translations["Show board coordinates?"]
+                       input#setCoords(type="checkbox" v-model="settings.coords")
                fieldset
                        label(for="selectColor")= translations["Board colors"]
-                       select#selectColor
-                               option(value="lichess" selected="this.color=='lichess'")
+                       select#setBcolor(v-model="settings.bcolor")
+                               option(value="lichess")
                                        = translations["brown"]
-                               option(value="chesscom" selected="this.color=='chesscom'")
+                               option(value="chesscom")
                                        = translations["green"]
-                               option(value="chesstempo" selected="this.color=='chesstempo'")
+                               option(value="chesstempo")
                                        = translations["blue"]
                fieldset
                        label(for="selectSound")= translations["Play sounds?"]
-                       select#selectSound
-                               option(value="0" selected="this.sound==0")= translations["None"]
-                               option(value="1" selected="this.sound==1")= translations["New game"]
-                               option(value="2" selected="this.sound==2")= translations["All"]
+                       select#setSound(v-model="settings.sound")
+                               option(value="0")= translations["None"]
+                               option(value="1")= translations["New game"]
+                               option(value="2")= translations["All"]
index 7d09190..89872ff 100644 (file)
@@ -30,11 +30,11 @@ block content
                .row
                        //my-room(v-show="display=='room'")
                        //my-game-list(v-show="display=='gameList'")
-                       my-rules(v-show="display=='rules'")
-                       //my-problems(v-show="display=='problems'")
+                       my-rules(v-show="display=='rules'" :settings="settings")
+                       //my-problems(v-show="display=='problems'" :query-hash="queryHash")
                        my-game(v-show="display=='game'" :game-id="gameid" :conn="conn"
                                :allow-chat="allowChat" :allow-movelist="allowMovelist"
-                               :mode="mode" :fen="fen")
+                               :mode="mode" :fen="fen" :query-hash="queryHash")
                        //my-board(:vr="vr" :mode="mode" :orientation="orientation"
                                :user-color="userColor" v-on:play-move="play")
 
@@ -42,6 +42,7 @@ block javascripts
        script(src="/javascripts/utils/array.js")
        script(src="/javascripts/utils/printDiagram.js")
        script(src="/javascripts/utils/datetime.js")
+       script(src="/javascripts/utils/squareId.js")
        script(src="/javascripts/socket_url.js")
        script(src="/javascripts/base_rules.js")
        script(src="/javascripts/settings.js")