开发者

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, and x < this.width - 1 before grabbing anything to the right of it. Similar story for y and this.height.
  • Make sure this.map[x - 1] or this.map[x + 1] is defined before trying to access anything in it. Same with y +/- 1 -- if it's undefined, consider it false.
  • Define this.map[-1] and this.map[whatever][-1] as false, as well as this.map[this.width] and this.map[whatever][this.height].
  • Redo your math so that x - 1 becomes (x + width - 1) % width. Same with y - 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;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