我正在重现 John Conway 的 Game Of Life。然而,我对游戏规则的检查并没有正确地检测到周围的生命。为什么是这样?

I'm recreating John Conway's Game Of Life. However, my checks for the rules of the game aren't correctly detecting surrounding lives. Why is this?

我试验了很久,就是看不出我在检测周围生命的错误在哪里!你们能不能看看我的代码,看看我的错误在哪里?代码中的所有内容都可以在检查周围生命之外完全发挥作用。

P.S。抱歉搞砸了格式。我正在使用 Sublime,这是自动格式化的最佳效果。

对于那些不熟悉的人,这里是生命游戏的规则:https://bitstorm.org/gameoflife/

import java.util.*;
import java.lang.*;
import java.io.*;

class Life
{
    public static void main(String[] args)
    {
        Scanner in = new Scanner(System.in);
        String userin = in.nextLine();
        int x = 8;
        int y = 8;      
        int [][] visualize;
        if(userin.equals("glider"))
        {
            visualize = new int [][]{
                //0 is used as a boundary, 1 represents a dead cell, 2 represents an alive cell
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 1, 1, 1, 1, 1, 1, 0},
                {0, 1, 1, 1, 1, 1, 1, 0},
                {0, 1, 1, 1, 2, 1, 1, 0},
                {0, 1, 1, 1, 1, 2, 1, 0},
                {0, 1, 1, 2, 2, 2, 1, 0},
                {0, 1, 1, 1, 1, 1, 1, 0},
                {0, 0, 0, 0, 0, 0, 0, 0}
            };
            for (int i = 0; i <= 7; i++)
            {
                for (int j = 0; j <= 7; j++)
                {
                    if (visualize[i][j] == 2) {
                        System.out.print("*");
                    } else if (visualize[i][j] == 1)
                    {
                        System.out.print(".");
                    } else if (visualize[i][j] == 0)
                    {
                        System.out.print("_");
                    }
                }
                System.out.println();
            }
            nextGen(visualize, x, y);
        } else if(userin.equals("own"))
        {
            visualize = new int [8][8];
            for(int o = 1; o <= 6; o++) //Starting it a pos 1 means pos 0 is automaically filled with a "0", which is used as the boundary
            {
                visualize[o] = new int[x];
                for(int p = 1; p <= 6; p++) //Starting it a pos 1 means pos 0 is automaically filled with a "0", which is used as the boundary
                {
                    visualize[o][p] = in.nextInt();
                }
                System.out.println(0);
                System.out.println();
            }
            for (int i = 0; i <= 7; i++)
            {
                for (int j = 0; j <= 7; j++)
                {
                    if(visualize[i][j] == 2) {
                        System.out.print("*");
                    } else if (visualize[i][j] == 1)
                    {
                        System.out.print(".");
                    } else if (visualize[i][j] == 0)
                    {
                        System.out.print("_");
                    }
                }
                System.out.println();
            }
            nextGen(visualize, x, y);
        }
        else if(userin.equals("test"))
        {
            visualize = new int [][]{
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 1, 1, 1, 1, 1, 1, 0},
                {0, 1, 2, 2, 1, 1, 1, 0},
                {0, 1, 2, 1, 1, 1, 1, 0},
                {0, 1, 1, 1, 1, 1, 1, 0},
                {0, 1, 1, 1, 1, 1, 1, 0},
                {0, 1, 1, 1, 1, 1, 1, 0},
                {0, 0, 0, 0, 0, 0, 0, 0}
            };
            for (int i = 0; i <= 7; i++)
            {
                for (int j = 0; j <= 7; j++)
                {
                    if (visualize[i][j] == 2) {
                        System.out.print("*");
                    } else if (visualize[i][j] == 1)
                    {
                        System.out.print(".");
                    } else if (visualize[i][j] == 0)
                    {
                        System.out.print("_");
                    }
                }
                System.out.println("_");
            }
            nextGen(visualize, x, y);
        }
    }
    static void nextGen(int visualize[][], int x, int y)
    {
        int[][] life = new int[x][y];
        int alive = 0;
        //Starts at array-point 1,1
        int startX = 1;
        int startY = 1;
        System.out.println();
        System.out.println();
        System.out.println("________");
        System.out.print("_");
        for(int repeat = startX; repeat <= 6; repeat++)
        {

            while(startY <= 6)
            {
                for(int k = startX; k <=6; k++)
                {
                    for(int l = startY; l <=6; l++)
                    {
                        //BEGIN CHECK FOR SURROUNDING LIVES
                        if(!(visualize[startX + 1][startY] == 0))
                        {
        if(visualize[startX + 1][startY] == 2) //Right 1
        {
            alive++;
        }
    }
    if(!(visualize[startX][startY + 1] == 0))
    {
        if(visualize[startX][startY + 1] == 2) //Up 1
        {
            alive++;
        }
    }
    if(!(visualize[startX + 1][startY + 1] == 0))
    {
        if(visualize[startX + 1][startY + 1] == 2) // Right 1, Up 1
        {
            alive++;
        }
    }
    if(!(visualize[startX - 1][startY] == 0))
    {
            if(visualize[startX - 1][startY] == 2) //Left 1
            {
                alive++;
            }       
        }
        if(!(visualize[startX][startY - 1] == 0))
        {
            if(visualize[startX][startY - 1] == 2) // Down 1
            {
                alive++;
            }
        }
        if(!(visualize[startX - 1][startY - 1] == 0))
        {
            if(visualize[startX - 1][startY - 1] == 2) //Left 1, Down 1
            {
                alive++;
            }
        }
        if(!(visualize[startX + 1][startY - 1] == 0))
        {
        if(visualize[startX + 1][startY - 1] == 2) //Right 1, Down 1
        {
            alive++;
        }
    }
    if(!(visualize[startX - 1][startY - 1] == 0))
    {
            if(visualize[startX - 1][startY - 1] == 2) //Left 1, Down 1
            {
                alive++;
            }
        }
        //CHECKS IF THERE ARE EXACTLY 3 LIVES AROUND AN AREA. IF NOT, IT KILLS THAT AREA
        if(alive == 3)
        {
            visualize[k][l] = 2;

        } else {
            visualize[k][l] = 1;
        }
    }
}

if (visualize[startX][startY] == 2) {
    System.out.print("*");
} else if (visualize[startX][startY] == 1)
{
    System.out.print(".");
}   
//Performs the check going down the Y-axis
startY++;
}
System.out.println("_");
System.out.print("_");
//After
startX++;
startY = 1;

}
System.out.println("_______");
}
}

