康威生命游戏算法错误(a.k.a 复制二维数组时出现问题)
Error in Conway's game of life algorithm (a.k.a problems copying two-dimensional arrays)
花了一些时间在 HTML canvas 中使用 Javascript 实施 Conways 生活游戏。
我的细胞没有正常运作。它似乎拾取了比实际更多的相邻单元格,并删除了不应删除的单元格。如有任何帮助,我们将不胜感激!
//Globals
var currentCells = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
];
var currentGrid = currentCells;
var lastGrid = currentCells;
var cellsX = currentCells[1].length;
var cellsY = currentCells.length;
var canvas_id = "gameGrid";
var gridWidth = 100;
var gridHeight = 50;
var c = document.getElementById("gameGrid");
var ctx = c.getContext("2d");
var cellWidth = gridWidth / cellsX;
var cellHeight = gridHeight / cellsY;
ctx.fillStyle = "yellow";
window.setInterval(step, 1000);
function move(){
for(var a=0;a<cellsX;a++) {
for(var b=0; b<cellsY;b++) {
if (a > 0 && b > 0 && a < cellsY - 1 && b < cellsX){ //centre cells only
var currentNeighbours = neighbourCount(a, b);
if (lastGrid[a][b] == 0){
if(currentNeighbours == 3){
currentGrid[a][b] = 1;
}
}else if (lastGrid[a][b] == 1){
if(currentNeighbours > 3 || currentNeighbours < 2){
currentGrid[a][b] = 0;
//console.log("triggered " + currentNeighbours);
}
}
}
}
}
lastGrid = currentGrid;
}
function neighbourCount(a, b){
var currentNeighbours = 0;
if(lastGrid[a-1][b] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a+1][b] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a][b-1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a][b+1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a-1][b-1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a+1][b+1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a-1][b+1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a+1][b-1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
//console.log(currentNeighbours);
return currentNeighbours;
}
function Draw(){
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
for(var a=0;a<cellsY;a++) {
var startX = 0;
for(var b=0; b<cellsX;b++) {
startX = cellWidth * b;
if (currentGrid[a][b] == 1){
ctx.fillRect(startX,(a*cellWidth) ,cellWidth,cellWidth);
}
ctx.strokeRect(startX,(a*cellWidth) ,cellWidth,cellWidth);
}
}
}
function step(){
move();
Draw();
}
<canvas id="gameGrid">
</canvas>
这里的问题是 lastGrid
和 currentGrid
都引用同一个数组及其子数组。当您编写以下代码时:
var currentCells = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
];
var currentGrid = currentCells;
var lastGrid = currentCells;
...您只创建了一个 数组,其中三个 名称引用了它。因此,当你在操纵 currentGrid
时,你实际上也在操纵 lastGrid
.
改为这样做:
var currentCells = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
];
var currentGrid = currentCells.map(function(arr){return arr.slice()});
var lastGrid = currentCells.map(function(arr){return arr.slice()});
...这是您 move()
的最后一行:
lastGrid = currentGrid.map(function(arr){return arr.slice()});
...因为,如上所述 here, the .slice()
method creates a new array with the same values and returns the reference to it. The .map()
方法遍历每个顶级数组项并执行请求的功能。
一般情况下,要复制一个一维数组,可以这样使用.slice()
:
newArray = oldArray.slice();
但是此方法不适用于二维数组,因为它只会为您提供一个新数组,其中包含指向与 oldArray
.[=26= 中引用的子数组相同的子数组的指针]
因此,您必须一次一个地遍历每个顶级数组和 .slice()
它们的子数组。这是通过 .map()
方法完成的。
花了一些时间在 HTML canvas 中使用 Javascript 实施 Conways 生活游戏。
我的细胞没有正常运作。它似乎拾取了比实际更多的相邻单元格,并删除了不应删除的单元格。如有任何帮助,我们将不胜感激!
//Globals
var currentCells = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
];
var currentGrid = currentCells;
var lastGrid = currentCells;
var cellsX = currentCells[1].length;
var cellsY = currentCells.length;
var canvas_id = "gameGrid";
var gridWidth = 100;
var gridHeight = 50;
var c = document.getElementById("gameGrid");
var ctx = c.getContext("2d");
var cellWidth = gridWidth / cellsX;
var cellHeight = gridHeight / cellsY;
ctx.fillStyle = "yellow";
window.setInterval(step, 1000);
function move(){
for(var a=0;a<cellsX;a++) {
for(var b=0; b<cellsY;b++) {
if (a > 0 && b > 0 && a < cellsY - 1 && b < cellsX){ //centre cells only
var currentNeighbours = neighbourCount(a, b);
if (lastGrid[a][b] == 0){
if(currentNeighbours == 3){
currentGrid[a][b] = 1;
}
}else if (lastGrid[a][b] == 1){
if(currentNeighbours > 3 || currentNeighbours < 2){
currentGrid[a][b] = 0;
//console.log("triggered " + currentNeighbours);
}
}
}
}
}
lastGrid = currentGrid;
}
function neighbourCount(a, b){
var currentNeighbours = 0;
if(lastGrid[a-1][b] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a+1][b] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a][b-1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a][b+1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a-1][b-1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a+1][b+1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a-1][b+1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
if(lastGrid[a+1][b-1] == 1){ //
currentNeighbours = currentNeighbours + 1;
}
//console.log(currentNeighbours);
return currentNeighbours;
}
function Draw(){
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
for(var a=0;a<cellsY;a++) {
var startX = 0;
for(var b=0; b<cellsX;b++) {
startX = cellWidth * b;
if (currentGrid[a][b] == 1){
ctx.fillRect(startX,(a*cellWidth) ,cellWidth,cellWidth);
}
ctx.strokeRect(startX,(a*cellWidth) ,cellWidth,cellWidth);
}
}
}
function step(){
move();
Draw();
}
<canvas id="gameGrid">
</canvas>
这里的问题是 lastGrid
和 currentGrid
都引用同一个数组及其子数组。当您编写以下代码时:
var currentCells = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
];
var currentGrid = currentCells;
var lastGrid = currentCells;
...您只创建了一个 数组,其中三个 名称引用了它。因此,当你在操纵 currentGrid
时,你实际上也在操纵 lastGrid
.
改为这样做:
var currentCells = [
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
];
var currentGrid = currentCells.map(function(arr){return arr.slice()});
var lastGrid = currentCells.map(function(arr){return arr.slice()});
...这是您 move()
的最后一行:
lastGrid = currentGrid.map(function(arr){return arr.slice()});
...因为,如上所述 here, the .slice()
method creates a new array with the same values and returns the reference to it. The .map()
方法遍历每个顶级数组项并执行请求的功能。
一般情况下,要复制一个一维数组,可以这样使用.slice()
:
newArray = oldArray.slice();
但是此方法不适用于二维数组,因为它只会为您提供一个新数组,其中包含指向与 oldArray
.[=26= 中引用的子数组相同的子数组的指针]
因此,您必须一次一个地遍历每个顶级数组和 .slice()
它们的子数组。这是通过 .map()
方法完成的。