Recursion for matrix in JavaScript - javascript

I'm using recursion for finding neighbors of neighbors in a matrix (in a minesweeper game). Right now my function is finding and marking neighbors only from left till bottom right. What am I doing wrong?
Javascript:
function openAllZeroCount(elcell, i, j) {
for (var idxi = i - 1; idxi <= i + 1; idxi++) {
for (var idxj = j - 1; idxj <= j + 1; idxj++) {
if (idxi < 0 || idxi >= gSize || idxj < 0 || idxj >= gSize) continue;
if (gBoard[idxi][idxj].isMine === false && gBoard[idxi][idxj].minesAroundCount === 1) {
var elCountZero = document.getElementById('cell-' + idxi + '-' + idxj)
elCountZero.style.opacity = '0.8'
elCountZero.innerText = gBoard[idxi][idxj].minesAroundCount
}
if (gBoard[idxi][idxj].isMine === false && gBoard[idxi][idxj].minesAroundCount === 0) {
var elCountZero = document.getElementById('cell-' + idxi + '-' + idxj)
elCountZero.style.opacity = '0.8'
}
}
}
if (idxi < 0 || idxi >= gSize || idxj < 0 || idxj >= gSize) return;
if (gBoard[idxi][idxj].isMine === false) {
console.log('gboard i j:', gBoard[idxi][idxj])
openAllZeroCount(null, idxi, idxj)
}
}

Related

Squares get stuck to each other during collision

for (var g = 0; g < cArray.length - 1; g++) {
if (h !== g) {
if (
cArray[h].x + cArray[h].size > cArray[g].x - cArray[g].size &&
cArray[h].x - cArray[h].size < cArray[g].x + cArray[g].size &&
cArray[h].y + cArray[h].size > cArray[g].y - cArray[g].size &&
cArray[h].y - cArray[h].size < cArray[g].y + cArray[g].size
) {
cArray[h].dirX = cArray[g].dirX;
cArray[g].dirX = cArray[h].dirX;
cArray[h].dirY = cArray[g].dirY;
cArray[g].dirY = cArray[h].dirY;
}
}
}
Instead of bouncing off, they no-clip to each other, causing their directions to combine.

Function to change colors multiple buttons colors only works fine in the same button