好吧,老实说,这里有几处错误:

您有不必要且令人困惑的循环

您的 nextGen 方法中有四个嵌套循环。你只需要两个,循环遍历网格中的每个单元格。你不需要最外面的两个,只需要里面的两个,所以去掉外面的两个。同时删除变量 repeatstartXstartY,因为您不需要它们。

您还需要遍历所有表达式,例如 visualize[startX + 1][startY],并将 startX 替换为 k,将 startY 替换为 l

你的平方校验逻辑错误

startXstartY 替换为 kl 后,以下行在您的代码中出现了两次:

                    if (!(visualize[k - 1][l - 1] == 0)) {
                        if (visualize[k - 1][l - 1] == 2) //Left 1, Down 1
                        {
                            alive++;
                        }
                    }

因此,您计算了相邻八个单元格之一的两次,而其中一个根本没有。

要解决此问题,请将此代码的出现之一替换为以下代码:

                    if (!(visualize[k - 1][l + 1] == 0)) {
                        if (visualize[k - 1][l + 1] == 2) //Left 1, Up 1
                        {
                            alive++;
                        }
                    }

您在计算下一代时正在修改当前代

在 Life 中,您无法在尝试计算出下一代是什么的同时修改世界的当前世代。否则,您可以将一个细胞标记为死亡,而该细胞是保持另一个细胞存活所必需的。相反,您必须创建第二个数组并在其中记录下一代的状态。

您已经创建了第二个数组 life,但您似乎根本没有使用它。所以,让我们使用它。一旦你弄清楚一个细胞应该是活的还是死的,将该值分配给 life[k][l] 而不是 visualize[k][l].

你还打印出一个由 *. 字符组成的小网格,代表下一代的状态。这将必须使用 life 而不是 visualize.

你搞错了生活规律

您的代码目前旨在将任何正方形标记为活的,如果它恰好有三个邻居,否则为死的。这不是生活的方式。

如果一个活细胞有两个或三个邻居,它就会存活,否则它就会死亡。恰好有三个邻居的空单元格变得活跃。

