"use strict" const Tile = Object.freeze({ NEUTRAL: 0, BLACK: 1, GREEN: 2, RED: 3, BLUE: 4, }); function cyrb128(str) { let h1 = 1779033703, h2 = 3144134277, h3 = 1013904242, h4 = 2773480762; for (let i = 0, k; i < str.length; i++) { k = str.charCodeAt(i); h1 = h2 ^ Math.imul(h1 ^ k, 597399067); h2 = h3 ^ Math.imul(h2 ^ k, 2869860233); h3 = h4 ^ Math.imul(h3 ^ k, 951274213); h4 = h1 ^ Math.imul(h4 ^ k, 2716044179); } h1 = Math.imul(h3 ^ (h1 >>> 18), 597399067); h2 = Math.imul(h4 ^ (h2 >>> 22), 2869860233); h3 = Math.imul(h1 ^ (h3 >>> 17), 951274213); h4 = Math.imul(h2 ^ (h4 >>> 19), 2716044179); h1 ^= (h2 ^ h3 ^ h4), h2 ^= h1, h3 ^= h1, h4 ^= h1; return [h1>>>0, h2>>>0, h3>>>0, h4>>>0]; } function sfc32(a, b, c, d) { return function() { a |= 0; b |= 0; c |= 0; d |= 0; let t = (a + b | 0) + d | 0; d = d + 1 | 0; a = b ^ b >>> 9; b = c + (c << 3) | 0; c = (c << 21 | c >>> 11); c = c + t | 0; return (t >>> 0) / 4294967296; } } function shuffle(array, rand) { let currentIndex = array.length - 1; while (currentIndex !== 0) { let otherIndex = Math.floor(rand() * (currentIndex + 1)); [array[currentIndex], array[otherIndex]] = [array[otherIndex], array[currentIndex]]; currentIndex--; } } function generateEmptyGrid(width, height){ let grid = []; for (let ii = 0; ii < height; ii++) { let line = Array(width); line.fill(Tile.NEUTRAL); grid.push(line) } return grid; } function getPositions(width, height) { let positions = []; for (let ii = 0; ii < height; ii++) { for (let jj = 0; jj < width; jj++) { positions.push([ii, jj]); } } return positions; } function getPosIndexByValue(array, pos) { for (let ii = 0; ii < array.length; ii++) { if (array[ii][0] === pos[0] && array[ii][1] === pos[1]) { return ii; } } return -1; } 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]); let blackNeutralCount = blackCount - commonBlackCount - blackGreenCount; let greenNeutralCount = greenCount - commonGreenCount - blackGreenCount; let p1 = generateEmptyGrid(width, height); let p2 = generateEmptyGrid(width, height); let p1NeutralPositions = getPositions(width, height); let p2NeutralPositions = getPositions(width, height); shuffle(p1NeutralPositions, rand); shuffle(p2NeutralPositions, rand); let p1GreenPositions = []; let p1BlackPositions = []; // P1 generation for (let ii = 0; ii < greenCount; ii++) { let pos = p1NeutralPositions.pop(); p1GreenPositions.push(pos); p1[pos[0]][pos[1]] = Tile.GREEN; } for (let ii = 0; ii < blackCount; ii++) { let pos = p1NeutralPositions.pop(); p1BlackPositions.push(pos); p1[pos[0]][pos[1]] = Tile.BLACK; } // P2 BLACK generation for (let ii = 0; ii < commonBlackCount; ii++) { let pos = p1BlackPositions.pop(); p2NeutralPositions.splice(getPosIndexByValue(p2NeutralPositions, pos), 1); p2[pos[0]][pos[1]] = Tile.BLACK; } for (let ii = 0; ii < blackGreenCount; ii++) { let pos = p1GreenPositions.pop(); p2NeutralPositions.splice(getPosIndexByValue(p2NeutralPositions, pos), 1); p2[pos[0]][pos[1]] = Tile.BLACK; } for (let ii = 0; ii < blackNeutralCount; ii++) { let pos = p1NeutralPositions.pop(); p2NeutralPositions.splice(getPosIndexByValue(p2NeutralPositions, pos), 1); p2[pos[0]][pos[1]] = Tile.BLACK; } // P2 GREEN generation for (let ii = 0; ii < commonGreenCount; ii++) { let pos = p1GreenPositions.pop(); p2NeutralPositions.splice(getPosIndexByValue(p2NeutralPositions, pos), 1); p2[pos[0]][pos[1]] = Tile.GREEN; } for (let ii = 0; ii < blackGreenCount; ii++) { let pos = p1BlackPositions.pop(); p2NeutralPositions.splice(getPosIndexByValue(p2NeutralPositions, pos), 1); p2[pos[0]][pos[1]] = Tile.GREEN; } for (let ii = 0; ii < greenNeutralCount; ii++) { let pos = p1NeutralPositions.pop(); p2NeutralPositions.splice(getPosIndexByValue(p2NeutralPositions, pos), 1); p2[pos[0]][pos[1]] = Tile.GREEN; } return [p1, p2]; } function parseAndGenerateDuet() { 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")); } 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; } const gridRoot = duetP1; let grid = grids[0]; 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; } } } } } generate_for_current_page();