summaryrefslogtreecommitdiff
path: root/codenames/assets/js
diff options
context:
space:
mode:
Diffstat (limited to 'codenames/assets/js')
-rw-r--r--codenames/assets/js/codenames.js249
1 files changed, 202 insertions, 47 deletions
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