Im doing two functions "getBetNumbers" to get multiple buttons and "changeButtonColor" to change multiple button colors, i dont get any erros if i click in the same button multiple times, but whenever i click a button then another one goes to the last else from changeButtonColor. Does anyone know how can i fix it or a better way to do this?
function getBetNumbers(num) {
var ext = document.getElementById('ext');
ext.innerHTML = '';
for (i = 1; i <= num; i++) {
if (i < 10) {
ext.innerHTML +=
'<div onclick="changeButtonColor(' +
i +
')" class="quina" data-numbers="data' +
i +
'" id="ext' +
i +
'">' +
0 +
i +
'</div>';
} else {
ext.innerHTML +=
'<div onclick="changeButtonColor(' +
i +
')" class="quina" data-numbers="data' +
i +
'" id="ext' +
i +
'">' +
i +
'</div>';
}
}
}
const changeButtonColor = function (number) {
getDescription('games.json', function (err, data) {
var ext = document.getElementById('ext' + number);
if (err === null) {
console.log('Ocorreu um erro' + err);
} else if (counterr === 0) {
ext.style.backgroundColor = '#ADC0C4';
counterr = 1;
counterNumbers = counterNumbers - 1;
totalNumbers.splice(-1, 100, ext.innerText);
} else if (
counterr === 1 &&
counterNumbers <= 15 &&
whichLoteriaIs === 'lotofacil'
) {
ext.style.backgroundColor = data.types[0].color;
counterNumbers = counterNumbers + 1;
counterr = 0;
totalNumbers.push(ext.innerText);
} else if (
counterr === 1 &&
counterNumbers <= 6 &&
whichLoteriaIs === 'megasena'
) {
ext.style.backgroundColor = data.types[1].color;
counterNumbers = counterNumbers + 1;
counterr = 0;
totalNumbers.push(ext.innerText);
} else if (
counterr === 1 &&
counterNumbers <= 20 &&
whichLoteriaIs === 'lotomania'
) {
ext.style.backgroundColor = data.types[2].color;
counterNumbers = counterNumbers + 1;
counterr = 0;
totalNumbers.push(ext.innerText);
} else if (
counterr === 1 &&
counterNumbers !== 5 &&
whichLoteriaIs === 'quina'
) {
ext.style.backgroundColor = data.types[3].color;
counterNumbers = counterNumbers + 1;
counterr = 0;
totalNumbers.push(ext.innerText);
}
});
};
While it's impossible to help with the change button color code (because it relies on many variables and other functions that we don't have access to), there is a more efficient and reliable way to create your number divs. In this example, I used backticks and template literals ( ${variable} ) to create your number divs - more readable and less code. For the 'onclick', I moved those to an event listener. Just one event listener is needed for all those button actions, but because those divs get created after the page loads, we put the listener on something that won't be created and destroyed, like body and check to see if we clicked on a quina div. In the context of the event listener, you can get to the item clicked with e.target
window.addEventListener('load', () => {
document.querySelector('body').addEventListener('click', e => {
if (e.target.classList.contains('quina')) {
changeButtonColor(e.target)
}
})
})
const getBetNumbers = num => {
let str = '',
i = 0;
while (++i <= num) str += `<div class="quina" data-numbers="data${i}" id="ext${i}">${("0"+i).slice(-2)}</div>`;
document.getElementById('ext').innerHTML = str;
}
const changeButtonColor = ext => {
console.log('changeButtonColor for ', ext.id)
return // because it would error in this snippet. you can take this out.
getDescription('games.json', function(err, data) {
if (err === null) {
console.log('Ocorreu um erro' + err);
} else if (counterr === 0) {
ext.style.backgroundColor = '#ADC0C4';
counterr = 1;
counterNumbers = counterNumbers - 1;
totalNumbers.splice(-1, 100, ext.innerText);
} else if (
counterr === 1 &&
counterNumbers <= 15 &&
whichLoteriaIs === 'lotofacil'
) {
ext.style.backgroundColor = data.types[0].color;
counterNumbers = counterNumbers + 1;
counterr = 0;
totalNumbers.push(ext.innerText);
} else if (
counterr === 1 &&
counterNumbers <= 6 &&
whichLoteriaIs === 'megasena'
) {
ext.style.backgroundColor = data.types[1].color;
counterNumbers = counterNumbers + 1;
counterr = 0;
totalNumbers.push(ext.innerText);
} else if (
counterr === 1 &&
counterNumbers <= 20 &&
whichLoteriaIs === 'lotomania'
) {
ext.style.backgroundColor = data.types[2].color;
counterNumbers = counterNumbers + 1;
counterr = 0;
totalNumbers.push(ext.innerText);
} else if (
counterr === 1 &&
counterNumbers !== 5 &&
whichLoteriaIs === 'quina'
) {
ext.style.backgroundColor = data.types[3].color;
counterNumbers = counterNumbers + 1;
counterr = 0;
totalNumbers.push(ext.innerText);
}
});
};
<div id='ext'></div>
<button onclick='getBetNumbers(10)'>Get Bet Numbers</button>

Game over return

I am during writing game. When condition (playerlife < 1) is meet, game should stop. Whole game is in singlePlayer function. The problem is, I don't know how to end this function. Simple placing condition inside singlePlayer function doesn't work because it is checked only once during starting a game.
if (playerlife < 1) {
return;
}
I also tried to put this condition in interval and check if condition is meet continously but I doesn't work and anyway it doesn't looks like a good idea.
Below is part of code where after moving player there are checked some conditions. Game is similar to old school "Frogger". When player jump in to the water then he lost 1 life. After loosing 3 lives game should be over.
$(function() {
function singlePlayer() {
checkPosition(x, y) {
for (var i = 0; i < raftsTab.length; i++) {
if (x == raftsTab[i].PosX && y == raftsTab[i].PosY) {
let thisRaft = raftsTab[i];
console.log(x, y);
console.log(thisRaft);
clearInterval(MoveToPlayer);
movePlayer(thisRaft);
return;
}
}
for (var i = 0; i < raftsTab.length; i++) {
if (x !== raftsTab[i].PosX && y !== raftsTab[i].PosY && y !== 0 && y !== 5 && y !== 10) {
player1.lifes = player1.lifes - 1;
//player dead after loosing 3 lives - it would be perfect if game could be ended from here
$('.lifes').text("Player lifes: " + player1.lifes);
for (var i = 0; i < trophiesTab.length; i++) {
if (player1.trophie - 1 == i) {
trophiesTab[i].show();
player1.trophie = -1;
}
}
player1.PosX = 5;
player1.PosY = 10;
clearInterval(MoveToPlayer);
changePosition();
return;
}
}
for (var i = 0; i < trophiesTab.length; i++) {
if (x == trophiesTab[i].PosX && y == trophiesTab[i].PosY && player1.trophie == -1) {
trophiesTab[i].hide();
}
}
if (x == 5 && y == 0 && player1.trophie !== -1) {
tresure1 = tresure1 + player1.trophie;
player1.items = player1.items + 1;
$('.items').text("Gathered items: " + player1.items + "/3");
player1.trophie = -1;
console.log(tresure1);
}
clearInterval(MoveToPlayer);
}
}
});

