Browse Source

[add] scoring

isundil 8 years ago
parent
commit
f1ec6dbcbb
8 changed files with 101 additions and 38 deletions
  1. 3 0
      js/Grid.js
  2. 21 5
      js/polling.js
  3. 6 3
      js/uiGrid.js
  4. 9 3
      js/uiScoreboard.js
  5. 5 2
      js/workflow.js
  6. 16 16
      public/crosswords.min.js
  7. 35 6
      src/Grid.js
  8. 6 3
      src/httpServer.js

+ 3 - 0
js/Grid.js

@@ -86,6 +86,9 @@ function Grid(data, pseudo) {
             this.grid[i][j] = new Cell();
         }
     }
+
+    /** @type {number|null} */
+    this.gridTime = null;
 }
 
 Grid.prototype.computeWord = function(x, y, dx, dy) {

+ 21 - 5
js/polling.js

@@ -39,8 +39,12 @@ function initPolling() {
                         GRID.update(resp["grid"]);
                         uiCreateGrid();
                     }
+                    if (resp["gridTime"]) {
+                        GRID.gridTime = parseInt(resp["gridTime"], 10);
+                    } else {
+                        scheduleNextPoll();
+                    }
                     KNOWN_VERSION = Math.max(KNOWN_VERSION, resp["v"] || 0);
-                    scheduleNextPoll();
                 } // TODO else cannot init party
             });
         } // TODO else cannot init pseudo
@@ -55,16 +59,28 @@ function pollNow() {
         }
         pollNow.polling = true;
         doGet("/api/poll?grid=" +GRID_PUBLIC_ID +"&v=" +KNOWN_VERSION, function(status, resp) {
-            pollNow.polling = false;
-            if (resp) {
-                updateOnPollResult(resp);
+            if (pollNow.stopped !== true) {
+                pollNow.polling = false;
+                if (resp) {
+                    updateOnPollResult(resp);
+                }
+                scheduleNextPoll();
             }
-            scheduleNextPoll();
         });
     }
 }
 
+function stopPolling() {
+    pollNow.stopped = true;
+    if (pollNow.pollSchedule) {
+        clearTimeout(pollNow.pollSchedule);
+        pollNow.pollSchedule = 0;
+    }
+    console.log("stop polling");
+}
+
 function scheduleNextPoll() {
+    pollNow.stopped = false;
     if (!pollNow.pollSchedule)
         pollNow.pollSchedule = setInterval(pollNow, POLL_INTERVAL);
 };

+ 6 - 3
js/uiGrid.js

@@ -124,7 +124,11 @@ function inputCell(x, y) {
         CURRENTINPUT.dom.classList.remove(R.klass.cell.currentInput);
     CURRENTINPUT = getUiCell(x, y);
     CURRENTINPUT.dom.classList.add(R.klass.cell.currentInput);
+
+    // Display mobile / tablet keyboard
     moveInput(CURRENTINPUT);
+
+    console.log("Current index: ", SELECTED_INDEX);
 }
 
 function uiSelectWritableCell(direction) {
@@ -190,14 +194,13 @@ function gridClickDelegate(e) {
                         var coordinates = words[0][j];
                         select(coordinates[0], coordinates[1]);
                         if (coordinates[0] == clickedCell.x && coordinates[1] == clickedCell.y)
-                            SELECTED_INDEX = index;
+                            SELECTED_INDEX = j;
                     }
                     target.classList.add(R.klass.cell.currentInput);
                     inputCell(clickedCell.x, clickedCell.y);
+                    return;
                 }
             }
-            // Display mobile / tablet keyboard
-            moveInput(CURRENTINPUT);
         }
     }
 }

+ 9 - 3
js/uiScoreboard.js

@@ -41,9 +41,10 @@ function onPlayersUpdated() {
     }
 }
 
