Game of Life p5.js细胞更新困难



我已经在p5.js中实现了Conway的game of life。我有一个函数来计算给定细胞的活邻居的数量,从我做的测试来看,它工作得很好。话虽如此,我在模拟的时候会有意想不到的行为:它没有遵循正确的模式。我从这里开始有3个对齐的方块(一个闪烁器),它应该旋转,但由于某种原因,它们都死了。

维基百科显示了闪烁器应该如何工作:https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Examples_of_patterns您可以将下面的源代码复制粘贴到https://editor.p5js.org/并自己查看。

我怀疑这个问题与复制板(单元格矩阵)有关,因为更新必须同时用于所有单元格,因此我们在内存中保留前一个板并根据前一个板更新当前板。

源:

//size of cell in pixels.
const size = 20;
const canvasWidth = 400;
const canvasHeight = 400;
const n = canvasWidth / size;
const m = canvasHeight / size;
class Cell {
constructor(status, position) {
this.status = status;
this.position = position;
}
}
let board = [];
function setup() {
//initialise matrix.
for(let i=0; i < m; i++) {
board[i] = new Array(n);
}
//fill matrix of cells.
for(let i=0; i < m; i++ ) {
for(let j=0; j < n; j++ ) {
board[i][j] = new Cell(false, [i*size, j*size]);
}
}
console.log("start", floor(m /2), floor(n / 2))
//[x, y] positions.
board[floor(m /2)][floor(n / 2)].status = true;
board[floor(m /2)+1][floor(n / 2)].status = true;
board[floor(m /2)+2][floor(n / 2)].status = true;
createCanvas(canvasWidth, canvasHeight);
frameRate( 1 )
}
//I'm 99.99% sure this function works, all the tests shows it does.
function updateCell(i, j, previousBoard) {
let count = 0;
//check neighbourgh cells.
for(let k=-1; k < 2; k++) {
for(let p=-1; p < 2; p++) {
if( !(i + k < 0 || j + p < 0 || j + p >= n || i + k >= m) ) {
if(k != 0 || p != 0) {         
if(previousBoard[i+k][j+p].status === true) {
count++;
}
}
}
}
}
console.log(count)
if((previousBoard[i][j].status === true) && (count < 2 || count > 3)) {
//console.log("false", i, j, count)
board[i][j].status = false;

} else if((count === 3) && (previousBoard[i][j].status === false)) { //if dead but 3 alive neighbours.
//alive
console.log("true", i, j, count)
board[i][j].status = true;

} else if((previousBoard[i][j].status === true) && (count === 2 || count === 3)) {
console.log("true", i, j, count)
board[i][j].status = true;
}
}
function copyMatrix() {
let newMatrix = []
for(let i=0; i < m; i++) {
//console.log(board[i])
newMatrix[i] = board[i].slice()
}
//console.log(newMatrix)
return newMatrix
} 
function draw() {
background(220);
//draw rectangles. 
for(let i=0; i < m; i++) {
for(let j=0; j < n; j++) {
if (board[i][j].status === true) {
fill('black');
} else {
fill('white');
}
rect(board[i][j].position[0], board[i][j].position[1], size, size);
}
}

//slice copies previous array into a new reference, previousBoard and board are 
//now independent.
let previousBoard = copyMatrix();

//updateCell(11, 9, previousBoard) //uncommenting this line creates weird results...
//console.log(previousBoard)
//update all cells based on previousBoard. (we'll modify board based on previous)
for(let i=0; i < m; i++) {
for(let j=0; j < n; j++) {
updateCell(i, j, previousBoard);
}
}
}
<html>
<head>
<Title>Gordon's Game of Life</Title>
<script src = "p5.js"></script>
<script src = "sketch.js"></script>
</head>
<body>
<h1>Gordon's Game of Life</h1>
</body>
</html>

问题是copyMatrix需要做一个深度拷贝。

将复制矩阵改为:

function copyMatrix() {
let newMatrix = []
for(let i=0; i < m; i++) {
newMatrix[i] = [];
for (let j=0;j< n;j++){
newMatrix[i][j] = new Cell(board[i][j].status, board[i][j].position);
}
}
return newMatrix
} 

这是你的代码与copyMatrix的变化和一个添加的滑翔器来帮助演示行为。

//size of cell in pixels.
const size = 20;
const canvasWidth = 400;
const canvasHeight = 400;
const n = canvasWidth / size;
const m = canvasHeight / size;
class Cell {
constructor(status, position) {
this.status = status;
this.position = position;
}
}
let board = [];
function setup() {
//initialise matrix.
for(let i=0; i < m; i++) {
board[i] = new Array(n);
}
//fill matrix of cells.
for(let i=0; i < m; i++ ) {
for(let j=0; j < n; j++ ) {
board[i][j] = new Cell(false, [i*size, j*size]);
}
}
board[floor(m /2)][floor(n / 2)].status = true;
board[floor(m /2)+1][floor(n / 2)].status = true;
board[floor(m /2)+2][floor(n / 2)].status = true;

// glider
board[0][0].status = true;
board[0][2].status = true;
board[1][1].status = true;
board[1][2].status = true;
board[2][1].status = true;

createCanvas(canvasWidth, canvasHeight);
frameRate( 1 )
}

function updateCell(i, j, previousBoard) {
let count = 0;
//check neighbourgh cells.
for(let k=-1; k < 2; k++) {
for(let p=-1; p < 2; p++) {
if( !(i + k < 0 || j + p < 0 || j + p >= n || i + k >= m) ) {
if(k != 0 || p != 0) {         
if(previousBoard[i+k][j+p].status === true) {
count++;
}
}
}
}
}

if((previousBoard[i][j].status) && (count < 2 || count > 3)) {
board[i][j].status = false;

} else if((count === 3) && (!previousBoard[i][j].status)) { //if dead but 3 alive neighbours.
board[i][j].status = true;

} else if((previousBoard[i][j].status) && (count === 2 || count === 3)) {
board[i][j].status = true;
}
}
function copyMatrix() {
let newMatrix = []
for(let i=0; i < m; i++) {
newMatrix[i] = [];
for (let j=0;j< n;j++){
newMatrix[i][j] = new Cell(board[i][j].status, board[i][j].position);
}
}
return newMatrix
} 
function draw() {
background(220);
//draw rectangles. 
for(let i=0; i < m; i++) {
for(let j=0; j < n; j++) {
if (board[i][j].status === true) {
fill('black');
} else {
fill('white');
}
rect(board[i][j].position[0], board[i][j].position[1], size, size);
}
}

let previousBoard = copyMatrix();

//updateCell(11, 9, previousBoard) //uncommenting this line creates weird results...
//console.log(previousBoard)
//update all cells based on previousBoard. (we'll modify board based on previous)
for(let i=0; i < m; i++) {
for(let j=0; j < n; j++) {
updateCell(i, j, previousBoard);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.min.js"></script>

对于滑翔机,此设置演示了所有三种可能的模式。我们从一个移动的spaceship滑翔机和一个oscillator开始,当滑翔机运行到振荡器时,我们有几个迭代,打破了这两种模式,然后它安定下来成为一个2x2still life

最新更新