ARTICLE AD BOX
Before I explain my question it's important to note I have little to no coding knowledge and have only been using Google and intuition until now.
I'm trying to repurpose Minesweeper to be used as an obscured map in a puzzle I'm making. I've had the most success in a Google Sheets clone I found that was built with Google Apps Script. I've done almost everything I need so far but I'm unsure how to build a fixed map rather than one that’s randomly generated. Any guidence is greatly appreciated!
For added clarity: I really know next to nothing about coding. I didn’t even write the original program, I just found a functional Google Sheets mine sweeper clone, looked for patterns in the code, and experimented with adding/deleting/modifying it until I got what I wanted (resizing the board and make a second type of “mine”, exits). Now I just need to fix the coordinates of each mines and exits so that it’s the same every time it’s opened, no matter who opens it.
// . x S H E E T S W E E P E R x . // // by John Waktinson // @pents90 // // To play: // * Start with an empty spreadsheet, resize the cells so that they are roughly square. // * In the "Triggers" menu above, add a trigger to run "checkCells" in the spreadsheet upon cell edit. // * Finally, run 'startGame' function to play! // // Use 'f' to flag a square that has a mine, use ' ' (spacebar) to clear a square. // // Currently, it does not congratulate you when you win, so you're on your own there. // // Ignore that little number at the bottom of the game, that's just the random number seed. :( // // Adjust these three variables below to make the game tiny/epic and easy/hard. var WIDTH = 20; var HEIGHT = 20; var MINES = 69; var EXITS = 6 // Our own random number stuff (so that we can use a fixed seed) var A = 48271; var M = 2147483647; var Q = M/A; var R = M % A; var oneOverM = 1.0 / M; var seed; var sheet; var field; function onOpen() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var menuEntries = [{name: "navStart", functionName: "startGame"}]; ss.addMenu("bootMap", menuEntries); } function onEdit(event) { checkCells(); } function nextRandomNumber(){ var hi = seed / Q; var lo = seed % Q; var test = A * lo - R * hi; if(test > 0){ seed = test; } else { seed = test + M; } return (seed * oneOverM); } function rand(max){ return Math.floor(nextRandomNumber() * max); } // Call this to start a new game function startGame() { var d = new Date(); seed = 2345678901 + (d.getSeconds() * 0xFFFFFF) + (d.getMinutes() * 0xFFFF); sheet = SpreadsheetApp.getActiveSheet(); var seedCell = sheet.getRange(HEIGHT+1, 1); seedCell.setValue(seed); for (var x = 0; x < WIDTH; x++) { for (var y = 0; y < HEIGHT; y++) { var cell = sheet.getRange(y + 1, x + 1); cell.setValue('◻'); cell.setFontColor('black'); } } } // Builds the actual mine map function buildGame() { field = new Array(WIDTH); for (var i = 0; i < WIDTH; i++) { field[i] = new Array(HEIGHT); for (var j = 0; j < HEIGHT; j++) { field[i][j] = 0; } } for (var i = 0; i < EXITS; i++) { var x = Math.floor(rand(WIDTH)); var y = Math.floor(rand(HEIGHT)); field[x][y] = 2; } for (var i = 0; i < MINES; i++) { var x = Math.floor(rand(WIDTH)); var y = Math.floor(rand(HEIGHT)); field[x][y] = 1; } } // Reveals a single square function reveal(x, y) { var cell = sheet.getRange(y + 1, x + 1); var count = 0; for (var xx = x - 1; xx <= x + 1; xx++) { for (var yy = y - 1; yy <= y + 1; yy++) { if (xx >= 0 && xx < WIDTH && yy >=0 && yy < HEIGHT) { if (field[xx][yy] == 1) { count++; } } } } if (field[x][y] == 1) { cell.setValue('*'); cell.setFontColor('red'); } else if (count == 0) { cell.setValue(' '); } else { if (count == 1) { cell.setFontColor('#38761d'); } else if (count == 2) { cell.setFontColor('blue'); } else if (count == 3) { cell.setFontColor('orange'); } else if (count == 4) { cell.setFontColor('magenta'); } else if (count >= 5) { cell.setFontColor('purple'); } cell.setValue(count); } return count; } // Exposes a square, which may result in other squares being exposed if they are safe function expose(x, y) { var visited = new Array(); var queueX = new Array(); var queueY = new Array(); queueX[0] = x; queueY[0] = y; visited[x+':'+y] = true; var n = 1; while (n > 0) { x = queueX[n-1] y = queueY[n-1]; //Browser.msgBox("x=" + x +" and y="+y); n--; var count = reveal(x,y); if (count == 0) { for (var xx = x - 1; xx <= x + 1; xx++) { for (var yy = y - 1; yy <= y + 1; yy++) { if (xx >= 0 && xx < WIDTH && yy >=0 && yy < HEIGHT) { //var cell = sheet.getRange(yy+1, xx+1); if (!visited[xx+':'+yy]) { queueX[n] = xx; queueY[n] = yy; visited[xx+':'+yy] = true; n = n + 1; } } } } } } } // Callback after the user edits. If the user puts 'f' in the cell, then they are flagging it. // Otherwise, they are revealing it. function checkCells() { sheet = SpreadsheetApp.getActiveSheet(); var cell = sheet.getActiveCell(); if (cell.getRow() > HEIGHT) { return; } if (cell.getValue() == 'f') { cell.setFontColor('#f1c232'); return; } // Recreate game map from seed that we stored in the sheet (bit of hack there) var x = cell.getColumn() - 1; var y = cell.getRow() - 1; var seedCell = sheet.getRange(HEIGHT+1, 1); seed = seedCell.getValue(); buildGame(); if (field[x][y] == 1) { expose(x,y); cell.setValue("X"); cell.setFontColor('red'); } else if (field[x][y] == 2) { expose(x,y); cell.setValue("O"); cell.setFontColor('#00ff00'); } else expose(x,y); }