-setInterval(function() {
+(function() {
+var timeInterval = setInterval(function() {
     if (GRID) {
-        var ellapsed = (Date.now() -GRID.startTime) / 1000;
+        var ellapsed = (GRID.gridTime !== null ? GRID.gridTime : (Date.now() -GRID.startTime)) / 1000;
 
         var seconds = Math.floor(ellapsed % 60);
         ellapsed = (ellapsed - seconds) / 60;
@@ -55,6 +56,11 @@ setInterval(function() {
         text += (seconds < 10 ? '0' : '') +seconds;
 
         dGet(R.id.scoreboard.header.time).textContent = text;
+
+        if (GRID.gridTime) {
+            clearInterval(timeInterval);
+            timeInterval = null;
+        }
     }
 }, 1000);
-
+})();

+ 5 - 2
js/workflow.js

@@ -31,7 +31,6 @@ function keyPressHandler(cell, key) {
 
         } else if (status === 204) {
             pollNow();
-            uiSelectWritableCell(1);
 
         } else {
             // out of sync ?
@@ -52,6 +51,10 @@ function updateOnPollResult(resp) {
         GRID.update(resp["grid"]);
         onGridUpdated();
     }
+    if (resp["gridTime"]) {
+        GRID.gridTime = parseInt(resp["gridTime"], 10);
+        stopPolling();
+    }
     KNOWN_VERSION = Math.max(KNOWN_VERSION, resp["v"] || 0);
 }
 
@@ -103,10 +106,10 @@ document.addEventListener('DOMContentLoaded', function() {
                     CURRENTINPUT.data.letter = key;
                     keyPressHandler(CURRENTINPUT, key);
                     onGridUpdated();
+                    uiSelectWritableCell(1);
                 }
             }
         }
-        console.log(e);
     });
     initPolling();
 });

+ 16 - 16
public/crosswords.min.js

