Skip to content

Instantly share code, notes, and snippets.

@rellfy
Created February 1, 2019 15:52
Show Gist options
  • Save rellfy/e15e1942d2645dff98dc3d4c6b857255 to your computer and use it in GitHub Desktop.
Save rellfy/e15e1942d2645dff98dc3d4c6b857255 to your computer and use it in GitHub Desktop.
Discord minesweeper generator
var width; // set by calling "init"
var total; // set by calling "init", total n of mines
var mines; // set by calling "init"
var adjacent = new Array(); // count of adjacent mines
var mine = 9; // adjacency count for a mine
var exposed = new Array(); // exposure state / pending exposures
var listEnd = -1; // end marker in "exposed"
var incorrect = -2; // incorrect flag, at end of game
var exploded = -3; // exploded mine (at end of game!)
var unexposed = -4; // default state at start of game
var squares = [];
var charMine = "||:bomb:||";
var charEmpty = "||:white_large_square:||";
var numbers = ['','one','two','three','four','five','six','seven','eight','nine'];
function setSq(thisSquare) {
var sq = squares[thisSquare] ? squares[thisSquare] : charEmpty;
var exp = exposed[thisSquare];
var adj = adjacent[thisSquare];
if (exp == exploded) {
sq = charMine;
} else if (exp == incorrect) {
sq = charIncorrect;
} else if (adj == mine) {
sq = charMine;
}
squares[thisSquare] = sq;
}
function applyToNeighbours(thisSquare, f) {
var x = thisSquare % width;
if (thisSquare >= width) { // there's a row above
if (x > 0) f(thisSquare - width - 1);
f(thisSquare - width);
if (x+1 < width) f(thisSquare - width + 1);
}
if (x > 0) f(thisSquare - 1);
if (x+1 < width) f(thisSquare + 1);
if (thisSquare < total-width) { // there's a row below
if (x > 0) f(thisSquare + width - 1);
f(thisSquare + width);
if (x+1 < width) f(thisSquare + width + 1);
}
}
var tail = listEnd;
function expose1(thisSquare) {
// Expose square and add to pending exposure list.
if (exposed[thisSquare] <= unexposed &&
exposed[thisSquare] != flagged) {
remaining--;
exposed[thisSquare] = listEnd;
exposed[tail] = thisSquare;
tail = thisSquare;
setSq(thisSquare);
}
}
function clickSq(event, thisSquare) {
if (!event) event = window.event; // IE versus the rest
if (!timer) startTimer();
if (exposed[thisSquare] > unexposed) {
// already exposed: do nothing
} else if (!event.which && event.button == 0) {
// mouse-up after right-click on IE: do nothing
} else if (event.shiftKey || event.button == 2) {
// flag or unflag
var exp = exposed[thisSquare];
if (exp == unexposed) {
exposed[thisSquare] = flagged;
} else if (exp == flagged) {
exposed[thisSquare] = queried;
} else if (exp == queried) {
exposed[thisSquare] = unexposed;
}
setSq(thisSquare);
} else if (adjacent[thisSquare] == mine) {
// exposing a mine: explode it and expose other mines
remaining--;
exposed[thisSquare] = exploded;
setSq(thisSquare);
var i;
for (i = 0; i < total; i++) {
if (i==thisSquare) {
} else if (adjacent[i] == mine && exposed[i] != flagged) {
remaining--;
exposed[i] = listEnd;
setSq(i);
} else if (adjacent[i] != mine && exposed[i] == flagged) {
remaining--;
exposed[i] = incorrect;
setSq(i);
}
}
} else {
// expose the square, if not already exposed
// If square has 0 adjacency, expose surrounding squares,
// and iterate
remaining--;
exposed[thisSquare] = listEnd;
tail = thisSquare;
setSq(thisSquare);
var pending = thisSquare;
// Until pending reaches the end of the exposure list, expose
// neighbors
while (pending != listEnd) {
if (adjacent[pending]==0) applyToNeighbours(pending, expose1);
pending = exposed[pending];
}
if (remaining==mines) {
// End of game: flag all remaining unflagged mines
var i;
for (i = 0; i < total; i++) {
if (adjacent[i] == mine && exposed[i] <= unexposed &&
exposed[i] != flagged ) {
exposed[i] = flagged;
setSq(i);
}
}
}
}
return false;
}
function neighbourIsMine(thisSquare) {
// Increase adjacency count, if this isn't itself a mine
if (adjacent[thisSquare] != mine) {
adjacent[thisSquare]++;
squares[thisSquare] = `||:${numbers[adjacent[thisSquare]]}:||`;
}
}
function layMines() {
// Lay the mines
var laid = 0;
while (laid < mines) {
var target = Math.floor(Math.random() * total);
// Despite what others might say, it's possible that "target
// = total". This is because although Math.random() is < 1,
// in an extreme case the multiplication by "total" will round up.
// We need to allow for this, if we really care about correctness.
if (target < total && adjacent[target] != mine) {
adjacent[target] = mine;
squares[target] = charMine;
applyToNeighbours(target, neighbourIsMine);
laid++;
}
}
}
function eraseRows() {
// erase square contents
var i;
for (i = 0; i < total; i++) {
adjacent[i] = 0;
if (exposed[i] != unexposed) {
exposed[i] = unexposed;
setSq(i);
}
}
}
function erase() {
eraseRows();
layMines();
return false;
}
function init(w, t, m) {
width = w;
total = t;
mines = m;
var i;
for (i = 0; i < total; i++) {
squares[i] = charEmpty;
}
erase();
let output = '';
let c2 = 0;
for (let c = 0; c < total; c++) {
c2++;
output += squares[c];
if (c2 == width) {
output += '\n';
c2 = 0;
}
}
console.log(output);
}
//init(10, 100, 12);
// width 10, tiles 10^2, bombs 12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment