From: Laurent Mazet Date: Thu, 22 Apr 2021 22:01:03 +0000 (+0200) Subject: add new boards (8x8 and 22x22) X-Git-Url: https://secure.softndesign.org/git/?a=commitdiff_plain;h=d51ae94441573e2e544e5e0f905a052215451452;p=trivabble.git add new boards (8x8 and 22x22) --- diff --git a/l10n/po/fr/trivabble.po b/l10n/po/fr/trivabble.po index 5e4bded..b8114ce 100644 --- a/l10n/po/fr/trivabble.po +++ b/l10n/po/fr/trivabble.po @@ -166,11 +166,11 @@ msgstr "Êtes-vous sûr·e de vouloir de changer la langue du plateau à '{0}' ? msgid "Board language:" msgstr "Langue du plateau :" -msgid "You changed the language of the board to {0}" -msgstr "Vous avez changé la langue du plateau en {0}" +msgid "You changed the board to {0}x{0} for language {1}" +msgstr "Vous avez changé le plateau pour {0}x{0} en {1}" -msgid "{0} changed the language of the board to {1}" -msgstr "{0} a changé la langue du plateau en {1}" +msgid "{0} changed the board to {1}x{1} for language {2}" +msgstr "{0} a changé le plateau pour {1}x{1} en {2}" msgid "Settings" msgstr "Paramètres" @@ -261,3 +261,10 @@ msgstr "Chronométrer la partie" msgid "To measure playing time, activate the timer." msgstr "Pour mesurer les temps de jeu, activez le chronomètre." + +msgid "Board size:" +msgstr "Taille du plateau" + +msgid "Are you sure you want to change board to {0}x{0}? This will put all the tiles back in the bag and start another game." +msgstr "Êtes-vous sûr·e de vouloir de changer la taille du plateau à {0}x{0} ? Cela remettra toutes les lettres du jeu dans le sac et commencera une nouvelle partie." + diff --git a/l10n/pot/trivabble.pot b/l10n/pot/trivabble.pot index 89eb0b8..4714921 100644 --- a/l10n/pot/trivabble.pot +++ b/l10n/pot/trivabble.pot @@ -172,10 +172,10 @@ msgstr "" msgid "Board language:" msgstr "" -msgid "You changed the language of the board to {0}" +msgid "You changed the board to {0}x{0} for language {1}" msgstr "" -msgid "{0} changed the language of the board to {1}" +msgid "{0} changed the board to {1}x{1} for language {2}" msgstr "" msgid "Settings" @@ -266,3 +266,9 @@ msgstr "" msgid "To measure playing time, activate the timer." msgstr "" + +msgid "Board size:" +msgstr "" + +msgid "Are you sure you want to change board to {0}x{0}? This will put all the tiles back in the bag and start another game." +msgstr "" diff --git a/public/boards.js b/public/boards.js new file mode 100644 index 0000000..0eb4ac8 --- /dev/null +++ b/public/boards.js @@ -0,0 +1,100 @@ +window.BoardList = { + "8x8": { + TW: [ + "A1", "A8", + "H1", "H8" + ], + DW: [ + "B2", "B7", + "E5", + "G2", "G7" + ], + TL: [ + "B5", + "E2", + "D7", + "G4" + ], + DL: [ + "A4", + "C3", "C6", + "D1", + "E8", + "F3", "F6", + "H5" + ], + CS: [ + "D4" + ] + }, + "15x15": { + TW: ["A1", "A8", "A15", "H1", "H15", "O1", "O8", "O15"], + DW: ["B2", "B14", "C3", "C13", "D4", "D12", "E5", "E11", "K5", "K11", "L4", "L12", "M3", "M13", "N2", "N14"], + TL: ["B6", "B10", "F2", "F6", "F10", "F14", "J2", "J6", "J10", "J14", "N6", "N10"], + DL: ["A4", "A12", "C7", "C9", "D1", "D8", "D15", "G3", "G7", "G9", "G13", "H4", "H12", "I3", "I7", "I9", "I13", "L1", "L8", "L15", "M7", "M9", "O4", "O11"], + CS: ["H8"] + }, + "22x22": { + TW: [ + "A1", "A8", "A15", "A22", + "H1", "H8", "H15", "H22", + "O1", "O8", "O15", "O22", + "V1", "V8", "V15", "V22" + ], + DW: [ + "B2", "B10", "B21", + "C3", "C20", + "D4", "D12", "D19", + "E5", "E18", + "I9", "I14", + "J21", + "K4", + "L12", "L19", + "M2", + "N9", "N14", + "R5", "R18", + "S4", "S11", "S19", + "T3", "T20", + "U2", "U13", "U21" + ], + TL: [ + "B6", "B17", + "E14", + "F2", "F6", "F10", "F17", "F21", + "I5", + "J13", "J17", + "M6", "M10", + "N18", + "Q2", "Q6", "Q13", "Q17", "Q21", + "R9", + "U6", "U17" + ], + DL: [ + "A4", "A12", "A19", + "B13", + "C7", "C11", "C16", + "D1", "D8", "D15", "D22", + "E9", + "F13", + "G3", "G7", "G11", "G16", "G20", + "H4", "H12", "H19", + "I18", + "J2", "J6", "J10", + "K1", "K8", "K16", "K20", + "L3", "L7", "L15", "L22", + "M13", "M17", "M21", + "N5", + "O4", "O11", "O19", + "P3", "P7", "P12", "P16", "P20", + "Q10", + "R14", + "S1", "S8", "S15", "S22", + "T7", "T12", "T16", + "U10", + "V4", "V11", "V19" + ], + CS: [ + "K11" + ] + } +}; diff --git a/public/index.html b/public/index.html index 8d046a0..6d4244e 100644 --- a/public/index.html +++ b/public/index.html @@ -8,6 +8,7 @@ + @@ -30,7 +31,7 @@
-
+