@@ -1,16 +1,16 @@
-var f={};function h(a){var b=document.createElement("li"),c=document.createElement("span");c.className="player-name";c.textContent=a.name;b.appendChild(c);b.j=document.createElement("span");b.j.className="player-score";b.appendChild(b.j);b.style.color=a.color;return b}
-function k(){var a,b=[],c;for(c in n.g){var d=f[c];d||(d=f[c]=h(n.g[c]),c===n.l.id&&d.classList.add("player-self"),a||(a=document.getElementById("scoreboardPlayers")),a.appendChild(d));d.j.textContent=n.g[c].j;b.push(c)}b.sort(function(a,b){return n.g[b].j-n.g[a].j});c=0;for(a=b.length;c<a;c++)f[b[c]].style.order=c}
-setInterval(function(){if(n){var a=(Date.now()-n.D)/1E3,b=Math.floor(a%60),a=(a-b)/60,c=Math.floor(a%60),a=Math.floor((a-c)/60),a=(a?a+":":"")+((10>c?"0":"")+c+":")+((10>b?"0":"")+b);document.getElementById("gridTime").textContent=a}},1E3);var p=[],q=null;function r(a,b,c){var d=document.createElement("div");d.className="cell";if(a.o)d.classList.add("cell-disabled");else if(null!==a.f){d.classList.add("cell-definition");for(var e=document.createElement("span"),g=0,l=a.f.length;g<l;g++){var u=a.f[g],m=document.createElement("span");m.dataset.x=b;m.dataset.y=c;m.dataset.definition=g;m.className="definition";m.innerHTML=u.text.join("<br/>");e.appendChild(m)}d.appendChild(e)}else d.classList.add("cell-letter");return d}
-function t(){var a=document.createDocumentFragment();document.getElementById("gridTitle").textContent=n.F;document.getElementById("gridDifficulty").textContent=n.G;for(var b=0;b<n.s;b++){var c=document.createElement("div");c.className="crossword-line";a.appendChild(c);for(var d=0;d<n.a;d++){var e=r(n.c[d][b],d,b);e.dataset.x=d;e.dataset.y=b;c.appendChild(e);p.push({x:d,y:b,b:e,data:n.c[d][b]})}}for(b=0;b<n.s;b++)for(d=0;d<n.a;d++)e=p[b*n.a+d],e.data.f&&e.data.f.forEach(function(a){switch(a.direction){case 2:p[b*
-n.a+d+1].b.classList.add("definition-right-vt");break;case 1:p[b*n.a+d+1].b.classList.add("definition-right-hz");break;case 4:p[(b+1)*n.a+d].b.classList.add("definition-bottom-vt");break;case 3:p[(b+1)*n.a+d].b.classList.add("definition-bottom-hz")}});v();c=document.getElementById("grid");c.textContent="";c.appendChild(a)}
-function v(){p.forEach(function(a){a.data.f||a.data.o||(a.data.m?(a.b.textContent=a.data.m,a.data.i&&(a.b.classList.add("cell-letter-correct"),a.b.classList.remove("cell-letter-wrong"),a.b.style.color=a.data.i.color)):a.b.textContent="")})}function w(){var a=x,b=document.getElementById("input");b.style.top=a.b.offsetTop+"px";b.style.left=a.b.offsetLeft+"px";b.focus()}function y(a){for(var b=0,c=a.length;b<c;b++)if(!p[a[b][0]+a[b][1]*n.a].data.complete)return!1;return!0}
-function z(a,b){x&&x.b.classList.remove("cell-input");x=p[a+b*n.a];x.b.classList.add("cell-input");w()}function A(a){for(var b=q+a,c=B.length;b<c&&0<=b;b+=a)if(!p[B[b].x+B[b].y*n.a].data.i){z(B[b].x,B[b].y);q=b;break}}
-function C(a){for(a=a.target;a&&a.dataset&&!a.dataset.x;)a=a.parentElement;if(a&&a.dataset&&a.dataset.x&&a.dataset.y){var b=p[parseInt(a.dataset.x,10)+parseInt(a.dataset.y,10)*n.a];if(b.data.o)D();else{if(b.data.f){var c=!0;D();if(b.data.f[a.dataset.definition]){var d=0;b.data.f[a.dataset.definition].B.forEach(function(a){E(a[0],a[1]);c&&!p[a[0]+a[1]*n.a].data.i&&(q=d,z(a[0],a[1]));c=!1;d++})}}else{var e=F(b.x,b.y);D();for(var d=0,g=e.length;d<g;d++)for(var l=0,u=e[d].length;l<u;l++)if(!p[e[d][l][0]+
-e[d][l][1]*n.a].data.i){if(e[d][l][0]==b.x&&e[d][l][1]==b.y){e[d].forEach(function(a){E(a[0],a[1])});q=l;z(b.x,b.y);return}break}d=0;for(g=e.length;d<g;d++)if(!y(e[d])){l=0;for(u=e[0].length;l<u;l++){var m=e[0][l];E(m[0],m[1]);m[0]==b.x&&m[1]==b.y&&(q=0)}a.classList.add("cell-input");z(b.x,b.y)}}w()}}};function G(a){this.text=a.text;this.direction=a.pos;this.B=null}function H(){this.o=!1;this.m=this.i=this.f=null}H.prototype.update=function(a,b){if(null===a.type)this.o=!0;else if(void 0!==a.definitions)this.f=[],a.definitions.forEach(function(a){this.f.push(new G(a))}.bind(this));else if(a.letter)return this.m=a.letter,this.i=b[a.found],a.v;return 0};
-function I(a,b){this.F=a.title||"";this.G=a.difficulty;this.a=a.w;this.s=a.h;this.D=a.startTime||0;this.g={};this.l=null;this.u=b;this.A=[];this.c=[];for(var c=0;c<this.a;c++){this.c[c]=[];for(var d=0;d<this.s;d++)this.c[c][d]=new H}}function J(a,b,c,d,e){if(!a.c[b+d]||!a.c[b+d][c+e]||a.c[b+d][c+e].f||a.c[b+d][c+e].o)return[[b,c]];a=J(a,b+d,c+e,d,e);a.unshift([b,c]);return a}
-function F(a,b){var c=[];n.A.forEach(function(d){for(var e=0,g=d.length;e<g;e++)if(d[e][0]==a&&d[e][1]==b){c.push(d);break}});return c}function K(a){var b=0;a.forEach(function(a){var c=this.g[a.name];c||(c=this.g[a.name]=new L(a));b=Math.max(b,c.update(a))}.bind(n))}
-I.prototype.update=function(a){var b=null,c=!1;a.forEach(function(a){a=this.c[a.x][a.y].update(a,this.g);b=Math.max(b||0,a);0===a&&(c=!0)}.bind(this));if(c){for(var d=[],e=0;e<this.a;e++)for(var g=0;g<this.s;g++)this.c[e][g].f&&this.c[e][g].f.forEach(function(a){var b;switch(a.direction){case 2:b=J(this,e+1,g,0,1);break;case 1:b=J(this,e+1,g,1,0);break;case 4:b=J(this,e,g+1,0,1);break;case 3:b=J(this,e,g+1,1,0)}d.push(b);a.B=b}.bind(this));this.A=d}return b};function L(a){this.id=a.name;this.C=encodeURIComponent(a.name);this.j=a.score;var b=a.name.indexOf("|");this.name=a.name.substr(0,b);this.color="#"+a.name.substr(b+1)}L.prototype.update=function(a){this.j=a.score;return a.v};function M(a,b){var c=new XMLHttpRequest;c.onreadystatechange=function(){if(4===c.readyState){var a=null;if(200===c.status){a=c.response;try{a=JSON.parse(a)}catch(e){a=null}}b(c.status,a)}};c.open("GET",a,!0);c.send(null)}function N(){O(function(a){a&&M("/api/poll?grid="+P+"&v="+Q,function(b,c){c&&(n=new I(c,a),c.players&&(K(c.players),n.l||(n.l=n.g[n.u]),k()),c.grid&&(n.update(c.grid),t()),Q=Math.max(Q,c.v||0),R())})})}
-function S(){!0!==S.c&&(S.a&&(clearTimeout(S.a),S.a=0),S.c=!0,M("/api/poll?grid="+P+"&v="+Q,function(a,b){S.c=!1;b&&(b.players&&(K(b.players),n.l||(n.l=n.g[n.u]),k()),b.grid&&(n.update(b.grid),v()),Q=Math.max(Q,b.v||0));R()}))}function R(){S.a||(S.a=setInterval(S,5E3))};var P,Q=0,n,B=[],x=null;function O(a){var b=window.sessionStorage.getItem("pseudonyme_"+P);b?a(b):M("/api/register?grid="+P,function(b,d){b&&d?(window.sessionStorage.setItem("pseudonyme_"+P,d),a(d)):a(null)})}function T(a){var b=x;b.b.classList.add("cell-letter-pending");M("/api/put?grid="+P+"&key="+a+"&x="+b.x+"&y="+b.y+"&me="+n.l.C,function(a){b.b.classList.remove("cell-letter-pending");403!==a||b.data.i?204===a?(S(),A(1)):S():b.b.classList.add("cell-letter-wrong")})}
-function D(){B.forEach(function(a){a.b.classList.remove("cell-selected")});x&&(x.b.classList.remove("cell-input"),x=null);B=[]}function E(a,b){var c=p[a+b*n.a];B.push(c);c.b.classList.add("cell-selected")}
-document.addEventListener("DOMContentLoaded",function(){P=document.location.hash.substr(1);""==P?document.location.href="/":(document.addEventListener("click",C),document.addEventListener("keydown",function(a){"BACKSPACE"===a.key.toUpperCase()&&a.preventDefault()}),document.addEventListener("keyup",function(a){if(x&&!x.data.i)if("DELETE"==a.key.toUpperCase())x.b.classList.remove("cell-letter-wrong"),x.data.m=null,v();else if("BACKSPACE"==a.key.toUpperCase())x.b.classList.remove("cell-letter-wrong"),
-x.data.m=null,A(-1),v();else if(1===a.key.length){var b=a.key.charAt(0).toUpperCase();b.match(/[A-Z]/)&&(x.data.m=b,T(b),v())}console.log(a)}),N())});
+var e={};function h(a){var b=document.createElement("li"),d=document.createElement("span");d.className="player-name";d.textContent=a.name;b.appendChild(d);b.j=document.createElement("span");b.j.className="player-score";b.appendChild(b.j);b.style.color=a.color;return b}
+function k(){var a,b=[],d;for(d in l.g){var c=e[d];c||(c=e[d]=h(l.g[d]),d===l.l.id&&c.classList.add("player-self"),a||(a=document.getElementById("scoreboardPlayers")),a.appendChild(c));c.j.textContent=l.g[d].j;b.push(d)}b.sort(function(a,b){return l.g[b].j-l.g[a].j});d=0;for(a=b.length;d<a;d++)e[b[d]].style.order=d}
+(function(){var a=setInterval(function(){if(l){var b=(null!==l.o?l.o:Date.now()-l.F)/1E3,d=Math.floor(b%60),b=(b-d)/60,c=Math.floor(b%60),b=Math.floor((b-c)/60),b=(b?b+":":"")+((10>c?"0":"")+c+":")+((10>d?"0":"")+d);document.getElementById("gridTime").textContent=b;l.o&&(clearInterval(a),a=null)}},1E3)})();var n=[],p=null;function r(a,b,d){var c=document.createElement("div");c.className="cell";if(a.s)c.classList.add("cell-disabled");else if(null!==a.f){c.classList.add("cell-definition");for(var f=document.createElement("span"),g=0,m=a.f.length;g<m;g++){var q=a.f[g],t=document.createElement("span");t.dataset.x=b;t.dataset.y=d;t.dataset.definition=g;t.className="definition";t.innerHTML=q.text.join("<br/>");f.appendChild(t)}c.appendChild(f)}else c.classList.add("cell-letter");return c}
+function u(){var a=document.createDocumentFragment();document.getElementById("gridTitle").textContent=l.G;document.getElementById("gridDifficulty").textContent=l.H;for(var b=0;b<l.u;b++){var d=document.createElement("div");d.className="crossword-line";a.appendChild(d);for(var c=0;c<l.a;c++){var f=r(l.c[c][b],c,b);f.dataset.x=c;f.dataset.y=b;d.appendChild(f);n.push({x:c,y:b,b:f,data:l.c[c][b]})}}for(b=0;b<l.u;b++)for(c=0;c<l.a;c++)f=n[b*l.a+c],f.data.f&&f.data.f.forEach(function(a){switch(a.direction){case 2:n[b*
+l.a+c+1].b.classList.add("definition-right-vt");break;case 1:n[b*l.a+c+1].b.classList.add("definition-right-hz");break;case 4:n[(b+1)*l.a+c].b.classList.add("definition-bottom-vt");break;case 3:n[(b+1)*l.a+c].b.classList.add("definition-bottom-hz")}});v();d=document.getElementById("grid");d.textContent="";d.appendChild(a)}
+function v(){n.forEach(function(a){a.data.f||a.data.s||(a.data.m?(a.b.textContent=a.data.m,a.data.i&&(a.b.classList.add("cell-letter-correct"),a.b.classList.remove("cell-letter-wrong"),a.b.style.color=a.data.i.color)):a.b.textContent="")})}function w(a){for(var b=0,d=a.length;b<d;b++)if(!n[a[b][0]+a[b][1]*l.a].data.complete)return!1;return!0}
+function x(a,b){y&&y.b.classList.remove("cell-input");y=n[a+b*l.a];y.b.classList.add("cell-input");var d=y,c=document.getElementById("input");c.style.top=d.b.offsetTop+"px";c.style.left=d.b.offsetLeft+"px";c.focus();console.log("Current index: ",p)}function z(a){for(var b=p+a,d=A.length;b<d&&0<=b;b+=a)if(!n[A[b].x+A[b].y*l.a].data.i){x(A[b].x,A[b].y);p=b;break}}
+function B(a){for(a=a.target;a&&a.dataset&&!a.dataset.x;)a=a.parentElement;if(a&&a.dataset&&a.dataset.x&&a.dataset.y){var b=n[parseInt(a.dataset.x,10)+parseInt(a.dataset.y,10)*l.a];if(b.data.s)C();else if(b.data.f){var d=!0;C();if(b.data.f[a.dataset.definition]){var c=0;b.data.f[a.dataset.definition].C.forEach(function(a){D(a[0],a[1]);d&&!n[a[0]+a[1]*l.a].data.i&&(p=c,x(a[0],a[1]));d=!1;c++})}}else{var f=E(b.x,b.y);C();for(var c=0,g=f.length;c<g;c++)for(var m=0,q=f[c].length;m<q;m++)if(!n[f[c][m][0]+
+f[c][m][1]*l.a].data.i){if(f[c][m][0]==b.x&&f[c][m][1]==b.y){f[c].forEach(function(a){D(a[0],a[1])});p=m;x(b.x,b.y);return}break}c=0;for(q=f.length;c<q;c++)if(!w(f[c])){g=0;for(q=f[0].length;g<q;g++)m=f[0][g],D(m[0],m[1]),m[0]==b.x&&m[1]==b.y&&(p=g);a.classList.add("cell-input");x(b.x,b.y);break}}}};function F(a){this.text=a.text;this.direction=a.pos;this.C=null}function G(){this.s=!1;this.m=this.i=this.f=null}G.prototype.update=function(a,b){if(null===a.type)this.s=!0;else if(void 0!==a.definitions)this.f=[],a.definitions.forEach(function(a){this.f.push(new F(a))}.bind(this));else if(a.letter)return this.m=a.letter,this.i=b[a.found],a.v;return 0};
+function H(a,b){this.G=a.title||"";this.H=a.difficulty;this.a=a.w;this.u=a.h;this.F=a.startTime||0;this.g={};this.l=null;this.A=b;this.B=[];this.c=[];for(var d=0;d<this.a;d++){this.c[d]=[];for(var c=0;c<this.u;c++)this.c[d][c]=new G}this.o=null}function I(a,b,d,c,f){if(!a.c[b+c]||!a.c[b+c][d+f]||a.c[b+c][d+f].f||a.c[b+c][d+f].s)return[[b,d]];a=I(a,b+c,d+f,c,f);a.unshift([b,d]);return a}
+function E(a,b){var d=[];l.B.forEach(function(c){for(var f=0,g=c.length;f<g;f++)if(c[f][0]==a&&c[f][1]==b){d.push(c);break}});return d}function J(a){var b=0;a.forEach(function(a){var c=this.g[a.name];c||(c=this.g[a.name]=new K(a));b=Math.max(b,c.update(a))}.bind(l))}
+H.prototype.update=function(a){var b=null,d=!1;a.forEach(function(a){a=this.c[a.x][a.y].update(a,this.g);b=Math.max(b||0,a);0===a&&(d=!0)}.bind(this));if(d){for(var c=[],f=0;f<this.a;f++)for(var g=0;g<this.u;g++)this.c[f][g].f&&this.c[f][g].f.forEach(function(a){var b;switch(a.direction){case 2:b=I(this,f+1,g,0,1);break;case 1:b=I(this,f+1,g,1,0);break;case 4:b=I(this,f,g+1,0,1);break;case 3:b=I(this,f,g+1,1,0)}c.push(b);a.C=b}.bind(this));this.B=c}return b};function K(a){this.id=a.name;this.D=encodeURIComponent(a.name);this.j=a.score;var b=a.name.indexOf("|");this.name=a.name.substr(0,b);this.color="#"+a.name.substr(b+1)}K.prototype.update=function(a){this.j=a.score;return a.v};function L(a,b){var d=new XMLHttpRequest;d.onreadystatechange=function(){if(4===d.readyState){var a=null;if(200===d.status){a=d.response;try{a=JSON.parse(a)}catch(f){a=null}}b(d.status,a)}};d.open("GET",a,!0);d.send(null)}function M(){N(function(a){a&&L("/api/poll?grid="+O+"&v="+P,function(b,d){d&&(l=new H(d,a),d.players&&(J(d.players),l.l||(l.l=l.g[l.A]),k()),d.grid&&(l.update(d.grid),u()),d.gridTime?l.o=parseInt(d.gridTime,10):Q(),P=Math.max(P,d.v||0))})})}
+function R(){!0!==R.c&&(R.a&&(clearTimeout(R.a),R.a=0),R.c=!0,L("/api/poll?grid="+O+"&v="+P,function(a,b){!0!==R.g&&(R.c=!1,b&&(b.players&&(J(b.players),l.l||(l.l=l.g[l.A]),k()),b.grid&&(l.update(b.grid),v()),b.gridTime&&(l.o=parseInt(b.gridTime,10),R.g=!0,R.a&&(clearTimeout(R.a),R.a=0),console.log("stop polling")),P=Math.max(P,b.v||0)),Q())}))}function Q(){R.g=!1;R.a||(R.a=setInterval(R,5E3))};var O,P=0,l,A=[],y=null;function N(a){var b=window.sessionStorage.getItem("pseudonyme_"+O);b?a(b):L("/api/register?grid="+O,function(b,c){b&&c?(window.sessionStorage.setItem("pseudonyme_"+O,c),a(c)):a(null)})}function S(a){var b=y;b.b.classList.add("cell-letter-pending");L("/api/put?grid="+O+"&key="+a+"&x="+b.x+"&y="+b.y+"&me="+l.l.D,function(a){b.b.classList.remove("cell-letter-pending");403!==a||b.data.i?R():b.b.classList.add("cell-letter-wrong")})}
+function C(){A.forEach(function(a){a.b.classList.remove("cell-selected")});y&&(y.b.classList.remove("cell-input"),y=null);A=[]}function D(a,b){var d=n[a+b*l.a];A.push(d);d.b.classList.add("cell-selected")}
+document.addEventListener("DOMContentLoaded",function(){O=document.location.hash.substr(1);""==O?document.location.href="/":(document.addEventListener("click",B),document.addEventListener("keydown",function(a){"BACKSPACE"===a.key.toUpperCase()&&a.preventDefault()}),document.addEventListener("keyup",function(a){y&&!y.data.i&&("DELETE"==a.key.toUpperCase()?(y.b.classList.remove("cell-letter-wrong"),y.data.m=null,v()):"BACKSPACE"==a.key.toUpperCase()?(y.b.classList.remove("cell-letter-wrong"),y.data.m=
+null,z(-1),v()):1===a.key.length&&(a=a.key.charAt(0).toUpperCase(),a.match(/[A-Z]/)&&(y.data.m=a,S(a),v(),z(1))))}),M())});

