I am trying to solve this leetcode problem (game of life): https://leetcode.com/problems/game-of-life
This is my code:
function isLive(board: number[][], row: number, column: number) {
let liveNeighbours = 0;
[row - 1, row, row + 1].forEach(r => {
if (r < 0 || r >= board.length) return;
[column - 1, column, column + 1].forEach(c => {
if (c === column && r === row) return;
if (c < 0 || c >= board[0].length) return;
if (board[r][c] === 1) liveNeighbours++
})
})
if (board[row][column] === 1 && (liveNeighbours === 3 || liveNeighbours === 2)) return true;
if (board[row][column] === 0 && liveNeighbours === 3) return true;
return false;
}
/**
Do not return anything, modify board in-place instead.
*/
function gameOfLife(board: number[][]): void {
let nextGen = Array(board.length).fill(Array(board[0].length).fill(0));
for (let i = 0; i < board.length; i++) {
for (let j = 0; j < board[0].length; j++) {
console.log("isLive row ", i, " col ", j, isLive(board, i, j))
if (isLive(board, i, j)) nextGen[i][j] = 1
}
}
console.log("next gen", nextGen);
board = nextGen;
};
I run the code with this input:
[
[0,1,0],
[0,0,1],
[1,1,1],
[0,0,0]
]
And it outputs this (same thing basically):
[
[0,1,0],
[0,0,1],
[1,1,1],
[0,0,0]
]
While it's expecting this:
[
[0,0,0],
[1,0,1],
[0,1,1],
[0,1,0]
]
Now what really drives me crazy, is the print logs. When I print for each cell whether it should be live or not, it comes back perfectly as it should be. This is the log:
isLive row 0 col 0 false
isLive row 0 col 1 false
isLive row 0 col 2 false
isLive row 1 col 0 true
isLive row 1 col 1 false
isLive row 1 col 2 true
isLive row 2 col 0 false
isLive row 2 col 1 true
isLive row 2 col 2 true
isLive row 3 col 0 false
isLive row 3 col 1 true
isLive row 3 col 2 false
Also, in the last log for printing nextGen, it print this:
next gen [ [ 1, 1, 1 ], [ 1, 1, 1 ], [ 1, 1, 1 ], [ 1, 1, 1 ] ]
So basically re-assigns all cells to 1, even though I can se not all statements are true.
Which is unlike anything. It doesn't fit the individual return I get for each cell, and doesn't even fit what it claims I'm returning even though it's basically at the end. Am I missing something about how to assign values to arrays?
EDIT: Instead of simply assigning board=nextGen I've also tried the following:
for (let i = 0; i < board.length; i++) {
for (let j = 0; j < board[0].length; j++) {
board[i][j] = nextGen[i][j];
}
}
I now get this as the output [[1,1,1],[1,1,1],[1,1,1],[1,1,1]] (the prit of nextGen).
EDIT 2: I've tried changing the function to simply return the count of neighbors and do the conditioning after. While I haven't got to moving the conditioning, I can see already that the is still an issue with assigning item to the new array.
This is my modified code (again, not complete, but the rest isn't relevant to the issue at this point):
function countNeighbors(board: number[][], row:number, column:number){
let liveNeighbors = 0;
[row-1, row, row+1].forEach(r=>{
if(r<0 || r>= board.length) return;
[column-1, column, column+1].forEach(c=>{
if(c === column && r=== row) return;
if(c<0 || c>= board[0].length) return;
if(board[r][c]===1) liveNeighbors++
})
})
return liveNeighbors;
}
/**
Do not return anything, modify board in-place instead.
*/
function gameOfLife(board: number[][]): void {
let neighbors = Array(board.length).fill(Array(board[0].length).fill(0));
for (let i = 0; i<board.length; i++){
for (let j = 0; j<board[0].length; j++){
let numberOfNeighbors = countNeighbors(board,i,j);
console.log(i, j, numberOfNeighbors)
neighbors[i][j] = numberOfNeighbors
}
console.log("neighbors", neighbors)
}
};
I've added a console log after each iteration of i, and this is what it prints:
0 0 1
0 1 1
0 2 2
neighbors [ [ 1, 1, 2 ], [ 1, 1, 2 ], [ 1, 1, 2 ], [ 1, 1, 2 ] ]
1 0 3
1 1 5
1 2 3
neighbors [ [ 3, 5, 3 ], [ 3, 5, 3 ], [ 3, 5, 3 ], [ 3, 5, 3 ] ]
2 0 1
2 1 3
2 2 2
neighbors [ [ 1, 3, 2 ], [ 1, 3, 2 ], [ 1, 3, 2 ], [ 1, 3, 2 ] ]
3 0 2
3 1 3
3 2 2
neighbors [ [ 2, 3, 2 ], [ 2, 3, 2 ], [ 2, 3, 2 ], [ 2, 3, 2 ] ]
SO basically each row gets duplicated to all rows. That seems to be what's messing my function in either way I've done it, but why is that happening?
Is it something to do with the behavior of fill?
Edit 3: Ok, so i's about how the new array is created. If I create it like this for my test case:
let neighbors = [[],[],[],[]];
Then everything works just fine.
Would love to know though, what is the cause of this behavior? Is there a neat way of creating this array that won't cause this?
I can just push new empty arrays for each iteration of i while would work and isn't very consuming, but I thought that how I did it first was more elegant.