我正在重现 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
方法中有四个嵌套循环。你只需要两个,循环遍历网格中的每个单元格。你不需要最外面的两个,只需要里面的两个,所以去掉外面的两个。同时删除变量 repeat
、startX
和 startY
,因为您不需要它们。
您还需要遍历所有表达式,例如 visualize[startX + 1][startY]
,并将 startX
替换为 k
,将 startY
替换为 l
。
你的平方校验逻辑错误
将 startX
和 startY
替换为 k
和 l
后,以下行在您的代码中出现了两次:
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++;
}
此外,Left
、Right
、Up
和 Down
评论是错误的。 k
循环遍历行(即它是 y 坐标)并且 l
循环遍历每行中的单元格(x-坐标)。另外,k + 1
向下一格,而不是向上一格。
我试验了很久,就是看不出我在检测周围生命的错误在哪里!你们能不能看看我的代码,看看我的错误在哪里?代码中的所有内容都可以在检查周围生命之外完全发挥作用。
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
方法中有四个嵌套循环。你只需要两个,循环遍历网格中的每个单元格。你不需要最外面的两个,只需要里面的两个,所以去掉外面的两个。同时删除变量 repeat
、startX
和 startY
,因为您不需要它们。
您还需要遍历所有表达式,例如 visualize[startX + 1][startY]
,并将 startX
替换为 k
,将 startY
替换为 l
。
你的平方校验逻辑错误
将 startX
和 startY
替换为 k
和 l
后,以下行在您的代码中出现了两次:
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++;
}
此外,Left
、Right
、Up
和 Down
评论是错误的。 k
循环遍历行(即它是 y 坐标)并且 l
循环遍历每行中的单元格(x-坐标)。另外,k + 1
向下一格,而不是向上一格。