java - 为什么我的生命游戏(使用处理)中的世代乱序?

标签 java multidimensional-array processing conways-game-of-life

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;

 }

}

http://pastebin.com/GH51hXzJ

我是一名尝试编写生命游戏代码的初学者,我不确定如何找到问题的根源。我将游戏设置为从设置中的简单滑翔机开始,并且相信我可能已经发现了问题的影响。

我在细胞上放置标记以帮助跟踪它们。如果您观看 cell (24,27),您至少会看到该问题的一个示例。在控制台中,我在程序运行过程中打印出该单元格的邻域。它似乎以某种方式检测到 (24,27) 在第 1 代中第 2 代中将具有的邻域,反之亦然(假设第一代是第 0 代)。我不确定如何解释它,但如果您检查控制台输出并查看邻域,您会发现它检测到第 1 代中第 2 代的邻域,反之亦然。这就是为什么当 (24,27) 在第 1 代中有 3 个邻居时,它只在第 3 代中出现,而在第 2 代中,它只有 2 个邻居。

如果您有任何疑问,请告诉我,我发现很难解释我的问题。

此问题有更多解释:http://imgur.com/gallery/iRc07/new

谢谢

最佳答案

这是您问题的主要原因:

currentGeneration = nextGeneration.clone();

您可能认为该行会复制 nextGeneration 中的所有内容进入currentGeneration ,确实如此……但不是以您想象的方式。

nextGeneration变量是一个二维数组。换句话说,它是一个数组的数组。换句话说,nextGeneration 包含的值。是数组。

当您调用clone()时数组的函数,它将旧数组的值复制到新数组中。这是你的问题:你的值是数组。所以它复制数组,而不是第二个数组中的值。

因此,nextGenerationcurrentGeneration都指向相同的数组。因此,现在当您计算下一代时,您正在更改当前一代的数组。这不起作用,因为生命游戏计算需要两个单独的数组。

换句话说,您正在制作数组的浅拷贝

使用更简单的程序可能更容易解释:

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 内的数组,这就是导致所有问题的原因。

您已经使用其他变量处理了这个问题:注意您如何重置 sumOfNeighborstemporarySumOfNeighbors在使用它们之前。您可以使用 nextGeneration 执行相同的操作变量。

但我会更进一步,去掉所有这三个类级别的变量。将它们的声明移动到使用它们的函数内部,这样您就不必担心它们在函数调用之间维护它们的值。

另外两个注释:

你不应该真的打电话Thread.sleep()来自draw()函数(或任何事件函数)。只需设置帧速率,然后让处理为您处理时间。

您使用了大量未绘制的单元格。您的数组为 1920x950,但您只绘制了这些单元格的一小部分。这会在您从未显示的单元上浪费大量 CPU 时间。就像我在其他问题中所说的那样,您需要更加小心地区分像素坐标和数组坐标。

无论如何,这是个好问题。我想你越来越近了。你只需要去除那些多余的细胞,你就会保持良好的状态。祝你好运。

PS:我要添加一个标记您的问题。如果您将来有任何疑问,最好确保包含此标签。不然我就看不到了:p

关于java - 为什么我的生命游戏(使用处理)中的世代乱序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38382356/

相关文章:

java - JAXB。通过两个 xsd 验证 XML

java - Junit 在法语字符串断言上失败

javascript - 获取每个数字的每个动态文本框的值

javascript - 根据整数而不是字符串按升序对数组进行排序

java - 伊 bean 和玩吧!不使用 .select() 过滤列

java - 该算法的时间复杂度是多少?

json - 如何使用 angular2 react 形式构建嵌套数组?

java - 让我的椭圆成为一个按钮以在同一窗口上显示一些数据?

javascript - 无法弄清楚为什么变量在 p5.js 中未定义

javascript - loadPixels() 不适用于 p5.js