diff options
| author | Botond Hende <nettingman@gmail.com> | 2026-02-18 00:53:31 +0100 |
|---|---|---|
| committer | Botond Hende <nettingman@gmail.com> | 2026-02-18 00:53:31 +0100 |
| commit | 5a866b9b129479de85e892752fd6ede6627cee55 (patch) | |
| tree | 2d616d439232ec112b4750bf118852477819daca /codenames/assets | |
| parent | cc6bdc68cb3ed40a6e51f885ea1c7c7a4e5fa6c5 (diff) | |
Diffstat (limited to 'codenames/assets')
| -rw-r--r-- | codenames/assets/css/codenames.css | 12 | ||||
| -rw-r--r-- | codenames/assets/js/codenames.js | 249 |
2 files changed, 214 insertions, 47 deletions
diff --git a/codenames/assets/css/codenames.css b/codenames/assets/css/codenames.css index db3fb71..30ec0ee 100644 --- a/codenames/assets/css/codenames.css +++ b/codenames/assets/css/codenames.css @@ -26,3 +26,15 @@ div.red { div.blue { background: blue; } + +.game-mode-0, +.game-mode-1, +.game-mode-2 { + display: none; +} + +html[data-game-mode="0"] .game-mode-0, +html[data-game-mode="1"] .game-mode-1, +html[data-game-mode="2"] .game-mode-2 { + display: inherit; +}
\ No newline at end of file diff --git a/codenames/assets/js/codenames.js b/codenames/assets/js/codenames.js index c838b48..c4c5f46 100644 --- a/codenames/assets/js/codenames.js +++ b/codenames/assets/js/codenames.js @@ -1,11 +1,13 @@ "use strict" +const GAME_MODE_KEY = "data-game-mode"; + const Tile = Object.freeze({ - NEUTRAL: 0, - BLACK: 1, - GREEN: 2, - RED: 3, - BLUE: 4, + NEUTRAL: 0, + BLACK: 1, + GREEN: 2, + RED: 3, + BLUE: 4, }); function cyrb128(str) { @@ -81,6 +83,7 @@ function getPosIndexByValue(array, pos) { return -1; } +// TODO: handle multiple rounds and memoize function generateDuetGrids(width, height, greenCount, blackCount, commonGreenCount, commonBlackCount, blackGreenCount, seed) { let seed_array = cyrb128(seed); let rand = sfc32(seed_array[0], seed_array[1], seed_array[2], seed_array[3]); @@ -153,59 +156,211 @@ function generateDuetGrids(width, height, greenCount, blackCount, commonGreenCou return [p1, p2]; } -function parseAndGenerateDuet() +function isValidUrl(params) { + if (!params.has("gm") || !params.has("w") || !params.has("h") || !params.has("b") || !params.has("s")) { + return false; + } + + switch (params.get("gm")) { + case "0": + if (!params.has("rb")) { + return false; + } + break; + case "1": + if (!params.has("cg") || !params.has("cb") || !params.has("bg")) { + return false; + } + // fallthrough + case "2": + if (!params.has("g") || !params.has("p")) { + return false; + } + break; + default: + return false; + } + + return true; +} + +function parseUrlAndGenerate() { let params = new URLSearchParams(window.location.search); - if (params.has("w") && params.has("h") && params.has("g") && params.has("b") && - params.has("cg") && params.has("cb") && params.has("bg") && params.has("s")) { - return generateDuetGrids(+params.get("w"), +params.get("h"), +params.get("g"), +params.get("b"), - +params.get("cg"), +params.get("cb"), +params.get("bg"), params.get("s")); + if (!isValidUrl(params)) + return null; + + switch (params.get("gm")) { + case "1": + return generateDuetGrids(+params.get("w"), +params.get("h"), +params.get("g"), +params.get("b"), + +params.get("cg"), +params.get("cb"), +params.get("bg"), decodeURI(params.get("s"))); } return null; } -function generate_for_current_page() { - const duetP1 = document.getElementById("duet_p1"); - const duetP2 = document.getElementById("duet_p2"); - if (duetP1 !== null || duetP2 !== null) { - let grids = parseAndGenerateDuet(); - if (grids == null) { - return; - } +function drawMap(grid, map, increment) { + let rowIdx = (increment > 0) ? 0 : map.length - 1; + let rowEndIdx = (increment > 0) ? map.length : -1; - const gridRoot = duetP1; - let grid = grids[0]; + while (rowIdx !== rowEndIdx) { + let row = map[rowIdx]; + let rowDiv = document.createElement("div"); + rowDiv.classList.add("tile_row"); + grid.appendChild(rowDiv); - for (let ii = 0; ii < grid.length; ii++) { - let row = grid[ii]; - let rowDiv = document.createElement("div"); - rowDiv.classList.add("tile_row"); - gridRoot.appendChild(rowDiv); - for (let jj = 0; jj < row.length; jj++) { - let tileDiv = document.createElement("div"); - tileDiv.classList.add("tile"); - rowDiv.appendChild(tileDiv); - switch (grid[ii][jj]) { - case Tile.NEUTRAL: - tileDiv.classList.add("neutral"); - break; - case Tile.BLACK: - tileDiv.classList.add("black"); - break; - case Tile.GREEN: - tileDiv.classList.add("green"); - break; - case Tile.RED: - tileDiv.classList.add("red"); - break; - case Tile.BLUE: - tileDiv.classList.add("blue"); - break; - } + let columnIdx = (increment > 0) ? 0 : row.length - 1; + let columnEndIdx = (increment > 0) ? row.length : -1; + + while (columnIdx !== columnEndIdx) { + let tileDiv = document.createElement("div"); + tileDiv.classList.add("tile"); + rowDiv.appendChild(tileDiv); + switch (map[rowIdx][columnIdx]) { + case Tile.NEUTRAL: + tileDiv.classList.add("neutral"); + break; + case Tile.BLACK: + tileDiv.classList.add("black"); + break; + case Tile.GREEN: + tileDiv.classList.add("green"); + break; + case Tile.RED: + tileDiv.classList.add("red"); + break; + case Tile.BLUE: + tileDiv.classList.add("blue"); + break; } + + columnIdx += increment; + } + + rowIdx += increment; + } +} + +function generateMapsFromUrl() { + const grid1 = document.getElementById("grid_p1"); + const grid2 = document.getElementById("grid_p2"); + + if (grid1 != null) { + grid1.innerHTML = ""; + } + if (grid2 != null) { + grid2.innerHTML = ""; + } + + let generatedMaps = parseUrlAndGenerate(); + if (generatedMaps == null) { + return; + } + + let player = new URLSearchParams(window.location.search).get("p"); + if (player === "0" || player === "2") { + drawMap(grid1, generatedMaps[0], 1); + } + + if (player === "1" || player === "2") { + drawMap(grid2, generatedMaps[1], -1); + } +} + +function getPlayer() { + return document.querySelector('input[name="p"]:checked').value; +} + +function getGameIntParam(key) { + return parseInt(document.getElementById(key).value) || 0; +} + +// TODO: warn about bad inputs +function parseInputAndSetUrl() { + let params = new URLSearchParams(); + let gamemode = document.documentElement.getAttribute(GAME_MODE_KEY); + params.append("gm", gamemode); + params.append("s", encodeURI(document.getElementById("s").value)); + params.append("w", getGameIntParam("w")); + params.append("h", getGameIntParam("h")); + params.append("b", getGameIntParam("b")); + switch (gamemode) { + case "0": // NORMAL + params.append("rb", getGameIntParam("rb")); + break; + + case "1": // DUET + params.append("cg", getGameIntParam("cg")); + params.append("cb", getGameIntParam("cb")); + params.append("bg", getGameIntParam("bg")); + // fallthrough + + case "2": // DUET MAYHEM + params.append("g", getGameIntParam("g")); + params.append("p", getPlayer()); + break; + } + + history.pushState({}, "", window.location.origin + window.location.pathname + "?" + params.toString()); + return true; +} + +function onGenerateButton() { + if (parseInputAndSetUrl()) { + generateMapsFromUrl(); + } +} + +function onSetGameMode(mode) { + document.documentElement.setAttribute(GAME_MODE_KEY, mode) + if (mode === 0) { + document.getElementById("b").value = 1; + } + else { + document.getElementById("b").value = 3; + } +} + +function onRandomSeed() { + let result = ''; + const characters = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const charactersLength = characters.length; + for (let i = 0; i < 10; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + + document.getElementById("s").value = result; +} + +function setParamsFromUrl(params) { + params.entries().forEach(function (item) { + if (item[0] === "s") { + document.getElementById("s").value = decodeURI(item[1]); } + else if (item[0] === "gm") { + onSetGameMode(parseInt(item[1])); + } + else if (item[0] === "p") { + document.getElementById("p" + item[1]).click(); + } + else { + document.getElementById(item[0]).value = parseInt(item[1]); + } + }) +} + +function initPage() { + let params = new URLSearchParams(window.location.search); + if (isValidUrl(params)) { + setParamsFromUrl(params); + generateMapsFromUrl(); + } + else { + onSetGameMode(0); + onRandomSeed(); + onGenerateButton(); } } -generate_for_current_page();
\ No newline at end of file +initPage();
\ No newline at end of file |