+

+ + +

diff --git a/public/trivabble.js b/public/trivabble.js index 1bfe8d6..c849d88 100644 --- a/public/trivabble.js +++ b/public/trivabble.js @@ -33,6 +33,8 @@ const DictionaryList = window.DictionaryList || {}; + const BoardList = window.BoardList || {}; + function setConf(parameterName, defaultValue) { if (typeof Conf[parameterName] === "undefined") { Conf[parameterName] = defaultValue; @@ -150,6 +152,7 @@ DisableSpellChecker: "boolean", GameNumber: "number", BoardLang: "string", + BoardSize: "number", Lang: "string", PlayerName: "string", Timer: "number", @@ -166,9 +169,9 @@ function format(s, v1, v2, v3) { return s - .replace("{0}", v1) - .replace("{1}", v2) - .replace("{2}", v3); + .replace(/\{0\}/gu, v1) + .replace(/\{1\}/gu, v2) + .replace(/\{2\}/gu, v3); } let board; @@ -177,6 +180,7 @@ let scoreOf; let bag; let boardLangSelect; + let boardSizeSelect; const downloadedDictionaries = {}; const playerLetters = []; @@ -751,7 +755,7 @@ } function setBoard(board) { - for (let i = 0; i < 15 * 15; i++) { + for (let i = 0; i < getSetting("BoardSize") * getSetting("BoardSize"); i++) { setCell(i, board[i]); } } @@ -771,6 +775,11 @@ setSetting("BoardLang", value); checkDictionaryExistance(value); break; + case "boardSize": + document.getElementById("board-size").value = value; + setSetting("BoardSize", value); + initBoard(value); + break; } } @@ -903,12 +912,13 @@ return; } - case "changeBoardLang": { + case "changeBoardDef": { const newLang = boardLangSelect.querySelector("[value=" + msg.specialMsg.newBoardLang + "]").textContent; + const newSize = msg.specialMsg.newBoardSize; infoMessage( (msg.sender === getSetting("PlayerName")) - ? format(_("You changed the language of the board to {0}"), newLang) - : format(_("{0} changed the language of the board to {1}"), msg.sender, newLang) + ? format(_("You changed the board to {0}x{0} for language {1}"), newSize, newLang) + : format(_("{0} changed the board to {1}x{1} for language {2}"), msg.sender, newSize, newLang) ); break; } @@ -1209,6 +1219,11 @@ set("boardLang", data.boardLang); (boardLangSelect || {}).value = data.boardLang; } + + if (data.boardSize) { + set("boardSize", Number(data.boardSize)); + (boardSizeSelect || {}).value = data.boardSize; + } if (data.letterValues) { scoreOf = data.letterValues; @@ -1498,6 +1513,7 @@ gameNumber: getSetting("GameNumber") || "", playerName: getSetting("PlayerName"), boardLang: getSetting("BoardLang"), + boardSize: getSetting("BoardSize"), version: VERSION, cmds: cmds }; @@ -1639,13 +1655,27 @@ myConfirm( format(_("Are you sure you want to change board to '{0}'? This will put all the tiles back in the bag and start another game."), _(lang)), function () { - sendCmds([{cmd: "changeBoard", lang: code}]); + sendCmds([{cmd: "changeBoard", lang: code, size: getSetting("BoardSize")}]); }, function () { boardLangSelect.value = getSetting("BoardLang"); } ); } + + function onChangeBoardSize() { + const size = document.getElementById("board-size").value; + + myConfirm( + format(_("Are you sure you want to change board to {0}x{0}? This will put all the tiles back in the bag and start another game."), size), + function () { + sendCmds([{cmd: "changeBoard", lang: getSetting("BoardLang"), size: size}]); + }, + function () { + boardSizeSelect.value = getSetting("BoardLang"); + } + ); + } function clearRack() { myConfirm( @@ -1709,11 +1739,11 @@ } function getLetterFromBoard(row, col) { - if ((row < 0) || (row >= 15) || (col < 0) || (col >= 15)) { + if ((row < 0) || (row >= getSetting("BoardSize")) || (col < 0) || (col >= getSetting("BoardSize"))) { return ""; } try { - const index = (row * 15) + col; + const index = (row * getSetting("BoardSize")) + col; const tilePlaceholder = boardCells[index].getElementsByClassName("tile-placeholder")[0]; const tile = tilePlaceholder.getElementsByClassName("tile")[0]; return tile.firstChild.textContent; @@ -1764,8 +1794,8 @@ for (const i of Object.keys(currentTilePlayed)) { /* Get board position */ - const row = Math.floor(i / 15); - const col = i % 15; + const row = Math.floor(i / getSetting("BoardSize")); + const col = i % getSetting("BoardSize"); /* Look for word in column */ const newWordInCol = searchWordInLine(row, col, 1, 0); @@ -1798,7 +1828,7 @@ /* only for new words */ for (let l = 0; l < word.letters.length; l++) { - const index = ((word.row + (l * word.incRow)) * 15) + word.col + (l * word.incCol); + const index = ((word.row + (l * word.incRow)) * getSetting("BoardSize")) + word.col + (l * word.incCol); const tilePlaceholder = boardCells[index].getElementsByClassName("tile-placeholder")[0]; const tile = tilePlaceholder.getElementsByClassName("tile")[0]; @@ -1808,7 +1838,7 @@ } else { /* tiles on board */ - for (let index = 0; index < 15 * 15; index++) { + for (let index = 0; index < getSetting("BoardSize") * getSetting("BoardSize"); index++) { const tilePlaceholder = boardCells[index].getElementsByClassName("tile-placeholder")[0]; const tile = tilePlaceholder.getElementsByClassName("tile")[0]; if (typeof tile !== "undefined") { @@ -1898,7 +1928,7 @@ const word = newWords[k]; for (let l = 0; l < word.letters.length; l++) { - const index = ((word.row + (l * word.incRow)) * 15) + word.col + (l * word.incCol); + const index = ((word.row + (l * word.incRow)) * getSetting("BoardSize")) + word.col + (l * word.incCol); /* Letter score */ const tilePlaceholder = boardCells[index].getElementsByClassName("tile-placeholder")[0]; @@ -1971,7 +2001,7 @@ return; } - const letters = "ABCDEFGHIJKLMNO"; + const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const col = cell.cellIndex - 1; const row = getRowIndex(cell.parentNode) - 1; @@ -1980,7 +2010,7 @@ msg: _("Look at:") + " " + letters[row] + (cell.cellIndex + 1), specialMsg: { type: "highlightCell", - cell: (row * 15) + col + cell: (row * getSetting("BoardSize")) + col } }]); } @@ -2382,6 +2412,7 @@ chatMessages = document.getElementById("chat-messages"); chatTextarea = document.getElementById("chat-ta"); participantPlaceholder = document.getElementById("participants-placeholder"); + boardSizeSelect = document.getElementById("board-size"); } function initEvents() { @@ -2389,6 +2420,7 @@ document.getElementById("clear-game").onclick = clearGame; document.getElementById("board-lang").onchange = onChangeBoardLang; + document.getElementById("board-size").onchange = onChangeBoardSize; document.getElementById("change-name").onclick = changeName; document.getElementById("join-game").onclick = joinGame; document.getElementById("clear-rack").onclick = clearRack; @@ -2423,25 +2455,6 @@ name.textContent = getSetting("PlayerName"); - const letters = "ABCDEFGHIJKLMNO"; - - const doubleLetter = { - "0,3": true, - "0,11": true, - "2,6": true, - "2,8": true, - "3,0": true, - "3,7": true, - "3,14": true, - "6,2": true, - "6,6": true, - "6,8": true, - "6,12": true - }; - - let cell; - let row; - for (let i = 0; i < 7; i++) { const span = document.createElement("span"); span.className = "tile-placeholder"; @@ -2449,7 +2462,34 @@ playerLetters.push(span); } - for (let i = 0; i < 15; i++) { + + if (getSetting("GameNumber")) { + document.getElementById("number").textContent = getSetting("GameNumber"); + } + + if (getSetting("BoardLang")) { + document.getElementById("board-lang").value = getSetting("BoardLang"); + } + + if (getSetting("BoardSize")) { + document.getElementById("board-size").value = getSetting("BoardSize"); + } + + startGame(getSetting("GameNumber")); + } + + function initBoard(boardSize) { + + const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + const boardDef = BoardList[boardSize + "x" + boardSize]; + + let cell; + let row; + + board.innerHTML = ""; + + for (let i = 0; i < boardSize; i++) { board.rows[0].appendChild(document.createElement("th")); board.rows[0].lastChild.textContent = i + 1; @@ -2457,7 +2497,7 @@ row.appendChild(document.createElement("th")); row.lastChild.textContent = letters[i]; - for (let j = 0; j < 15; j++) { + for (let j = 0; j < boardSize; j++) { cell = document.createElement("td"); boardCells.push(cell); row.appendChild(cell); @@ -2465,18 +2505,19 @@ cell.appendChild(document.createElement("div")); cell.lastChild.className = "tile-placeholder"; - if (i === j && i === 7) { + const cellName = letters[i] + (j + 1); + if (boardDef.CS.indexOf(cellName) !== -1) { specialCell("doubleWord", row.lastChild); cell = row.lastChild.getElementsByClassName("special-cell-label")[0]; cell.textContent = "★"; row.lastChild.id = "center-cell"; - } else if (i % 7 === 0 && j % 7 === 0) { + } else if (boardDef.TW.indexOf(cellName) !== -1) { specialCell("tripleWord", row.lastChild); - } else if ((i === j || i + j === 14) && (i < 5 || i > 9)) { + } else if (boardDef.DW.indexOf(cellName) !== -1) { specialCell("doubleWord", row.lastChild); - } else if ((i % 4 === 1) && (j % 4 === 1)) { + } else if (boardDef.TL.indexOf(cellName) !== -1) { specialCell("tripleLetter", row.lastChild); - } else if ((i < 8 && doubleLetter[i + "," + j]) || (i > 7 && doubleLetter[(14 - i) + "," + j]) || (i === 7 && (j === 3 || j === 11))) { + } else if (boardDef.DL.indexOf(cellName) !== -1) { specialCell("doubleLetter", row.lastChild); } } @@ -2490,22 +2531,12 @@ row = board.insertRow(-1); row.appendChild(board.rows[0].cells[0].cloneNode(false)); - for (let i = 0; i < 15; i++) { + for (let i = 0; i < boardSize; i++) { row.appendChild(document.createElement("th")); row.lastChild.textContent = i + 1; } row.appendChild(board.rows[0].cells[0].cloneNode(false)); - - if (getSetting("GameNumber")) { - document.getElementById("number").textContent = getSetting("GameNumber"); - } - - if (getSetting("BoardLang")) { - document.getElementById("board-lang").value = getSetting("BoardLang"); - } - - startGame(getSetting("GameNumber")); } function initLang() { diff --git a/server/trivabble-server.js b/server/trivabble-server.js index a5b19a2..8e916c5 100644 --- a/server/trivabble-server.js +++ b/server/trivabble-server.js @@ -35,6 +35,7 @@ const SAVE_TIMEOUT = 5000; const KEEP_ALIVE = 30000; const GAMES_BACKUP = process.env.TRIVABBLE_GAMES_BACKUP || "games.backup.json"; const DEFAULT_BOARD_LANG = process.env.TRIVABBLE_DEFAULT_BOARD_LANG || "fr"; +const DEFAULT_BOARD_SIZE = process.env.TRIVABBLE_DEFAULT_BOARD_SIZE || 15; const VERSION = 202005070100; @@ -206,18 +207,19 @@ function keepAlive(responseAndType) { }, KEEP_ALIVE); } -function newBoard() { - const res = new Array(15 * 15); +function newBoard(size) { + const res = new Array(size * size); - for (let i = 0; i < 15 * 15; i++) { + for (let i = 0; i < size * size; i++) { res[i] = ""; } return res; } -Game.prototype.init = function (lang) { - this.board = newBoard(); +Game.prototype.init = function (lang, size) { + this.size = size || DEFAULT_BOARD_SIZE; + this.board = newBoard(this.size); this.lang = lang || DEFAULT_BOARD_LANG; this.bag = boardTilesPerLang[this.lang].bag.slice(); this.letterValues = boardTilesPerLang[this.lang].letterValues; @@ -233,6 +235,7 @@ Game.prototype.toJSON = function () { return { board: this.board, lang: this.lang, + size: this.size, bag: this.bag, letterValues: this.letterValues, racks: this.racks, @@ -244,7 +247,8 @@ Game.prototype.toJSON = function () { Game.fromJSON = function (obj) { const game = new Game(); - game.board = obj.board || newBoard(); + game.size = obj.size || DEFAULT_BOARD_SIZE; + game.board = obj.board || newBoard(game.size); game.lang = obj.lang || DEFAULT_BOARD_LANG; game.bag = boardTilesPerLang[game.lang].bag.slice(); game.letterValues = boardTilesPerLang[game.lang].letterValues; @@ -402,11 +406,12 @@ Game.prototype.bagPushLetter = function (letter, player) { }; Game.prototype.reset = function (player) { - this.init(this.lang); + this.init(this.lang, this.size); this.pendingEvents.push({ player: player, action: "reset", board: this.board, + size: this.size, remainingLetters: this.bag.length, rack: [] }); @@ -483,6 +488,7 @@ function handleCommand(cmdNumber, message, response) { gameNumber: gameNumber, playerName: playerName, boardLang: game.lang, + boardSize: game.size, availableBoardLangs: availableBoardLangs, currentPlayer: game.currentPlayer, rack: game.getPlayerRack(playerName), @@ -496,7 +502,7 @@ function handleCommand(cmdNumber, message, response) { case "hello": { game.playerJoined(playerName); - reply(message, response, cmdNumber, {error: 0, boardLang: game.lang, version: VERSION}); + reply(message, response, cmdNumber, {error: 0, boardLang: game.lang, boardSize: game.size, version: VERSION}); break; } @@ -542,7 +548,7 @@ function handleCommand(cmdNumber, message, response) { break; case "board": - if (cmd.indexFrom < 0 || cmd.indexFrom >= 15 * 15) { + if (cmd.indexFrom < 0 || cmd.indexFrom >= game.size * game.size) { reply(message, response, cmdNumber, {error: 1, reason: "Wrong indexFrom"}); return false; } @@ -587,7 +593,7 @@ function handleCommand(cmdNumber, message, response) { break; case "board": - if (cmd.indexTo < 0 || cmd.indexTo >= 15 * 15) { + if (cmd.indexTo < 0 || cmd.indexTo >= game.size * game.size) { reply(message, response, cmdNumber, {error: 1, reason: "Wrong indexTo"}); return false; } @@ -675,21 +681,24 @@ function handleCommand(cmdNumber, message, response) { case "changeBoard": { game.lang = cmd.lang || DEFAULT_BOARD_LANG; + game.size = cmd.size || DEFAULT_BOARD_SIZE; game.reset(); reply(message, response, cmdNumber, { error: 0, boardLang: game.lang, + boardSize: game.size, letterValues: game.letterValues }); game.pendingEvents.push({ msg: { sender: playerName, - content: "I changed the language of the board to " + game.lang, + content: "I changed the board to " + game.size + "x" + game.size + " in language " + game.lang, specialMsg: { - type: "changeBoardLang", - newBoardLang: game.lang + type: "changeBoardDef", + newBoardLang: game.lang, + newBoardSize: game.size } } }); @@ -730,6 +739,7 @@ function handleCommands(message, responseAndType) { currentPlayer: game.currentPlayer, gameNumber: gameNumber, boardLang: game.lang, + boardSize: game.size, availableBoardLangs: availableBoardLangs, letterValues: game.letterValues, rack: game.getPlayerRack(message.playerName),