import processing.core.PApplet;
import static java.lang.System.out;
public class GoL2 extends PApplet {
int rectSideLength = 25; // rectSideLength = length of each side of the rectangles drawn that represent cells
int generation = 0;
int windowWidth = 1920;
int windowHeight = 950;
int[][] currentGeneration = new int[windowWidth][windowHeight]; // currentGeneration = 2D array to gold cell values of current generation
int[][] nextGeneration = new int[windowWidth][windowHeight]; // nextGeneration = 2D array to hold cell values of next generation
int sumOfNeighbors;
int temporarySumOfNeighbors;
int counter;
public static void main(String[] args) {
PApplet.main("GoL2");
}
public void settings() {
size(windowWidth, windowHeight);
}
int numRectWidth = width / rectSideLength; // numRectWidth = the number of rectangles wide that will fit in the x axis of window
int numRectHeight = height / rectSideLength; // numRectHeight = the number of rectangles that will fit in the y axis of window
// The previous statements are here because they need the size of the frame to
// be set in order to accurately set the variables, lest they end up equal to 100
/* public void setup() {
* background(255);
* frameRate(1);
* for (int y = 0; y < windowHeight; y++) { // For each row,
* for (int x = 0; x < windowWidth; x++) { // For each element in the current row,
* currentGeneration[x][y] = (int) random(0, 2); // Set element (cell) equal to either 0 or 1 (on or off)
* }
* }
* } */
public void setup() {
background(255);
frameRate(1);
for (int y = 0; y < windowHeight; y++) { // For each row,
for (int x = 0; x < windowWidth; x++) { // For each element in the current row,
currentGeneration[x][y] = 0; // Set element (cell) equal to either 0 or 1 (on or off)
}
}
currentGeneration[25][25] = 1;
currentGeneration[25][26] = 1;
currentGeneration[25][27] = 1;
currentGeneration[26][27] = 1;
currentGeneration[27][26] = 1;
}
public void draw() {
numRectWidth = width / rectSideLength;
numRectHeight = height / rectSideLength;
displayCurrentGeneration();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
fill(255, 20, 147);
textSize(30);
text(generation, 20, 30);
textSize(10);
text("25,25", 625, 645);
text("24,27", 600, 695);
text(generation, 580, 695);
generation++;
generateNextGeneration();
}
public void displayCurrentGeneration() {
background(255);
for (int y = 0; y < 950; y++) { // For each row,
for (int x = 0; x < 1920; x++) { // For each element in the current row,
if (currentGeneration[x][y] == 0) { // If element equals zero, make rectangle white
fill(255);
stroke(0);
} else if (currentGeneration[x][y] == 1) { // If element equals one, make rectangle black
fill(0);
stroke(255);
} else {
out.println("Inappropriate value for currentGeneration[" + x + "][" + y + "]. Value: "
+ currentGeneration[x][y] + ", generation: " + generation);
}
rect(x * rectSideLength, y * rectSideLength, rectSideLength, rectSideLength); // Display rectangle (cell)
}
}
// out.println("Generation " + generation);
}
public void generateNextGeneration() {
out.println("Generating gen " + generation);
for (int y = 1; y < numRectHeight - 1; y++) { // For each row,
for (int x = 1; x < numRectWidth - 1; x++) { // For each element in the current row,
sumOfNeighbors = 0;
sumOfNeighbors = getSumOfNeighbors(x, y);
if (sumOfNeighbors != 2 && sumOfNeighbors != 3) { // Death
nextGeneration[x][y] = 0;
} else if (sumOfNeighbors == 3 && currentGeneration[x][y] == 0) { // Birth
nextGeneration[x][y] = 1;
} else if ((sumOfNeighbors == 2 || sumOfNeighbors == 3) && currentGeneration[x][y] == 1) { // Stasis
nextGeneration[x][y] = 1;
}
}
}
currentGeneration = nextGeneration.clone();
}
public int getSumOfNeighbors(int xAxis, int yAxis) {
temporarySumOfNeighbors = 0;
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (xAxis == 24 && yAxis == 27 && j != 0 && i != 0) {
out.println("X" + j + ", Y" + i + ":: " + currentGeneration[xAxis + j][yAxis + i]);
} else if (xAxis == 24 && yAxis == 27 && j == 0 && i != 0) {
out.println("X" + ", Y" + i + ":: " + currentGeneration[xAxis + j][yAxis + i]);
} else if (xAxis == 24 && yAxis == 27 && j != 0 && i == 0) {
out.println("X" + j + ", Y" + ":: " + currentGeneration[xAxis + j][yAxis + i]);
} else if (xAxis == 24 && yAxis == 27 && j == 0 && i == 0) {
out.println("X" + ", Y" + ":: " + currentGeneration[xAxis + j][yAxis + i]);
}
temporarySumOfNeighbors += currentGeneration[xAxis + j][yAxis + i];
}
}
temporarySumOfNeighbors -= currentGeneration[xAxis][yAxis];
if (temporarySumOfNeighbors > 8) {
out.println("temporarySumOfNeighbors > 8: " + temporarySumOfNeighbors);
}
if (xAxis == 24 && yAxis == 27) {
out.println("Generation: " + generation + "- " + xAxis + ", " + yAxis + ": " + temporarySumOfNeighbors);
}
return temporarySumOfNeighbors;
}
}
我是一个尝试编写生命游戏的初学者,我不确定如何找到问题的根源。我将游戏设置为刚开始使用简单的滑翔机,并相信我可能已经找到了问题的影响。
我在细胞上放置标记以帮助跟踪它们。如果你看单元格(24,27),你至少会看到一个问题的例子。在控制台中,我在整个程序运行期间打印出该单元格的邻域。它似乎以某种方式检测到第(2)代在第1代中将具有的邻域(反之亦然)(假设第一代是第0代)。我不确定如何解释它,但如果你检查控制台输出并查看邻域,你会发现它在第1代中检测到第2代的邻域,反之亦然。这就是为什么当(24,27)在第一代中有3个邻居时,它只会在第3代中生存,而在第2代,它只有2个邻居。
如果您有任何问题,请告诉我,我发现很难解释我的问题。
此处更详细地解释了这个问题:http://imgur.com/gallery/iRc07/new
谢谢
答案 0 :(得分:0)
这是您问题的主要来源:
currentGeneration = nextGeneration.clone();
您可能会认为该行会将nextGeneration
中的所有内容复制到currentGeneration
中,而且确实会......但不会像您认为的那样。
nextGeneration
变量是2D数组。换句话说,它是一个数组数组。换句话说, nextGeneration
包含的值是数组。
当您调用数组的clone()
函数时,它会将旧数组的值复制到新数组中。您的问题是:您的值是数组。所以它复制了数组,而不是那些第二个数组中的值。
因此,nextGeneration
和currentGeneration
都指向相同的数组。所以现在当你计算下一代时,你正在改变当前一代的数组。这不起作用,因为生命游戏计算需要两个独立的阵列。
换句话说,您正在制作阵列的浅层副本。
使用更简单的程序可能更容易解释:
public class Test {
public static void main(String... args){
//create an array
int[][] array = {{1, 2, 3}, {4, 5, 6}};
//clone the array
int[][] arrayTwo = array.clone();
//change the original array
array[0][0] = 99;
//second array has also changed!
System.out.println(arrayTwo[0][0]);
}
}
长话短说:您几乎不应该使用clone()
功能。
您可以通过对数组进行深层复制来解决您的问题。有些库可以为您处理,或者您可以使用序列化,或者只编写自己的嵌套for
循环。
但更简单(我认为更正确)的解决方案是:在您不需要时停止使用类级变量。
除了您使用clone()
作为类级变量之外,nextGeneration
问题不会成为问题。这意味着它在调用generateNextGeneration()
之间保留其值。由于该值指向currentGeneration
内的数组,导致所有问题。
您已使用其他变量处理此问题:请注意在使用之前重置sumOfNeighbors
和temporarySumOfNeighbors
的方式。您可以使用nextGeneration
变量执行相同的操作。
但我会更进一步,摆脱所有这三个类级变量。将他们的声明移到使用它们的函数内部,这样你就不必担心它们在函数调用之间保持它们的值。
我还有两个注意事项:
你不应该从Thread.sleep()
函数(或任何事件函数)中调用draw()
。只需设置帧速率,让Processing为您处理时间。
你正在使用大量你没有画过的细胞。你的数组是1920x950,但你只是在绘制一小部分单元格。这会在您从未显示的单元上浪费大量的CPU时间。就像我在你的另一个问题中所说,你需要更加小心区分像素坐标和数组坐标。
无论如何,这是一个很好的问题。我觉得你越来越近了。你只需要摆脱那些额外的细胞,你就会处于相当不错的状态。祝你好运。
PS:我要在您的问题中添加processing标记。如果您将来有任何问题,确保包含此标记可能是个好主意。否则我不会看到它。 :P