Running into "Maximum call stack" errors on a recursive function

I'm making a height map editor. Basically its a grid of numbers where you can change any location by +/- 1. The editor then makes sure that there can only be a difference of 1 between any of the touching 8 tiles.
I'm doing this with a recursive function. Basically its looking at it's 8 neighbors and adjusting them as needed. If any where adjusted, call the function on all 8 neighbors.
I get Uncaught RangeError: Maximum call stack size exceeded errors after messing around for awhile and I can't see where they are coming from. I'm doing checks to make sure I don't try to access non-exsiting grid locations...
The function is this:
var moveDown = function (x, y) {
var updated = false;
if (x-1 >= 0 && Math.abs(grid[x][y] - grid[x-1][y]) > 1) {
grid[x-1][y] -= 1;
updated = true;
}
if (x-1 < size && Math.abs(grid[x][y] - grid[x+1][y]) > 1) {
grid[x+1][y] -= 1;
updated = true;
}
if (y-1 >= 0 && Math.abs(grid[x][y] - grid[x][y-1]) > 1) {
grid[x][y-1] -= 1;
updated = true;
}
if (y+1 < size && Math.abs(grid[x][y] - grid[x][y+1]) > 1) {
grid[x][y+1] -= 1;
updated = true;
}
if (x-1 >= 0 && y-1 >= 0 && Math.abs(grid[x][y] - grid[x-1][y-1]) > 1) {
grid[x-1][y-1] -= 1;
updated = true;
}
if (x-1 >= 0 && y+1 < size && Math.abs(grid[x][y] - grid[x-1][y+1]) > 1) {
grid[x-1][y+1] -= 1;
updated = true;
}
if (x+1 < size && y-1 >= 0 && Math.abs(grid[x][y] - grid[x+1][y-1]) > 1) {
grid[x+1][y-1] -= 1;
updated = true;
}
if (x+1 < size && y+1 < size && Math.abs(grid[x][y] - grid[x+1][y+1]) > 1) {
grid[x+1][y+1] -= 1;
updated = true;
}
if (updated) {
if (x-1 >= 0) { moveDown(x-1, y); }
if (x+1 < size) { moveDown(x+1, y); }
if (y-1 >= 0) { moveDown(x, y-1); }
if (y+1 < size) { moveDown(x, y+1); }
if (x-1 >= 0 && y-1 >= 0) { moveDown(x-1, y-1); }
if (x-1 >= 0 && y+1 < size) { moveDown(x-1, y+1); }
if (x+1 < size && y-1 >= 0) { moveDown(x+1, y-1); }
if (x+1 < size && y+1 < size) { moveDown(x+1, y+1); }
}
}
I have a fiddle here. And it looks like I can just inline it, so I did that too.
var size = 15
var grid;
var active = {x: -1, y: -1};
var moveDown = function (x, y) {
var updated = false;
if (x-1 >= 0 && Math.abs(grid[x][y] - grid[x-1][y]) > 1) {
grid[x-1][y] -= 1;
updated = true;
}
if (x-1 < size && Math.abs(grid[x][y] - grid[x+1][y]) > 1) {
grid[x+1][y] -= 1;
updated = true;
}
if (y-1 >= 0 && Math.abs(grid[x][y] - grid[x][y-1]) > 1) {
grid[x][y-1] -= 1;
updated = true;
}
if (y+1 < size && Math.abs(grid[x][y] - grid[x][y+1]) > 1) {
grid[x][y+1] -= 1;
updated = true;
}
if (x-1 >= 0 && y-1 >= 0 && Math.abs(grid[x][y] - grid[x-1][y-1]) > 1) {
grid[x-1][y-1] -= 1;
updated = true;
}
if (x-1 >= 0 && y+1 < size && Math.abs(grid[x][y] - grid[x-1][y+1]) > 1) {
grid[x-1][y+1] -= 1;
updated = true;
}
if (x+1 < size && y-1 >= 0 && Math.abs(grid[x][y] - grid[x+1][y-1]) > 1) {
grid[x+1][y-1] -= 1;
updated = true;
}
if (x+1 < size && y+1 < size && Math.abs(grid[x][y] - grid[x+1][y+1]) > 1) {
grid[x+1][y+1] -= 1;
updated = true;
}
if (updated) {
if (x-1 >= 0) { moveDown(x-1, y); }
if (x+1 < size) { moveDown(x+1, y); }
if (y-1 >= 0) { moveDown(x, y-1); }
if (y+1 < size) { moveDown(x, y+1); }
if (x-1 >= 0 && y-1 >= 0) { moveDown(x-1, y-1); }
if (x-1 >= 0 && y+1 < size) { moveDown(x-1, y+1); }
if (x+1 < size && y-1 >= 0) { moveDown(x+1, y-1); }
if (x+1 < size && y+1 < size) { moveDown(x+1, y+1); }
}
}
var moveUp = function (x, y) {
var updated = false;
if (x-1 >= 0 && Math.abs(grid[x][y] - grid[x-1][y]) > 1) {
grid[x-1][y] += 1;
updated = true;
}
if (x-1 < size && Math.abs(grid[x][y] - grid[x+1][y]) > 1) {
grid[x+1][y] += 1;
updated = true;
}
if (y-1 >= 0 && Math.abs(grid[x][y] - grid[x][y-1]) > 1) {
grid[x][y-1] += 1;
updated = true;
}
if (y+1 < size && Math.abs(grid[x][y] - grid[x][y+1]) > 1) {
grid[x][y+1] += 1;
updated = true;
}
if (x-1 >= 0 && y-1 >= 0 && Math.abs(grid[x][y] - grid[x-1][y-1]) > 1) {
grid[x-1][y-1] += 1;
updated = true;
}
if (x-1 >= 0 && y+1 < size && Math.abs(grid[x][y] - grid[x-1][y+1]) > 1) {
grid[x-1][y+1] += 1;
updated = true;
}
if (x+1 < size && y-1 >= 0 && Math.abs(grid[x][y] - grid[x+1][y-1]) > 1) {
grid[x+1][y-1] += 1;
updated = true;
}
if (x+1 < size && y+1 < size && Math.abs(grid[x][y] - grid[x+1][y+1]) > 1) {
grid[x+1][y+1] += 1;
updated = true;
}
if (updated) {
if (x-1 >= 0) { moveUp(x-1, y); }
if (x+1 < size) { moveUp(x+1, y); }
if (y-1 >= 0) { moveUp(x, y-1); }
if (y+1 < size) { moveUp(x, y+1); }
if (x-1 >= 0 && y-1 >= 0) { moveUp(x-1, y-1); }
if (x-1 >= 0 && y+1 < size) { moveUp(x-1, y+1); }
if (x+1 < size && y-1 >= 0) { moveUp(x+1, y-1); }
if (x+1 < size && y+1 < size) { moveUp(x+1, y+1); }
}
}
var init = function () {
$('#board').mouseleave(function () {
active.x = -1;
active.y = -1;
})
.mousemove(function () {
active.x = -1;
active.y = -1;
});
$('#reset').click(function () {
for(var x=0; x<size; x++) {
for(var y=0; y<size; y++) {
grid[x][y] = 1;
}
}
});
$(window).keydown(function (e) {
if (e.keyCode === 119 || e.keyCode === 87) {
// W
grid[active.x][active.y] += 1;
moveUp(active.x, active.y);
}
if (e.keyCode === 115 || e.keyCode === 83) {
// S
grid[active.x][active.y] -= 1;
moveDown(active.x, active.y);
}
});
grid = [];
for(var x=0; x<size; x++) {
grid[x] = [];
var row = $('<div class="row">');
for(var y=0; y<size; y++) {
grid[x][y] = 1;
var cell = $('<div id="C' + x + '_' + y + '" class="cell">');
cell.data('x', x).data('y', y);
cell.mousemove(function (e) {
var $this = $(this);
active.x = $this.data('x');
active.y = $this.data('y');
e.stopPropagation();
});
row.append(cell)
}
$('#board').append(row);
}
setInterval(function () {
for(var x=0; x<size; x++) {
for(var y=0; y<size; y++) {
$('#C' + x + '_' + y).text(grid[x][y]);
}
}
$('#info').text('x: ' + active.x + ' y: ' + active.y);
}, 100);
};
init();
#board {
padding: 20px;
z-index: -1;
}
.row {
height: 25px;
}
.cell {
position: relative;
display: inline-block;
width: 25px;
height: 25px;
border: 1px solid black;
text-align: center;
line-height: 25px;
cursor: default;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="board"></div>
<div id="info"></div>
<p>
Click on the board once to set focus. This lets the keyboard work. Press <strong>S</strong> to make a tile go down, press <strong>W</strong> to make a tile go up.
</p>
<button id="reset">Reset</button>
Uncaught RangeError: Maximum call stack size exceeded This error occurs when there is no breakpoint for recursion function. When you call any function from that function or such like that. Then the execution goes then caller function goes into stack and callee function gets into memory for execution. If there is no return statement or condition before recursion, then processor stack gets full and throws this error message.
In your case, you are calling moveDown from moveDown but there one condition which is always true and which is responsible for calling moveDown again, or same with moveUp.
Just debug with breakpoints, you will get where it is wrong.

Cannot read property of undefined caused by variables

I have a 2d array called 'map.curCellMap' storing 1's and 0's. I am using the function 'cells.getNeighbourCount' (below) to reference cells in this map.
Within the context of the 'cells.update' function (below) this is returning an undefined error. In firefox it reads 'TypeError: map.curCellMap[nextY] is undefined'. However, if I call 'cells.getNeighbourCount' with hardcoded values it does work.
What gives?
var cells = {
getNeighbourCount: function(x, y) {
/*
/* [y][x]
/* Start a top and move clockwise
*/
var neighbours = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1]],
count = 0;
for(i = 0; i < neighbours.length; i++) {
var curNeighbour = neighbours[i];
//Skip this iteration if neighbour is out of bounds
if((y + curNeighbour[0] < 0) || (y + curNeighbour[0] > ROWS) || (x + curNeighbour[1] < 0) || (x + curNeighbour[1] > COLS)) {
continue;
}
var nextY = y+curNeighbour[0],
nextX = x+curNeighbour[1];
if(map.curCellMap[nextY][nextX] == 1) {
count++;
}
}
return count;
},
update: function() {
for(y = 0; y < ROWS; y++) {
for(x = 0; x < COLS; x++) {
var numNeighbours = this.getNeighbourCount(x, y),
newCellState;
if(numNeighbours >= 2 && numNeighbours <= 3) {
newCellState = 1;
} else {
newCellState = 0;
}
map.nextCellMap[y][x] = newCellState;
}
}
map.curCellMap = map.nextCellMap;
}
}
var map = {
curCellMap: null,
nextCellMap: null,
//Map functions
init: function() {
this.curCellMap = this.generateRandomMap(0.05);
this.nextCellMap = this.curCellMap;
},
generateRandomMap: function(density) {
/*
/* Generates a random cell map
/* density = 0.00 -> No live cells, density = 1.00 -> All cells live
*/
var map = helpers.create2DArray(ROWS, COLS);
for(y = 0; y < ROWS; y++) {
for(x = 0; x < COLS; x++) {
var rand = helpers.getRandomNum(0, 1);
map[y][x] = (rand <= density) ? 1 : 0;
}
}
return map;
}
}
The problem was
if((y + curNeighbour[0] < 0) || (y + curNeighbour[0] > ROWS) || (x + curNeighbour[1] < 0) || (x + curNeighbour[1] > COLS)) {
Needed to read
if((y + curNeighbour[0] < 0) || (y + curNeighbour[0] > ROWS-1) || (x + curNeighbour[1] < 0) || (x + curNeighbour[1] > COLS-1)) {
OOPS!

Categories