我正在尝试解决一个编程练习,其中有几个错误需要修复。最终,它应该代表一个带有细胞网格的动画,在每个时间步,如果一个细胞正好有三个活着的邻居(每个细胞有8个邻居),它就“生命”,如果它少了超过2个或超过3个邻居,它'死'(邻居'环绕'网格)。初始脚本如下:
<html>
<head>
<script type="text/javascript">
var Board;
var xsize = 10;
var ysize = 10;
var dead = 0;
var alive = 1;
function Neighbors(Board, x, y)
{
var n = 0
for(dx=-1;dx < 1; ++dx)
for(dy=-1;dy < 1; ++dy)
{
var ax = x+dx;
var ay = y+dy;
if(Board[ax][ay]==alive) ++n;
}
return n;
}
function Kill(Board,x,y)
{
if(Board[x][y] == alive)
Board[x][y] = dead;
}
function MakeLive(Board,x,y)
{
if(Board[x][y] == dead)
Board[x][y] = alive;
}
function NextStep(Board)
{
for(var x = 0; x <= xsize; ++x)
{
for(var y = 0; y <= ysize; ++x)
{
n = Neighbors(Board,x,y);
if(n=3) MakeLive(Board,x,y);
if((n<2)||(n>3)) Kill(Board,x,y);
}
}
}
function DrawBoard(Board)
{
var Text = "";
for(var y = 0; y < ysize; ++y)
{
for(var x = 0; x < xsize; ++x)
Text += Board[x][y]==alive ? "o":"_";
Text += "<br/>";
}
document.getElementById("board").innerHTML = Text;
}
function Main()
{
// *** Change this variable to choose a different baord setup from below
var BoardSetup = "blinker";
Board = new Array(xsize);
for(var x = 0; x < xsize; ++x)
{
Board[x] = new Array(ysize);
for(var y = 0; y < ysize; ++y)
Board[x][y] = 0;
}
if(BoardSetup == "blinker")
{
Board[1][0] = 1;
Board[1][1] = 1;
Board[1][2] = 1;
}
else if(BoardSetup == "glider")
{
Board[2][0] = 1;
Board[2][1] = 1;
Board[2][2] = 1;
Board[1][2] = 1;
Board[0][1] = 1;
}
else if(BoardSetup == "flower")
{
Board[4][6] = 1;
Board[5][6] = 1;
Board[6][6] = 1;
Board[7][6] = 1;
Board[8][6] = 1;
Board[9][6] = 1;
Board[10][6] = 1;
Board[4][7] = 1;
Board[6][7] = 1;
Board[8][7] = 1;
Board[10][7] = 1;
Board[4][8] = 1;
Board[5][8] = 1;
Board[6][8] = 1;
Board[7][8] = 1;
Board[8][8] = 1;
Board[9][8] = 1;
Board[10][8] = 1;
}
DrawBoard(Board);
}
</script>
</head>
<body onload="Main()">
<div id="board">
</div>
<a href="#IGoNowhere" onclick="NextStep(Board);DrawBoard(Board);">Next -></a>
</body>
</html>
问题是,如果我按下“下一步”按钮,在控制台中我会看到以下错误:
Uncaught TypeError: Cannot read property '-1' of undefined
at Neighbors (life_broken__281_29.html:19)
at Function.NextStep (life_broken__281_29.html:42)
at HTMLAnchorElement.onclick (life_broken__281_29.html:117)
Neighbors @ life_broken__281_29.html:19
NextStep @ life_broken__281_29.html:42
onclick @ life_broken__281_29.html:117
我认为,问题是Board
在Main()
函数中定义,这不在onclick
回调函数的范围内。
我最初的方法是将Board
的初始化移到Main()
函数之外,使其成为全局变量,并从所有函数调用中删除Board
。然而,这似乎不是一种优雅的方法。相反,我尝试使用Function.prototype.call(),如下所示:
<a href="#IGoNowhere" onclick="NextStep.call(Main, Board); DrawBoard.call(Main, Board);">Next -></a>
此外,我实现了wrapAround
函数以避免索引超出范围:
function Neighbors(Board, x, y)
{
var n = 0
for(dx=-1;dx < 1; ++dx)
for(dy=-1;dy < 1; ++dy)
{
var ax = x+dx;
var ay = y+dy;
ax = wrapAround(ax, xsize);
ay = wrapAround(ay, ysize);
if(Board[ax][ay]==alive) ++n;
}
return n;
}
function wrapAround(coordinate, size) {
var result = coordinate % size;
if (result < 0) {
result += size;
}
return result;
}
然而,现在我收到一个新错误:
life_broken__281_29.html:42 Uncaught TypeError: Cannot read property '0' of undefined
at MakeLive (life_broken__281_29.html:42)
at Function.NextStep (life_broken__281_29.html:53)
at HTMLAnchorElement.onclick (life_broken__281_29.html:127)
显然,Neighbors
函数现在没有引发任何错误,但NextStep
,MakeLive
中的下一个函数是。然而,我不明白,因为它们都在相同的“级别”中定义,并且在NextStep
中具有类似的调用。任何人都可以解释这里的问题吗?
更新
确实Board
在全局范围内声明,因此不需要Function.prototype.call()
。 (我习惯于Python,声明和定义总是在同一个地方)。我还将布尔表达式更改为(x === 3)
。
但是,由于某种原因,即使我将x
替换为10
,<=
仍然可以升级到<
。以下是更新的代码,其中包含用于调试的console.log
语句:
<html>
<head>
<script type="text/javascript">
var Board;
var xsize = 10;
var ysize = 10;
var dead = 0;
var alive = 1;
function Neighbors(Board, x, y)
{
var n = 0
for(dx=-1;dx < 1; ++dx)
for(dy=-1;dy < 1; ++dy)
{
var ax = x+dx;
var ay = y+dy;
ax = wrapAround(ax, xsize);
ay = wrapAround(ay, ysize);
if(Board[ax][ay]==alive) ++n;
}
return n;
}
function wrapAround(coordinate, size) {
var result = coordinate % size;
if (result < 0) {
result += size;
}
return result;
}
function Kill(Board, x, y)
{
if (Board[x][y] == alive)
Board[x][y] = dead;
}
function MakeLive(Board, x, y)
{
if (Board[x][y] == dead)
Board[x][y] = alive;
}
function NextStep(Board)
{
for(var x = 0; x < xsize; ++x)
{
for(var y = 0; y < ysize; ++x)
{
n = Neighbors(Board,x,y);
console.log("x = " + x + ", y = " + y + ", n = " + n);
if (n===3) MakeLive(Board,x,y);
if ((n<2)||(n>3)) Kill(Board,x,y);
}
}
}
function DrawBoard(Board)
{
var Text = "";
for(var y = 0; y < ysize; ++y)
{
for(var x = 0; x < xsize; ++x)
Text += Board[x][y]==alive ? "o":"_";
Text += "<br/>";
}
document.getElementById("board").innerHTML = Text;
}
function Main()
{
// *** Change this variable to choose a different baord setup from below
var BoardSetup = "blinker";
Board = new Array(xsize);
for(var x = 0; x < xsize; ++x)
{
Board[x] = new Array(ysize);
for(var y = 0; y < ysize; ++y)
Board[x][y] = 0;
}
if(BoardSetup == "blinker")
{
Board[1][0] = 1;
Board[1][1] = 1;
Board[1][2] = 1;
}
else if(BoardSetup == "glider")
{
Board[2][0] = 1;
Board[2][1] = 1;
Board[2][2] = 1;
Board[1][2] = 1;
Board[0][1] = 1;
}
else if(BoardSetup == "flower")
{
Board[4][6] = 1;
Board[5][6] = 1;
Board[6][6] = 1;
Board[7][6] = 1;
Board[8][6] = 1;
Board[9][6] = 1;
Board[10][6] = 1;
Board[4][7] = 1;
Board[6][7] = 1;
Board[8][7] = 1;
Board[10][7] = 1;
Board[4][8] = 1;
Board[5][8] = 1;
Board[6][8] = 1;
Board[7][8] = 1;
Board[8][8] = 1;
Board[9][8] = 1;
Board[10][8] = 1;
}
DrawBoard(Board);
}
</script>
</head>
<body onload="Main()">
<div id="board">
</div>
<a href="#IGoNowhere" onclick="NextStep(Board); DrawBoard(Board);">Next -></a>
</body>
</html>
这是我点击“下一步”时控制台的结果:
x = 0, y = 0, n = 0
life_broken__281_29.html:53 x = 1, y = 0, n = 1
life_broken__281_29.html:53 x = 2, y = 0, n = 0
life_broken__281_29.html:53 x = 3, y = 0, n = 0
life_broken__281_29.html:53 x = 4, y = 0, n = 0
life_broken__281_29.html:53 x = 5, y = 0, n = 0
life_broken__281_29.html:53 x = 6, y = 0, n = 0
life_broken__281_29.html:53 x = 7, y = 0, n = 0
life_broken__281_29.html:53 x = 8, y = 0, n = 0
life_broken__281_29.html:53 x = 9, y = 0, n = 0
life_broken__281_29.html:53 x = 10, y = 0, n = 0
life_broken__281_29.html:36 Uncaught TypeError: Cannot read property '0' of undefined
at Kill (life_broken__281_29.html:36)
at NextStep (life_broken__281_29.html:55)
at HTMLAnchorElement.onclick (life_broken__281_29.html:128)
我有点不知道为什么会这样,因为这种方式的简单for
循环确实有效:
for (var i = 0; i < 10; ++i) {
console.log("i = " + i);
}
VM158:2 i = 0
VM158:2 i = 1
VM158:2 i = 2
VM158:2 i = 3
VM158:2 i = 4
VM158:2 i = 5
VM158:2 i = 6
VM158:2 i = 7
VM158:2 i = 8
VM158:2 i = 9
undefined
控制台是否以某种方式使用旧代码的缓存版本? (我正在使用Brackets中的实时预览)。
更新2
这是因为我应该使用后增量而不是预增量(参见http://jsforallof.us/2014/07/10/pre-increment-vs-post-increment/)。将++x
更改为x++
解决了问题。
答案 0 :(得分:1)
错误与变量范围无关。 Board
是一个全局变量,因此任何函数都可以访问它。
您的原始问题是因为您在Board
和x = 0
时访问了dx = -1
数组,并使用wrapAround()
函数修复了此问题。
下一个问题是NextStep
中的循环走得太远了。行索引从0
变为xsize-1
,列从0
变为ysize-1
。但是那里的循环使用x <= xsize
和y <= ysize
,因此它会尝试访问不存在的Board[xsize]
。将<=
更改为<
,就像Main()
中的循环一样。
答案 1 :(得分:1)
if(n=3) MakeLive(Board,x,y);
,您的n = 3
应为n === 3
,我确定您不想将3
分配给n
会产生truthy
值,每次都会调用MakeLive(Board,x,y);
。
此外,在NextStep
中,您的x
和y
一直向xsize
和ysize
(<=
)发送,而您使用<
的其他任何地方,认为这导致undefined
Board[x]
值