2017-11-23 2 views
0

私は解決するいくつかのバグがあるプログラミング演習を解決しようとしています。最終的には、各時間ステップで、セルが正確に3つの近隣(セルが8つの隣接セルを有する)を有する場合、それは「生きる」ことになり、より少ない2つ以上の隣人よりも、それは '死んでいる'(隣人がグリッドの周りを回るところ)です。次のように最初のスクリプトは次のとおりです。onclickのコールバック関数の範囲を調整する

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 

問題は、私は信じて、次のとおりです。

<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> 

問題は、私は、私は次のエラーが表示されるコンソールで、「次へ」ボタンを押すと、ということですBoardMain()関数で定義されており、これはonclickコールバック関数の対象外です。

最初のアプローチは、Main()関数の外にあるBoardの初期化をグローバル変数にして、すべての関数呼び出しからBoardを削除することでした。しかしこれは優雅なアプローチのようには見えません。代わりに、私は次のようにFunction.prototype.call()を使用してみました:

しかし
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; 
} 

が、今私は新しいエラーを取得する:

<a href="#IGoNowhere" onclick="NextStep.call(Main, Board); DrawBoard.call(Main, Board);">Next -></a> 

をさらに、私は、インデックスが範囲外に行く避けるためにwrapAround機能を実装しました

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関数はエラーを発生させていませんが、次の関数はNextStepMakeLiveは、です。しかし、これは同じ意味で定義されており、同様の呼び出しが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) 

私はなぜこれをビットnonplussedよこの方法では、単純な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 

は何とか古いコードのキャッシュされたバージョンを使用してコンソールですか? (私はブラケットでライブプレビューを使用しています)。

アップデート2

Iポストインクリメントの代わりにプリインクリメント(参照http://jsforallof.us/2014/07/10/pre-increment-vs-post-increment/)を使用しなければならないためです。 ++xx++に変更すると問題が解決しました。

+1

であなたのundefined値を引き起こすことを考えるxsizeysize<=)までのすべての道を行く持っている 'Board'はグローバルです変数。 'Main()'はそれを割り当て、ローカルに宣言しません。 – Barmar

+1

古典的な[Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)。 –

答えて

1

エラーは可変スコープとは関係ありません。 Boardはグローバル変数なので、どの関数からでもアクセスできます。

x = 0dx = -1のときにBoardアレイの外部にアクセスし、wrapAround()機能で修正したため、元の問題が発生しました。

次の問題は、NextStepのループが行き過ぎてしまうことです。行インデックスは0からxsize-1になり、列は0からysize-1になります。しかし、ループはx <= xsizey <= ysizeを使用しているので、存在しないBoard[xsize]にアクセスしようとします。ループのように<=<に変更すると、Main()になります。

1

if(n=3) MakeLive(Board,x,y);は、あなたのn = 3n === 3する必要があり、私はあなたがするたびにMakeLive(Board,x,y);呼び出しますtruthy値を引き起こすことになるn3を割り当てたくないと確信しています。

また、NextStepであなたのxyはあなたが<を使用する他のどこでも一方で、Board[x]

関連する問題