I'm trying to perform the function where i click on a cell , and if it isn't in proximity of a bomb, it'll reveal all up until those who neighbour with a bomb.
I'm practically stuck :
I'm adding the code i think relevant here
//Click cells to reveal + placing mines for the first time
function cellClicked(elCell, i, j) {
if (!gGame.isOn) return;
if (gClickCounter === 0) {
getRandomMine(gLevel.mines, i, j);
startTimeInterval();
gClickCounter++;
}
var cell = gBoard[i][j];
console.log('cell:', cell);
if (cell.isShown) return;
if (!cell.isShown) {
cell.isShown = true;
elCell.classList.add('shown');
gGame.shownCount++;
console.log('gGame.shownCount:', gGame.shownCount);
}
if (cell.isMine === true) {
gLivesLeft--;
var elLives = document.querySelector('.lives');
elLives.innerHTML = gLivesLeft;
elCell.innerText = BOMB;
if (gLivesLeft === 0) {
gameOver();
}
} else {
var gNegs = countNegs(i, j);
elCell.innerText = gNegs;
console.log('elCell:', elCell.dataset.i);
console.log('elCell:', elCell.dataset.j);
cell.minesAroundCount = gNegs;
if (gNegs === 0) {
//check up
if (i > 0) {
var uCell = document.getElementById(gBoard.length * (i - 1) + j);
if (!gBoard[i - 1][j].isShown && !gBoard[i - 1][j].isMarked) {
cellClicked(uCell, i - 1, j);
}
}
//check down
if (i < gBoard.length - 1) {
var uCell = document.getElementById(gBoard.length * (i + 1) + j);
if (!gBoard[i + 1][j].isShown && !gBoard[i + 1][j].isMarked) {
cellClicked(uCell, i + 1, j);
}
}
//check right
if (j < gBoard.length - 1) {
var uCell = document.getElementById(gBoard.length * i + (j + 1));
if (!gBoard[i][j + 1].isShown && !gBoard[i][j + 1].isMarked) {
cellClicked(uCell, i, j + 1);
}
}
}
}
}
//counting neighbors
function countNegs(cellI, cellJ) {
var negsCount = 0;
for (var i = cellI - 1; i <= cellI + 1; i++) {
if (i < 0 || i > gBoard.length - 1) continue;
for (var j = cellJ - 1; j <= cellJ + 1; j++) {
if (j < 0 || j > gBoard[i].length - 1) continue;
if (i === cellI && j === cellJ) continue;
if (gBoard[i][j].isMine) {
negsCount++;
}
if (negsCount === 0) {
}
}
}
return negsCount;
}
and the entire code is here :
https://codepen.io/Aegtar/pen/XWaLLzz
Would appreciate any life savers here!
Related
In my research, I need to generate Fricke Polynomials. Luckily the job has been done for me on a website. However, it is in javascript+html+css so I am not sure how it works as I only use Mathematica. I was wondering if anyone could explain how I could make all of this work on a single javascript code with a single input (and where to put the input). My plan is then to just take the code and embed it in Mathematica as I have seen this is possible. The input is a word say made up of a's and b's say aabbbaa and an output is a polynomial. I do not need to understand the code really.
Thank you
function Polynomial(){
this.data = "";
this.setData = function(str){
this.data = str;
}
this.toString = function(){
var s = this.data;
if (this.data.startsWith("x0y0z0"))
s = s.replace("x0y0z0", "1");
s = s.replace(/x0y0z0/g, "")
.replace(/\s\+\s-/g, "</sup> - ").replace(/\s\+/g, "</sup> +")
.replace(/x/g, "x<sup>").replace(/y/g, "</sup>y<sup>")
.replace(/z/g, "</sup>z<sup>")
.replace(/\s1x/g, " x").replace(/\s1y/g, " y").replace(/\s1z/g, " z");
s += "</sup>";
s = s.replace(/x<sup>0<\/sup>/g, "").replace(/y<sup>0<\/sup>/g, "")
.replace(/z<sup>0<\/sup>/g, "")
.replace(/x<sup>1<\/sup>/g, "x").replace(/y<sup>1<\/sup>/g, "y")
.replace(/z<sup>1<\/sup>/g, "z");
if (s.startsWith("1x"))
s = s.replace("1x", "x");
if (s.startsWith("1y"))
s = s.replace("1y", "y");
if (s.startsWith("1z"))
s = s.replace("1z", "z");
return s;
}
}
function compareMonomial(m1, m2){
m1s = m1.split(/[x|y|z]/g);
m2s = m2.split(/[x|y|z]/g);
if (m1s[3]< m2s[3]) return -1;
else if (m1s[3] > m2s[3]) return 1;
else if (m1s[2]< m2s[2]) return -1;
else if (m1s[2] > m2s[2]) return 1;
else if (m1s[1]< m2s[1]) return -1;
else if (m1s[1] > m2s[1]) return 1;
else return 0;
}
function addMonomial(m1, m2){
m1s = m1.split(/[x|y|z]/g);
m2s = m2.split(/[x|y|z]/g);
coef = parseInt(m1s[0]) + parseInt(m2s[0]);
if (coef == 0)
return "ZERO"
else
return coef + "x" + m1s[1] + "y" + m1s[2] + "z" + m1s[3];
}
function subMonomial(m1, m2){
m1s = m1.split(/[x|y|z]/g);
m2s = m2.split(/[x|y|z]/g);
coef = parseInt(m1s[0]) - parseInt(m2s[0]);
if (coef == 0)
return "ZERO";
else
return coef + "x" + m1s[1] + "y" + m1s[2] + "z" + m1s[3];
}
function mulMonomial(m1, m2){
m1s = m1.split(/[x|y|z]/g);
m2s = m2.split(/[x|y|z]/g);
coef = parseInt(m1s[0]) * parseInt(m2s[0]);
coefx = parseInt(m1s[1]) + parseInt(m2s[1]);
coefy = parseInt(m1s[2]) + parseInt(m2s[2]);
coefz = parseInt(m1s[3]) + parseInt(m2s[3]);
if (coef == 0)
return "ZERO";
else
return coef + "x" + coefx + "y" + coefy + "z" + coefz;
}
function add(p1, p2){
if (p1.data == "")
return p2;
if (p2.data == "")
return p1;
var r = new Polynomial();
p1Mos = p1.data.split(" + ");
p2Mos = p2.data.split(" + ");
var data = "";
var k = 0; var current = p1Mos[0];
for (var i = 0; i < p2Mos.length; i++){
if (k >= p1Mos.length)
data += " + " + p2Mos[i];
else {
while (k < p1Mos.length && compareMonomial(current, p2Mos[i]) < 0){
data += " + " + p1Mos[k]; k++; current = p1Mos[k];
}
if (current == undefined)
data += " + " + p2Mos[i];
else if (compareMonomial(current, p2Mos[i]) == 0){
if (addMonomial(current, p2Mos[i]) != "ZERO")
data += " + " + addMonomial(current, p2Mos[i]);
k++; current = p1Mos[k];
}
else{
data += " + " + p2Mos[i];
}
}
}
while (k < p1Mos.length){
data += " + " + p1Mos[k]; k++
}
r.setData(data.substring(3));
return r;
}
function sub(p1, p2){
if (p2.data == "")
return p1;
if (p1.data == ""){
//need to update here
return p2;
}
var r = new Polynomial();
p1Mos = p1.data.split(" + ");
p2Mos = p2.data.split(" + ");
var data = "";
var k = 0; var current = p1Mos[0];
for (var i = 0; i < p2Mos.length; i++){
p2coef = p2Mos[i].split(/[x|y|z]g/)[0];
if (parseInt(p2coef) < 0)
p2MoNeg = p2Mos[i].substring(1);
else
p2MoNeg = "-" + p2Mos[i];
if (k >= p1Mos.length)
data += " + " + p2MoNeg;
else {
while (k < p1Mos.length && compareMonomial(current, p2Mos[i])< 0){
data += " + " + p1Mos[k]; k++; current = p1Mos[k];
}
if (current == undefined)
data += " + " + p2MoNeg;
else if (compareMonomial(current, p2Mos[i]) == 0){
if (subMonomial(current, p2Mos[i]) != "ZERO")
data += " + " + subMonomial(current, p2Mos[i]);
k++; current = p1Mos[k];
}
else{
data += " + " + p2MoNeg;
}
}
}
while (k < p1Mos.length){
data += " + " + p1Mos[k]; k++
}
r.setData(data.substring(3));
return r;
}
// multiply polynomial p1 (with array of monomials p1Mos) with a monomial m2
function mulPM(p1Mos, m2){
r = new Polynomial();
var data = "";
for (var i = 0; i < p1Mos.length; i++){
if (mulMonomial(p1Mos[i], m2) != "ZERO")
data += " + " + mulMonomial(p1Mos[i], m2);
}
r.setData(data.substring(3)); return r;
}
// multiply polynomial p1 with polynomial p2
function mul(p1, p2){
p1s = p1.data.split(" + ");
p2s = p2.data.split(" + ");
r = new Polynomial();
for (var i = 0; i < p2s.length; i++){
r = add(r, mulPM(p1s, p2s[i]));
}
return r;
}
function Fricke(s){
var w = new Word();
w.setWordString(s);
w.reduce(); s = w.toString();
var r = new Polynomial();
var l = s.length;
// Trivial case or case where 2 consecutive letters among last 4 letter
// are the same
if (l == 0){
r.setData("2x0y0z0");
return r;
}
if (l == 1){
if (s == "a" || s == "A")
r.setData("1x1y0z0");
else
r.setData("1x0y1z0");
return r;
}
if (s.charAt(l-1) == s.charAt(l-2)){
var c = s.charAt(l-1);
var s1 = s.substring(0, l-2);
r = sub(mul(Fricke(s1 + c), Fricke(c + "")), Fricke(s1));
return r;
}
if (l == 2){
if (s == "ab" || s == "ba" || s == "AB" || s == "BA"){
r.setData("1x0y0z1");
return r;
}
else if (s == "aB" || s == "Ba" || s == "Ab" || s == "bA"){
r.setData("1x1y1z0 + -1x0y0z1");
return r;
}
}
if (s.charAt(l-2) == s.charAt(l-3)){
s = s.charAt(l-1) + s.substring(0, l-1);
r = Fricke(s);
return r;
}
if (l == 3){
s = s.charAt(l-1) + s.substring(0, l-1);
r = Fricke(s);
return r;
}
if (s.charAt(l-3) == s.charAt(l-4)){
s = s.substring(l-2, l) + s.substring(0, l-2);
r = Fricke(s);
return r;
}
// Case 2: w = x1Yx2y
var t = s.charCodeAt(l-1) - s.charCodeAt(l-3);
if ( t == 32 || t == -32){
var w1 = new Word();
w1.setWordString(s.substring(l-2, l));
var s2 = s.substring(0, l-2) + w1.bar().toString();
r = sub(mul(Fricke(s.substring(0, l-2)), Fricke(s.substring(l-2, l))),
Fricke(s2));
return r;
}
// Case 3: w = ...Xyxy
t = s.charCodeAt(l-2) - s.charCodeAt(l-4);
if ( t == 32 || t == -32){
r = Fricke(s.charAt(l-1) + s.substring(0, l-1));
return r;
}
// Last case 4: w = ...xyxy
r = sub(mul(Fricke(s.substring(0, l-2)), Fricke(s.substring(l-4, l-2))),
Fricke(s.substring(0, l-4)));
return r;
}
// Helper methods:
function cancel2Char(src, i){
dest = [];
for (var j = 0; j < i; j++)
dest[j] = src[j];
for (var j = i; j < src.length - 2; j++)
dest[j] = src[j+2];
return dest;
}
function trim2Ends(src){
dest = [];
for (var j = 1; j < src.length - 1; j++)
dest[j - 1] = src[j];
return dest;
}
// Function to find the minimum equivalent class of a reduced cyclic word rc.
function minReduceCyclic(rc){
var min = rc.clone();
var W = new Word();
for (var i = 0; i < rc.word.length; i++){
W = rc.permute(i);
if (min.compareTo(W) > 0)
min = W;
}
return min;
}
function canonical(W){
W.reduce();
W.toReduceCyclic();
W = minReduceCyclic(W);
return W;
}
// CLASS Word
function Word(){
this.word = [];
this.setWord = function(w){
this.word = w;
}
this.setWordString = function(s){
// a-z = 1-26 && A-Z = -1 - -26;
for (var i = 0; i < s.length; i++){
var c = s.charCodeAt(i);
if (c >= 65 && c <= 90 )
this.word[i] = -(c - 64);
else if (c >= 97 && c < 122)
this.word[i] = c - 96;
else {
this.word = []; return;
}
}
}
this.length = function(){ return this.word.length; }
}
Word.prototype.isReduce = function(){
for(var i = 0; i < this.word.length - 1; i++)
if (this.word[i] == -this.word[i+1])
return false;
return true;
}
Word.prototype.reduce = function(){
var i = -2;
while(i != this.word.length - 1){
if (this.word.length == 0)
return;
for(i = 0; i < this.word.length - 1; i++)
if (this.word[i] == -this.word[i+1]){
this.word = cancel2Char(this.word, i);
break;
}
}
return;
}
Word.prototype.toReduceCyclic = function(){
this.reduce();
while(this.word[0] == -this.word[this.word.length - 1])
this.word = trim2Ends(this.word);
return;
}
Word.prototype.toString = function(){
var s = "";
for (var i = 0; i < this.word.length; i++){
if (this.word[i] < 0)
s = s + String.fromCharCode(-this.word[i] + 64);
else
s = s + String.fromCharCode(this.word[i] + 96);
}
return s;
}
Word.prototype.bar = function(){
var r = new Word();
var w = r.word;
for (var j = 0; j < this.word.length; j++)
w[j] = - this.word[this.word.length - 1 - j];
return r;
}
Word.prototype.permute = function(i){
var r = new Word();
var w = r.word;
for (var j = 0; j < this.word.length; j++)
w[j] = this.word[(j + i) % this.word.length];
return r;
}
Word.prototype.isEqual = function(W2){
var w1 = this.word;
var w2 = W2.word;
if (w1.length != w2.length)
return false;
for (var i = 0; i < w1.length; i++)
if (w1[i] != w2[i])
return false;
return true;
}
Word.prototype.compareTo = function(W2){
var w1 = this.word;
var w2 = W2.word;
var l = Math.min(w1.length, w2.length);
for (var i = 0; i < l; i++){
if (w1[i] < w2[i])
return -1;
if (w1[i] > w2[i])
return 1;
}
if (w1.length > w2.length)
return 1;
if (w1.length < w2.length)
return -1;
return 0;
}
Word.prototype.clone = function(){
var r = new Word();
w = r.word;
for (var i = 0; i < this.word.length; i++)
w[i] = this.word[i];
return r;
}
Word.prototype.primitiveExp = function(){
w = this.word; l = w.length;
for(var i = 1; i <= l/2; i++){
if (l % i == 0){
found = true;
test:
for (var j = 0; j < l/i; j++)
for (var t = 0; t < i; t++)
if (w[t] != w[t + j * i]){
found = false;
break test;
}
}
if (found)
return l/i;
}
return 1;
}
// Need to debug
function concat(W1, W2){
r = new Word();
var w1 = W1.word;
var w2 = W2.word;
var w = []
for (var i = 0; i < w1.length; i++)
w[i] = w1[i];
for (var i = 0; i < w2.length; i++)
w[i + w1.length] = w2[i];
r.setWord(w);
return r;
}
// These are supposed to be surface word methods
// sw is a word and the order is a map, which
// maps characters in a word (1-k or (-1)-(-k)) to its order in the alphabet
function order(sw){
var w = sw.word;
var o = new Map();
for (var i = 0; i < w.length; i++)
o.set(w[i], i);
return o;
}
function findCharPos(sw, c){
for (var i = 0; i < sw.word.length; i++)
if (sw.word[i] == c)
return i;
}
var time;
$(document).ready(function(){
$("#compute").click(function(){
$("#note").text("Note: Computing.....");
time = new Date().getTime();
setTimeout(function(){
new Promise(compute).then(doneCompute("Note: Done! The computation time is about "));
}, 50);
});
$("#reset").click(function(){
$("#note").text("Note:");
$("#word").val("");
$("#fpOutput").text("");
});
});
function compute(value){
$("#fpOutput").html(Fricke($("#word").val()).toString());
$("#fpOutput").slideDown("slow");
}
function doneCompute(value){
$("#note").text(value + (new Date().getTime() - time - 50) + " milliseconds.");
}
<!DOCTYPE html>
<html>
<head>
<link href="fricke.css" type="text/css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript" src="Word.js"></script>
<script type="text/javascript" src="Polynomial.js"></script>
<script type="text/javascript" src="gui.js"></script>
</head>
<body>
<h2>Computing Fricke Polynomial for word with 2 generators a and b</h2>
<br>
<b>Word: </b>
<input type="text" class="inputText" id="word"></input><br><br>
<br><br>
<button class="button" id="compute">Compute</button>
<button class="button" id="reset">Reset</button>
<br><br>
<div id="note">Note:</div>
<br><br>
<div class="slide">Fricke Polynomial</div>
<div class="output" id="fpOutput"></div>
</body>
</html>
I'm making a tag game. When I just use html and js, I generate elements dynamically and click on each one, the selected cell is moved to an empty space, everything works fine, but when I connected webpack, it stopped working (due to the fact that moveThisTile was called inside the line ). I rewrote the showTable function using createElement instead of concatenation. And now, when pressed, it draws another table with tags - the old table is not rubbed with a new one, but simply added to the end, with the changed position of the pressed button. I do not understand why. How can I fix this? Please help me to get this code to work. Here is my complete code https://codepen.io/tom7777/pen/abZjZav
And here is what it was originally (to see how it should work) https://codepen.io/tom7777/pen/abZjmZp
function startNewGame() {
let arrayOfNumbers = new Array();
let arrayHasNumberBeenUsed;
let randomNumber = 0;
let count = 0;
moves = 0;
rows = document.getElementById("rows").value;
columns = document.getElementById("columns").value;
textMoves.innerHTML = moves;
arrayForBoard = new Array(rows);
for (let i = 0; i < rows; i++){
arrayForBoard[i] = new Array(columns);
}
arrayHasNumberBeenUsed = new Array( rows * columns );
for (let i = 0; i < rows * columns; i++){
arrayHasNumberBeenUsed[i] = 0;
}
for (let i = 0; i < rows * columns; i++){
randomNumber = Math.floor(Math.random()*rows * columns);
if (arrayHasNumberBeenUsed[randomNumber] == 0) {
arrayHasNumberBeenUsed[randomNumber] = 1;
arrayOfNumbers.push(randomNumber);
}else
{
i--;
}
}
count = 0;
for (let i = 0; i < rows; i++){
for (let j = 0; j < columns; j++){
arrayForBoard[i][j] = arrayOfNumbers[count];
count++;
}
}
showTable();
}
function showTable() {
let tbody = document.createElement("tbody");
document.querySelector('#table').appendChild(tbody);
for (let i = 0; i < rows; i++) {
let tr = document.createElement('tr');
for (let j = 0; j < columns; j++) {
let cell = document.createElement('td');
if (arrayForBoard[i][j] == 0) {
cell.className = 'blank';
} else {
cell.className = 'tile';
cell.onclick = moveThisTile(i, j);
cell.innerHTML =arrayForBoard[i][j];
}
tr.appendChild(cell);
}
tbody.appendChild(tr);
}
};
function moveThisTile(tableRow, tableColumn) {
if (checkIfMoveable(tableRow, tableColumn, "up") ||
checkIfMoveable(tableRow, tableColumn, "down") ||
checkIfMoveable(tableRow, tableColumn, "left") ||
checkIfMoveable(tableRow, tableColumn, "right") ) {
incrementMoves();
} else {
alert("ERROR: Cannot move tile!\nTile must be next to a blank space.");
}
if (checkIfWinner()) {
alert("Congratulations! You solved the puzzle in " + moves + " moves.");
startNewGame();
}
}
function checkIfMoveable(rowCoordinate, columnCoordinate, direction) {
let rowOffset = 0;
let columnOffset = 0;
if (direction == "up"){rowOffset = -1;}
else if (direction == "down"){rowOffset = 1;}
else if (direction == "left"){columnOffset = -1;}
else if (direction == "right"){columnOffset = 1;}
if (rowCoordinate + rowOffset >= 0 && columnCoordinate + columnOffset >= 0 &&
rowCoordinate + rowOffset < rows && columnCoordinate + columnOffset < columns
){
if ( arrayForBoard[rowCoordinate + rowOffset][columnCoordinate + columnOffset] == 0){
arrayForBoard[rowCoordinate + rowOffset][columnCoordinate + columnOffset] = arrayForBoard[rowCoordinate][columnCoordinate];
arrayForBoard[rowCoordinate][columnCoordinate] = 0;
showTable();
return true;
}
}
return false;
}
function checkIfWinner(){
let count = 1;
for (let i = 0; i < rows; i++){
for (let j = 0; j < columns; j++){
if (arrayForBoard[i][j] != count){
if ( !(count === rows * columns && arrayForBoard[i][j] === 0 )){
return false;
}
}
count++;
}
}
return true;
}
I'm making a gem-puzzle. When I just use html and js I generate elements dynamically and put onclick on each one and when I click on it, everything works well, but when I connected the webpack it doesn't work. I rewrite the function showTable with createElement instead concatenation. And now I have an error Maximum call stack size exceeded at moveThisTile. I don't understand why? How can I fixed that? Please, help me to make this code work. There is my full code https://codepen.io/tomas777/pen/abZjZav?editors=1111
function startNewGame() {
let arrayOfNumbers = new Array();
let arrayHasNumberBeenUsed;
let randomNumber = 0;
let count = 0;
moves = 0;
rows = document.getElementById("rows").value;
columns = document.getElementById("columns").value;
textMoves.innerHTML = moves;
arrayForBoard = new Array(rows);
for (let i = 0; i < rows; i++){
arrayForBoard[i] = new Array(columns);
}
arrayHasNumberBeenUsed = new Array( rows * columns );
for (let i = 0; i < rows * columns; i++){
arrayHasNumberBeenUsed[i] = 0;
}
for (let i = 0; i < rows * columns; i++){
randomNumber = Math.floor(Math.random()*rows * columns);
if (arrayHasNumberBeenUsed[randomNumber] == 0) {
arrayHasNumberBeenUsed[randomNumber] = 1;
arrayOfNumbers.push(randomNumber);
}else
{
i--;
}
}
count = 0;
for (let i = 0; i < rows; i++){
for (let j = 0; j < columns; j++){
arrayForBoard[i][j] = arrayOfNumbers[count];
count++;
}
}
showTable();
}
function showTable() {
let tbody = document.createElement("tbody");
document.querySelector('#table').appendChild(tbody);
for (let i = 0; i < rows; i++) {
let tr = document.createElement('tr');
for (let j = 0; j < columns; j++) {
let cell = document.createElement('td');
if (arrayForBoard[i][j] == 0) {
cell.className = 'blank';
} else {
cell.className = 'tile';
cell.onclick = moveThisTile(i, j);
cell.innerHTML =arrayForBoard[i][j];
}
tr.appendChild(cell);
}
tbody.appendChild(tr);
}
};
function moveThisTile(tableRow, tableColumn) {
if (checkIfMoveable(tableRow, tableColumn, "up") ||
checkIfMoveable(tableRow, tableColumn, "down") ||
checkIfMoveable(tableRow, tableColumn, "left") ||
checkIfMoveable(tableRow, tableColumn, "right") ) {
incrementMoves();
} else {
alert("ERROR: Cannot move tile!\nTile must be next to a blank space.");
}
if (checkIfWinner()) {
alert("Congratulations! You solved the puzzle in " + moves + " moves.");
startNewGame();
}
}
function checkIfMoveable(rowCoordinate, columnCoordinate, direction) {
let rowOffset = 0;
let columnOffset = 0;
if (direction == "up"){rowOffset = -1;}
else if (direction == "down"){rowOffset = 1;}
else if (direction == "left"){columnOffset = -1;}
else if (direction == "right"){columnOffset = 1;}
if (rowCoordinate + rowOffset >= 0 && columnCoordinate + columnOffset >= 0 &&
rowCoordinate + rowOffset < rows && columnCoordinate + columnOffset < columns
){
if ( arrayForBoard[rowCoordinate + rowOffset][columnCoordinate + columnOffset] == 0){
arrayForBoard[rowCoordinate + rowOffset][columnCoordinate + columnOffset] = arrayForBoard[rowCoordinate][columnCoordinate];
arrayForBoard[rowCoordinate][columnCoordinate] = 0;
showTable();
return true;
}
}
return false;
}
function checkIfWinner(){
let count = 1;
for (let i = 0; i < rows; i++){
for (let j = 0; j < columns; j++){
if (arrayForBoard[i][j] != count){
if ( !(count === rows * columns && arrayForBoard[i][j] === 0 )){
return false;
}
}
count++;
}
}
return true;
}
--SOLVED--
I was just forgetting to reset the number of flags after each game.
I'm having issues with the number of flags in my minesweeper game. For some reason, sometimes when I flag a tile the number of flags increases by more than 1. Sometimes it increases by 3, sometimes 4, sometimes 7. I can't find the issue in my logic, so I was hoping to get another set of eyes on it.
The only sort of pattern I can see when it adds more flags than it should, i.e. the flags variable is incremented more than once, is when I flag a tile that is mostly surrounded by revealed tiles.
Javascript:
var flags = 0;
var trueFlags = 0;
function newGame() {
var cols = $("#width").val();
var rows = $("#height").val();
if (cols < 8 || rows < 8) {
return;
}else if (cols > 40 || rows > 30) {
return;
}
boardClear();
possibleBombs = (rows * cols) - 1;
numBombs = 0;
for (var i = 1; i <= rows; i++) {
for (var j = 1; j <= cols; j++) {
if (numBombs < possibleBombs) {
var q = Math.floor(Math.random() * 50);
if (0 <= q && q <= 2) {
numBombs += 1;
$("#board").append('<button type="button" class="tile" data-row = ' + i + ' data-col = ' + j + ' data-contains = ' + 0 + ' data-flagged = ' + false + '></button>').prop("revealed", false);
}
else {
$("#board").append('<button type="button" class="tile" data-row = ' + i + ' data-col = ' + j + ' data-contains = ' + 1 + 'data-flagged = ' + false + '></button>').prop("revealed", false);
}
}
else {
$("#board").append('<button type="button" class="tile" data-row = ' + i + ' data-col = ' + j + ' data-contains = ' + 1 + ' data-flagged = ' + false + '></button>').prop("revealed", false);
}
}
$("#board").append("<br/>");
}
$(".controls h2").text("Bombs to go: " + numBombs);
$(".tile").css("background-color", "white");
$(".tile").width(15);
$(".tile").height(15);
console.log("bombs: " + numBombs, "possible: " + possibleBombs);
$(".tile").click(function(e) {
if (e.shiftKey) {
flagKey($(this));
$(".controls h2").text("Bombs to go: " + (numBombs - flags));
}
else if ($(this).data("contains") == 0) {
console.log("you lose");
boardClear();
newGame();
return;
}
else {
revealNeighbors($(this));
// if (gameWon() == true) {
// alert("You have won!");
// newGame();
// }
return;
}
});
}
function boardClear() {
$("#board").empty();
}
function revealNeighbors(tile) {
var cordsx = tile.data("row");
var cordsy = tile.data("col");
// tile has bomb
if(tile.data("contains") == 0) {return;}
// tile is flagged
else if(tile.data("flagged") == true){return;}
// tile has been revealead already
else if(tile.prop("revealed") == true) {return;}
// reveal the tile
var tileBombs = nearbyBombCount(tile);
tile.prop("revealed", true);
tile.text(tileBombs);
tile.css("background-color", "grey");
if (tileBombs == 0){tile.text("");}
else if(tileBombs != 0) {return;}
for (var i = -1; i <= 1; i++) {
for (var j = -1; j <= 1; j++) {
if (cordsx + i < 1 || cordsy + j < 1) {continue;}
else if (cordsx + i > $("#width").val() || cordsy + j > $("#height").val()) {continue;}
else if (i == 0 && j == 0) {continue;}
var neighbor = $('.tile[data-row="' + (cordsx+i) + '"][data-col ="'+(cordsy+j)+'"]');
revealNeighbors(neighbor);
}
}
}
function nearbyBombCount(tile) {
var cx = tile.data("row");
var cy = tile.data("col");
var nearbyBombs = 0;
for (var n = -1; n < 2; n++) {
for (var m = -1; m < 2; m++) {
if (cx + n < 1 || cy + m < 1) {continue;}
else if (cx + n > $("#width").val() || cy + m > $("#height").val()) {continue;}
var neighbor = $('.tile[data-row="' + (cx+n) + '"][data-col ="'+(cy+m)+'"]');
if (neighbor.data("contains") == 0) {
nearbyBombs++;
}
}
}
return nearbyBombs;
}
function flagKey(tile) {
// tile is already revealed
if (tile.data("revealed") == true) {
return;
}
// tile is already flagged
else if (tile.data("flagged") == true) {
tile.data("flagged", false);
tile.css("background-color", "white");
flags--;
// contains bomb
if (tile.data("contains") == 0) {
trueFlags--;
}
return;
}
// tile not flagged
else if (tile.data("flagged") == false) {
flags++;
tile.data("flagged", true);
tile.css("background-color", "red");
// contains bomb
if (tile.data("contains") == 0) {
trueFlags++;
console.log(trueFlags);
}
}
else {
return;
}
}
My guess is that there's something wrong with my revealNeighbors() function or it's some scope issue, but I can't for the life of me figure out what it is.
Hi I change a litle and works fine
<html>
<head>
<style>
.tile{padding:5px;}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
Width : <input type="text" id="width" value="15" /> Height :<input type="text" id="height" value="15" /><input type="button" onclick="newGame()" id="btnstart" value="start" />
<br />
<div>
<div id="board" >
</div>
</div>
<script>
var flags = 0;
var trueFlags = 0;
function newGame() {
var cols = $("#width").val();
var rows = $("#height").val();
if (cols < 8 || rows < 8) {
return;
}else if (cols > 40 || rows > 30) {
return;
}
boardClear();
possibleBombs = (rows * cols) - 1;
numBombs = 0;
for (var i = 1; i <= rows; i++) {
for (var j = 1; j <= cols; j++) {
if (numBombs < possibleBombs) {
var q = Math.floor(Math.random() * 50) + 1;
if (q <= 2) {
numBombs += 1;
$("#board").append('<button type="button" class="tile" data-row = ' + i + ' data-col = ' + j + ' data-contains = ' + 0 + ' data-flagged = ' + false + '></button>').prop("revealed", false);
}
else {
$("#board").append('<button type="button" class="tile" data-row = ' + i + ' data-col = ' + j + ' data-contains = ' + 1 + 'data-flagged = ' + false + '></button>').prop("revealed", false);
}
}
else {
$("#board").append('<button type="button" class="tile" data-row = ' + i + ' data-col = ' + j + ' data-contains = ' + 1 + ' data-flagged = ' + false + '></button>').prop("revealed", false);
}
}
$("#board").append("<br/>");
}
$(".controls h2").text("Bombs to go: " + numBombs);
$(".tile").css("background-color", "white");
$(".tile").width(15);
$(".tile").height(15);
console.log("bombs: " + numBombs, "possible: " + possibleBombs);
$(".tile").click(function (e) {
if (e.shiftKey) {
flagKey($(this));
$(".controls h2").text("Bombs to go: " + (numBombs - flags));
}
else if ($(this).data("contains") == 0) {
console.log("you lose");
boardClear();
newGame();
return;
}
else {
revealNeighbors($(this));
// if (gameWon() == true) {
// alert("You have won!");
// newGame();
// }
return;
}
});
}
function boardClear() {
$("#board").empty();
}
function revealNeighbors(tile) {
var cordsx = tile.data("row");
var cordsy = tile.data("col");
// tile has bomb
if(tile.data("contains") == 0) {return;}
// tile is flagged
else if(tile.data("flagged") == true){return;}
// tile has been revealead already
else if(tile.prop("revealed") == true) {return;}
// reveal the tile
var tileBombs = nearbyBombCount(tile);
tile.prop("revealed", true);
tile.text(tileBombs);
tile.css("background-color", "grey");
if (tileBombs == 0){tile.text("");}
else if(tileBombs != 0) {return;}
for (var i = -1; i <= 1; i++) {
for (var j = -1; j <= 1; j++) {
if (cordsx + i < 1 || cordsy + j < 1) {continue;}
else if (cordsx + i > $("#width").val() || cordsy + j > $("#height").val()) {continue;}
else if (i == 0 && j == 0) {continue;}
var neighbor = $('.tile[data-row="' + (cordsx+i) + '"][data-col ="'+(cordsy+j)+'"]');
revealNeighbors(neighbor);
}
}
}
function nearbyBombCount(tile) {
var cx = tile.data("row");
var cy = tile.data("col");
var nearbyBombs = 0;
for (var n = -1; n < 2; n++) {
for (var m = -1; m < 2; m++) {
if (cx + n < 1 || cy + m < 1) {continue;}
else if (cx + n > $("#width").val() || cy + m > $("#height").val()) {continue;}
var neighbor = $('.tile[data-row="' + (cx+n) + '"][data-col ="'+(cy+m)+'"]');
if (neighbor.data("contains") == 0) {
nearbyBombs++;
}
}
}
return nearbyBombs;
}
function flagKey(tile) {
// tile is already revealed
if (tile.data("revealed") == true) {
return;
}
// tile is already flagged
else if (tile.data("flagged") == true) {
tile.data("flagged", false);
tile.css("background-color", "white");
flags--;
// contains bomb
if (tile.data("contains") == 0) {
trueFlags--;
}
return;
}
// tile not flagged
else if (tile.data("flagged") == false) {
flags++;
tile.data("flagged", true);
tile.css("background-color", "red");
// contains bomb
if (tile.data("contains") == 0) {
trueFlags++;
console.log(trueFlags);
}
}
else {
return;
}
}
</script>
</body>
</html>
I am trying to generate a random grid of connected paths. The image below shows how far I've managed to get it:
The rules that the grid needs to adhere to are the following:
all the paths must connect to each other in some way but there can be dead ends
there can be no blocks that have no connections (i.e. can't be reached)
the blocks on the edge must have paths that point inward, not outward.
As you can see in my image, my code isn't quite right, but I can't find the error.
Here is a fiddle with the code: jsfiddle.net/thatOneGuy/jz5sfr00/1
But I think my mistake is in this function:
function linkAll() {
for (var x = 0; x < 9; x++) {
for (y = 0; y < 9; y++) {
//link up to each other
var count = 0;
if ((x > 0) && (y > 0)) {
if (hz[x - 1][y].right) {
hz[x][y].left = 1;
} else count++;
if (hz[x][y - 1].bottom) {
hz[x][y].top = 1;
} else count++;
}
if ((x < 9) && (y < 9)) {
if (hz[x + 1][y].left) {
hz[x][y].right = 1;
} else count++;
if (hz[x][y + 1].top) {
hz[x][y].bottom = 1;
} else count++;
}
if (count == 4) {
var newPath = getDirection(getRandomInt(0, 3));
if (newPath == 'top') {
hz[x][y - 1].bottom = 1
hz[x][y].top = 1;
} else if (newPath == 'left') {
hz[x - 1][y].right = 1;
hz[x][y].left = 1;
} else if (newPath == 'bottom') {
hz[x][y + 1].top = 1;
hz[x][y].bottom = 1;
} else if (newPath == 'right') {
hz[x + 1][y].left = 1;
hz[x][y].right = 1;
}
}
} //end for (y)
} //end for (x)
}
UPDATE:
I realised that I confused the x and y values of the array. They should have been swopped.
So I added a linkEdges() function so that the edge blocks all link together:
function linkEdges(){
for(var x = 0; x < 10; x++){
for(var y = 0; y < 10; y++){
if((x==0) && (y > 0) && (y < 9)){
if(hz[0][y-1].right){
//console.log(x + ' ' + y + ' y-1 = 1');
//console.log('Inside (y-1) ');
//console.log(hz[x][y]);
if (hz[0][y].left != null)
{
hz[0][y].left = 1;
}
}
}
if ((y==0) && (x > 0)){
if(hz[x-1][0].bottom){
if(hz[x][0].top != null)
hz[x][0].top = 1;
}
}
if ((y==9) && (x < 9) && (x > 0)){
if(hz[x+1][9].top){
if(hz[x][9].bottom != null)
hz[x][9].bottom = 1;
}
}
if ((x==9) && (y < 9)){
if(hz[9][y+1].left){
if(hz[9][y].right != null)
hz[9][y].right = 1;
}
}
} //end for(y)
}//end for(x)
}
I also updated the linkAll() function:
function linkAll(){
for(var x=0; x < 9; x++){
for(var y=0; y < 9; y++){
//link up to each other
var count = 0;
if((x > 0) && (y > 0)){
if(hz[x-1][y].bottom){
hz[x][y].top = 1;
}
else count++;
if(hz[x][y-1].right){
hz[x][y].left = 1;
}
else count++;
}
if((x < 9) && (y < 9)){
if(hz[x+1][y].top){
hz[x][y].bottom = 1;
}
else count++;
if(hz[x][y+1].left){
hz[x][y].right = 1;
}
else count++;
}
if(count == 4){
//console.log('x: ' + x + ' y: '+y);
var newPath = getDirection(getRandomInt(0, 3));
//console.log(newPath);
if(newPath == 'top'){
hz[x][y-1].right = 1
hz[x][y].left = 1;
}
else if(newPath == 'left'){
hz[x-1][y].bottom = 1;
hz[x][y].top = 1;
}
else if(newPath == 'bottom'){
hz[x][y+1].left = 1;
hz[x][y].right = 1;
}
else if(newPath == 'right'){
hz[x+1][y].top = 1;
hz[x][y].bottom = 1;
}
}
}//end for (y)
}//end for (x)
}
My grid now looks like this:
I just don't know how to connect those last few edges. I think it has something to do with my linkEdges() function.