下面的代码实现了这个逻辑:

            if (visualize[k][l] == 2 && (alive == 2 || alive == 3)) {
                // Live cell stays alive if 2 or 3 neighbours
                life[k][l] = 2;
            }
            else if (visualize[k][l] == 1 && alive == 3) {
                // Dead cell becomes live if 3 neighbours
                life[k][l] = 2;
            }
            else {
                // Anything else: cell either dies or stays dead.
                life[k][l] = 1;
            }

您忘记重置 alive 计数器

您在 nextGen 的开头将变量 alive 设置为 0,但是在计算每个单元格的存活邻居数时您没有将其重置为零。这意味着 alive 因此正在计算到目前为止遇到的每个细胞的存活邻居的数量。用不了多久就会超过 3,一切都会结束。

您需要在 l 循环开始时将 alive 重置回零。


我对您的 nextGen 方法进行了所有这些更改并且它似乎有效,因为它显示了我希望从滑翔机上看到的一代。这是我最终得到的结果(IntelliJ 对其进行了一些格式化,因此它的格式与您的代码的格式不同):

    static void nextGen(int visualize[][], int x, int y) {
        int[][] life = new int[x][y];
        int alive = 0;

        System.out.println();
        System.out.println();
        System.out.println("________");
        System.out.print("_");

        for (int k = 1; k <= 6; k++) {
            for (int l = 1; l <= 6; l++) {
                alive = 0;
                //BEGIN CHECK FOR SURROUNDING LIVES
                if (!(visualize[k + 1][l] == 0)) {
                    if (visualize[k + 1][l] == 2) //Right 1
                    {
                        alive++;
                    }
                }
                if (!(visualize[k][l + 1] == 0)) {
                    if (visualize[k][l + 1] == 2) //Up 1
                    {
                        alive++;
                    }
                }
                if (!(visualize[k + 1][l + 1] == 0)) {
                    if (visualize[k + 1][l + 1] == 2) // Right 1, Up 1
                    {
                        alive++;
                    }
                }
                if (!(visualize[k - 1][l] == 0)) {
                    if (visualize[k - 1][l] == 2) //Left 1
                    {
                        alive++;
                    }
                }
                if (!(visualize[k][l - 1] == 0)) {
                    if (visualize[k][l - 1] == 2) // Down 1
                    {
                        alive++;
                    }
                }
                if (!(visualize[k - 1][l - 1] == 0)) {
                    if (visualize[k - 1][l - 1] == 2) //Left 1, Down 1
                    {
                        alive++;
                    }
                }
                if (!(visualize[k + 1][l - 1] == 0)) {
                    if (visualize[k + 1][l - 1] == 2) //Right 1, Down 1
                    {
                        alive++;
                    }
                }
                if (!(visualize[k - 1][l + 1] == 0)) {
                    if (visualize[k - 1][l + 1] == 2) //Left 1, Up 1
                    {
                        alive++;
                    }
                }

                if (visualize[k][l] == 2 && (alive == 2 || alive == 3)) {
                    life[k][l] = 2;
                }
                else if (visualize[k][l] == 1 && alive == 3) {
                    life[k][l] = 2;
                }
                else {
                    life[k][l] = 1;
                }

                if (life[k][l] == 2) {
                    System.out.print("*");
                }
                else if (life[k][l] == 1) {
                    System.out.print(".");
                }
            }

            System.out.println("_");
            System.out.print("_");
        }
        System.out.println("_______");

        // Copy the 'life' array back to 'visualize', so that the
        // next generation could be calculated from it.
        for (int i = 1; i < 6; ++i)
        {
            visualize[i] = life[i];
        }
    }

花时间了解更改,以及此代码为何有效。

终于,你写了八次这样的代码:

                if (!(visualize[k + 1][l] == 0)) {
                    if (visualize[k + 1][l] == 2) //Right 1
                    {
                        alive++;
                    }
                }

您可以写 if (something != 0) 而不是 if (!(something == 0)) ...。但是,您可以进一步简化此代码:如果一个单元格等于 2,它也自动不等于 0,因此您可以改为编写以下内容:

                if (visualize[k + 1][l] == 2) //Right 1
                {
                    alive++;
                }

此外,LeftRightUpDown 评论是错误的。 k 循环遍历行(即它是 y 坐标)并且 l 循环遍历每行中的单元格(x-坐标)。另外,k + 1 向下一格,而不是向上一格。