From: Raphaƫl Jakse Date: Wed, 15 Apr 2020 19:53:32 +0000 (+0200) Subject: Pre-shuffle the bag to avoids risks of nasty endless loops X-Git-Url: https://secure.softndesign.org/git/?a=commitdiff_plain;h=f8426578ad37d3d443bbf66eda9434a9e14f09e0;p=trivabble.git Pre-shuffle the bag to avoids risks of nasty endless loops --- diff --git a/trivabble-server.js b/trivabble-server.js index 858ec7c..f88b4bf 100644 --- a/trivabble-server.js +++ b/trivabble-server.js @@ -134,6 +134,18 @@ function saveGames(callback) { saveTimeout = null; } + +function shuffleInPlace(a) { + // https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array + + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + const x = a[i]; + a[i] = a[j]; + a[j] = x; + } +} + function Game() { this.letterValues = frValues; this.init(); @@ -247,31 +259,42 @@ function newBoard() { Game.prototype.init = function () { this.board = newBoard(); this.bag = frBag.slice(); - this.remainingLetters = this.bag.length; this.racks = {}; this.scores = {}; this.lastUpdated = new Date(); + + shuffleInPlace(this.bag); }; Game.prototype.toJSON = function () { return { - remainingLetters: this.remainingLetters, board: this.board, bag: this.bag, racks: this.racks, scores: this.scores, - lastUpdated: this.lastUpdated.toISOString() + lastUpdated: this.lastUpdated.toISOString(), + bagShuffled: true // Will be gone soon, needed for compatibility with saved games }; }; Game.fromJSON = function (obj) { + // WARNING: modifies the passed parameter because of the suffling. + // This is harmless here, and temporary anyway. + // Variable bagShuffled is soon to be gone. + const game = new Game(); game.board = obj.board || newBoard(); game.bag = obj.bag || frBag.slice(); - game.remainingLetters = obj.remainingLetters || game.bag.length; game.racks = obj.racks || {}; game.scores = obj.scores || {}; game.lastUpdated = obj.lastUpdated ? new Date(obj.lastUpdated) : new Date(); + + // To delete soon + if (!obj.bagShuffled) { + game.bag = game.bag.filter((tile) => tile !== ""); + shuffleInPlace(game.bag); + } + return game; }; @@ -377,21 +400,12 @@ Game.prototype.commit = function () { }; Game.prototype.bagPopLetter = function (player) { - if (this.remainingLetters) { - let letter = ""; - let index; - - while (letter === "") { - index = Math.floor(Math.random() * this.bag.length); - letter = this.bag[index]; - } - - this.bag[index] = ""; - this.remainingLetters--; + if (this.bag.length) { + const letter = this.bag.pop(); this.pendingEvents.push({ player: player, action: "popBag", - remainingLetters: this.remainingLetters + remainingLetters: this.bag.length }); return letter; @@ -416,20 +430,13 @@ Game.prototype.setCell = function (index, letter, player) { Game.prototype.bagPushLetter = function (letter, player) { if (letter) { - let index = 0; - - while (this.bag[index] !== "") { - index++; - } - - this.bag[index] = letter; - - this.remainingLetters++; + this.bag.push(letter); + shuffleInPlace(this.bag); this.pendingEvents.push({ player: player, action: "pushBag", - remainingLetters: this.remainingLetters + remainingLetters: this.bag.length }); } }; @@ -440,7 +447,7 @@ Game.prototype.reset = function (player) { player: player, action: "reset", board: this.board, - remainingLetters: this.remainingLetters, + remainingLetters: this.bag.length, rack: [] }); @@ -507,7 +514,7 @@ function handleCommand(cmd, gameNumber, playerName, response) { "playerName": playerName, "rack": game.getPlayerRack(playerName), "board": game.board, - "remainingLetters": game.remainingLetters, + "remainingLetters": game.bag.length, "letterValues": frValues }) ); @@ -604,7 +611,7 @@ function handleCommand(cmd, gameNumber, playerName, response) { from: cmd.from, to: cmd.to, indexFrom: typeof cmd.indexFrom === "number" ? cmd.indexFrom : -1, - remainingLetters: game.remainingLetters + remainingLetters: game.bag.length }) ); @@ -710,7 +717,7 @@ function handleCommands(cmds, responseAndType) { "letterValues": game.letterValues, "rack": game.getPlayerRack(cmds.playerName), "board": game.board, - "remainingLetters": game.remainingLetters + "remainingLetters": game.bag.length }) );