Cannot read property '-1' of undefined
This is my first attempt at using classes in a Javascript project - I'm trying to implement Conway's Game of Life in HTML5 Canvas. Here's the code. As you can see, the first generation renders fine, but there's something wrong with the next()
function that prevents it from running any further. (I did notice t开发者_JS百科hat the error in question is actually being thrown at the last line of get()
, one of the functions called by neighbors()
, which is called by next()
. I can't find any problems in either function, but clearly something's wrong!)
The problem is [that the assumption about %
is wrong and thus] the guards in the get/set
functions do not work as intended:
-1 % 42 // results in -1
Happy coding.
I would consider removing the guards in the get/set
functions and using sentinel values (or other neighbor edge-casing) for the border (e.g. the first/last row and column are never actually drawn to the screen).
This can avoid a significant number of guard checks -- get/set
will be called a whole bunch of times each iterations (I wouldn't even have them as functions). I consider the removal of get/set
and guards "okay" because these operations are internal to the process and closely tied to the algorithm -- they are not directly exposed and JavaScript is only so fast.
Doing a "full grid neighbor check" is C * O(h*w)
per cycle. While it has the same complexity, a significantly smaller C
can make the program run much quicker.
The line
x = x % this.width;
does not work as expected:
-1 % 640
gives
-1
Easy fix:
x = (x + this.width) % this.width;
Let's examine the first cell. Say x
is 0 and y
is 0. During your processing of that cell, you're going to end up checking this.map[-1][-1]
. Since this.map[-1]
is undefined, you're not going to be able to find element -1 in it, even if it did exist (which it doesn't).
You have a few options:
- Check that
x > 0
before grabbing anything to the left of that cell, andx < this.width - 1
before grabbing anything to the right of it. Similar story fory
andthis.height
. - Make sure
this.map[x - 1]
orthis.map[x + 1]
is defined before trying to access anything in it. Same withy +/- 1
-- if it's undefined, consider it false. - Define
this.map[-1]
andthis.map[whatever][-1]
as false, as well asthis.map[this.width]
andthis.map[whatever][this.height]
. - Redo your math so that
x - 1
becomes(x + width - 1) % width
. Same withy - 1
. That ought to make the map wrap around.
You have this loop in next
:
for(var y = 0; y < this.height; y++){
for(var x = 0; x < this.width; x++){
newMap[x][y] = this.get(x, y);
//Rule 1: any live cell with fewer than two live neighbors dies
if(this.get(x, y) == true && this.neighbors(x, y) < 2){
newMap[x][y] = false;
}
//...
so in your first iteration, x
and y
are zero. Now have a look what neighbors
is doing:
this.neighbors = function(x, y){
n = 0;
//...
if(this.get(x-1, y-1)){n++;}
//...
return n;
}
If x
and y
are 0
, it tries to inspect cell (-1,-1)
:
this.map[x][y] = val;
But your map
has only positive integer keys.
If you want to "wrap around", increment the values in get
in order to avoid negative values:
x = (x + this.width) % this.width;
y = (y + this.height) % this.height;
精彩评论