+ 35 - 6
src/Grid.js

@@ -37,8 +37,12 @@ LetterCell.prototype.toStatic = function() {
 };
 
 LetterCell.prototype.setFound = function(playerId, t) {
-    this.found = playerId;
-    this.version = Math.max(this.version, t);
+    if (!this.found) {
+        this.found = playerId;
+        this.version = Math.max(this.version, t);
+        return true;
+    }
+    return false;
 };
 
 function Definition(position, alignment, text) {
@@ -141,13 +145,15 @@ DefinitionCell.prototype.toStatic = function() {
 function parseGrid(grid, definitions, w, h) {
     var currentDefinition = 0
         ,resultGrid = []
-        ,firstCharCode = 'a'.charCodeAt(0);
+        ,firstCharCode = 'a'.charCodeAt(0)
+        ,letterCellCount = 0;
 
     for (let i =0; i < h; i++) {
         for (let j =0; j < w; j++) {
             let c = grid[i][j];
             if (c == c.toUpperCase()) {
                 resultGrid.push(new LetterCell(j, i, c));
+                letterCellCount++;
             } else if (c == 'z') {
                 resultGrid.push(new EmptyCell(j, i));
             } else {
@@ -157,7 +163,10 @@ function parseGrid(grid, definitions, w, h) {
             }
         }
     }
-    return resultGrid;
+    return {
+        grid: resultGrid
+        ,nbLetters: letterCellCount
+    };
 }
 
 function Player(t) {
@@ -165,16 +174,25 @@ function Player(t) {
     this.version = t;
 }
 
+Player.prototype.putScore = function(scoreInc, t) {
+    this.score += scoreInc;
+    this.version = Math.max(this.version, t);
+};
+
 function Grid(publicId, data) {
     this.title = data["titre"];
     this.difficulty = data["force"];
     this.width = data["nbcaseslargeur"];
     this.height = data["nbcaseshauteur"];
-    this.grid = parseGrid(data["grille"], data["definitions"], this.width, this.height);
+    var gridInf = parseGrid(data["grille"], data["definitions"], this.width, this.height);
+    this.grid = gridInf.grid;
+    this.remainingCells = gridInf.nbLetters;
     this.publicId = publicId;
     this.minVersion = 0;
     /** @type {Object.<string, Player>} playerId -> score */
     this.players = {};
+    /** @type {number|null} grid termination time */
+    this.closureTime = null;
 };
 
 Grid.colors = shuffleArray([ "007b00", "00407b", "42007b", "7b0059", "7b0000", "00747b", "007b39", "7b6300", "ff5f5f", "5c7cff" ]);
@@ -227,6 +245,14 @@ Grid.prototype.generateNewPlayerId = function() {
     return playerName +'|' +Grid.colors[Object.keys(this.players).length % Grid.colors.length];
 };
 
+Grid.prototype.setFound = function(cell, playerId, t) {
+    if (cell.setFound(playerId, t)) {
+        this.remainingCells--;
+        if (!this.remainingCells)
+            this.closureTime = t;
+    }
+};
+
 Grid.prototype.registerNewPlayer = function(t) {
     var playerId = this.generateNewPlayerId();
     this.players[playerId] = new Player(t);
@@ -255,6 +281,9 @@ Grid.prototype.toStatic = function(v) {
             maxV = Math.max(cell.version, maxV);
         }
     });
+    if (this.closureTime && this.closureTime > v) {
+        ret.gridTime = this.closureTime -this.minVersion;
+    }
     if (grid.length)
         ret.grid = grid;
     for (var i in this.players) {
@@ -270,7 +299,7 @@ Grid.prototype.toStatic = function(v) {
         }
     }
     ret.v = maxV;
-    return ret.grid || !v || ret.players ? ret : null;
+    return Object.keys(ret).length > 0 ? ret : null;
 };
 
 module.exports.Grid = Grid;

+ 6 - 3
src/httpServer.js

@@ -5,6 +5,9 @@ const http = require('http')
     ,GridManager = require('./GridManager.js')
     ,LetterCell = require('./Grid.js').LetterCell;
 
+const SCORE_ON_FAIL = -1
+    ,SCORE_ON_SUCCESS = 3;
+
 function HttpServer(config) {
     var ctx = this;
 
@@ -175,13 +178,13 @@ HttpServer.prototype.serveApi = function(req, url, res) {
             return;
         }
         if (cell.letter !== urlToken["key"][0]) {
-            //TODO lower player score
+            playerObj.putScore(SCORE_ON_FAIL, req.reqT.getTime());
             res.writeHeader("403");
             res.end();
             return;
         }
-        // TODO inc player score
-        cell.setFound(playerID, req.reqT.getTime());
+        playerObj.putScore(SCORE_ON_SUCCESS, req.reqT.getTime());
+        grid.setFound(cell, playerID, req.reqT.getTime());
         res.writeHeader("204");
         res.end();
     } else if (url === "register") {