2

我在用 C++ 编写康威的生命游戏时遇到了一些问题。我觉得我有一个好的开始,我只是需要一些方向。首先,当我尝试运行程序时,我总是得到一个空白的控制台。而且我也不确定为董事会上没有完整八个邻居的地方编码的最佳方式。任何帮助,将不胜感激。

规则:

您将“硬编码”一个起始配置。用户不需要能够提供不同的启动配置(这只会使您的程序复杂化)。

建议:寻找稳定的配置。也就是说,寻找不断重复模式的社区。重复中的配置数称为周期。有一些配置是固定的,它们会继续不变。一个可能的项目是找到这样的配置。

提示:定义一个名为 generation 的 void 函数,它接受我们称为 world 的向量(通过引用调用或使用指针),其中包含当前(或初始)配置。该函数扫描向量并修改单元格,按照前面列出的规则标记单元格的出生和死亡。这涉及依次检查每个细胞,要么杀死细胞,让它存活,要么如果细胞是空的,则决定是否应该出生一个细胞。请注意,如果您的代码在它正在修改的同一向量中计算邻居,则游戏将无法运行。在修改之前必须创建世界向量的副本,并且该副本用于计算邻居,同时在原始向量中打开或关闭单元格。

应该有一个函数 display 接受向量世界并在屏幕上显示网格。在调用生成和显示之间存在某种时间延迟是合适的。为此,您的程序应在您按下 Return/Enter 时生成并显示下一代。您可以自由地自动执行此操作(设置实时延迟,而不是等待用户按键),但程序不需要自动化。

如果您想“延迟”网格的显示,而不是等待用户键入内容并在显示下一个网格之前按 Enter,那么您将需要以某种方式暂停或“休眠”您的程序。如果您使用的是 Microsoft Windows,请执行以下操作:

我们将每个小区定义为有八个相邻小区。单元格的邻居是直接在上方、下方、右侧、左侧、左右斜上方和左右斜下方的单元。检查边缘的邻居时要小心;您可以决定边缘单元是否在边缘之外有活的或死的邻居。

如果一个被占用的细胞有零个或一个邻居,它就会死于孤独。如果一个被占用的小区有超过三个邻居,它就会死于过度拥挤。

如果一个空单元格恰好有三个被占用的相邻单元格,则会生成一个新单元格来替换该空单元格。

出生和死亡是瞬时的,发生在世代的变化中。一个因任何原因而死亡的细胞可能有助于出生,但一个新生的细胞不能使一个正在死亡的细胞复活,一个细胞的死亡也不会阻止另一个细胞的死亡,例如,通过减少当地人口。

到目前为止我的代码:

/*

Filename: main.cpp
Author:
Version: 20120920
Description:

*/

#include<iostream>
#include<vector>
#include<unistd.h>
#include<cstdlib>

using namespace std;

/*Change the values of your world matrix*/
#define ROWS 21
#define COLS 80

/*Change the values for dead or alive*/
#define DEAD  ' '
#define ALIVE '*'

/*Function Prototype for generation*/
void generation (vector< vector<char> > &world, vector< vector<char> > &world_copy);

/*Function Prototype for display*/
void display(vector< vector<char> >);

int main()
{

    vector< vector<char> > world(ROWS, vector<char>(COLS, DEAD));
    vector< vector<char> > world_copy(ROWS, vector<char>(COLS, DEAD));

    /*Set ALIVE cells*/
    world[1][1] = world[1][2] = world[1][3] = ALIVE;

    while(true);
    {
        /*Clear screen and display world*/
        system("cls");
        display(world);

        /*Wait*/
        usleep(8000);

        /*Update World*/
        generation(world, world_copy);

    }
    return 0;
}

/*Copy the contents of world into world_copy*/
void generation (vector< vector<char> > &world, vector< vector<char> > &world_copy)
{
    int ALIVE_count = 0;

    for (int i = 0; i < ROWS; i++)
    {
        for (int j = 0; j < COLS; j++)
        {
            /*Checks neighbors for life*/
            if(world_copy[i-1][j+1] == ALIVE)
            {
                ALIVE_count++;
            }
            if(world_copy[i][j+1] == ALIVE)
            {
                ALIVE_count++;
            }
            if(world_copy[i+1][j+1] == ALIVE)
            {
                ALIVE_count++;
            }
            if(world_copy[i-1][j] == ALIVE)
            {
                ALIVE_count++;
            }
            if(world_copy[i+1][j] == ALIVE)
            {
                ALIVE_count++;
            }
            if(world_copy[i-1][j-1] == ALIVE)
            {
                ALIVE_count++;
            }
            if(world_copy[i][j-1] == ALIVE)
            {
                ALIVE_count++;
            }
            if(world_copy[i+1][j-1])
            {
                ALIVE_count++;
            }

            /*Rule Section*/
            /*Death by loneliness. 0 or 1 neighbors.*/
            if (world_copy[i][j] == ALIVE && (ALIVE_count == 0 || ALIVE_count == 1))
            {
                world[i][j] = world_copy[i][j];
                world[i][j] == DEAD;
            }
            /*Live to next generation. 2 or 3 neighbors.*/
            else if(world_copy[i][j] == ALIVE && (ALIVE_count == 2 || ALIVE_count == 3))
            {
                world[i][j] = world_copy[i][j];
                world[i][j] == ALIVE;
            }
            /*Death by overcrowding. More than 3 neighbors.*/
            else if (world_copy[i][j] == ALIVE && ALIVE_count > 3)
            {
                world[i][j] = world_copy[i][j];
                world[i][j] == DEAD;
            }
            /*Birth. Exactly 3 neighbors.*/
            else if (world_copy[i][j] == ALIVE && ALIVE_count ==3)
            {
                world[i][j] = world_copy[i][j];
                world[i][j] == ALIVE;
            }
        }
    }
}

/*Display the world*/
void display(vector< vector<char> > &world)
{
    for (int i = 0; i < ROWS; i++)
    {
        for (int j = 0; i < COLS; j++)
        {
            cout << world[i][j];
        }

        cout << endl;
    }
}

更新:

在 main 的 while 语句中发现了一个问题。我曾有一个 ; 过了一会儿:

while(true);
{
/*Clear screen and display world*/
system("cls");
display(world);

/*Wait*/
Sleep(800);

/*Update World*/
generation(world, world_copy);
} 

我继续把它拿出来,但现在我得到了一个未定义的引用,指向“在 while 循环中显示”。

4

2 回答 2

4

不正确的循环条件

void display(vector< vector<char> > &world)
{
    for (int i = 0; i < ROWS; i++)
    {
        for (int j = 0; i < COLS; j++)
        {
            cout << world[i][j];
        }

        cout << endl;
    }
}

应该:

void display(vector< vector<char> > &world)
{
    for (int i = 0; i < ROWS; i++)
    {
        for (int j = 0; j < COLS; j++)
        {
            cout << world[i][j];
        }

        cout << endl;
    }
}

注意内部 FOR 循环的条件子句。

不正确的 while() 循环终止

while(true);

应该:

while(true)

赋值操作不当

这种模式在代码中重复了很多次。保留第一个任务。第二个根本没有完成。这是一个条件表达式求值。看起来像这样:

world[i][j] = world_copy[i][j];
world[i][j] == DEAD;

应该看起来像这样(注意我猜测副本是先前的状态。不确定您的意图是什么):

world_copy[i][j] = world[i][j];
world[i][j] = DEAD;

链接期间未定义的符号 display()

文件顶部的函数原型是:

void display(vector< vector<char> > );

然而下面的实现是:

void display(vector< vector<char> >& )

注意第二个中的引用参数,第一个中的 by-val 参数。不同的参数列表 = 不同的签名。可能第二个是您的想法,因此更改原型(第一个)以匹配实现(第二个)。

数组索引超出范围

您的代码中有几个地方(特别是 generation() 函数)索引超出了分配向量的末尾。例如,

/*Checks neighbors for life*/
if(world_copy[i-1][j+1] == ALIVE)
{
    ALIVE_count++;
}
if(world_copy[i][j+1] == ALIVE)
{
    ALIVE_count++;
}
if(world_copy[i+1][j+1] == ALIVE)

这些[j+1][i+1]索引一旦达到(i==(ROWS-1))or的条件就会使您的流程出错(如果您幸运的话) (j==(COLS-1)),因为 ROWS 和 COLS 是您战场的分配大小。同样的 for[i-1][j-1]whenijare 在它们的循环开始处(i=0 或 j=0)

有很多方法可以解决这个问题,从逻辑到不检查会溢出的内容(易于检测)到用一个从不触及的死区(涉及更多,但编码更有趣)来构建你的字段。

底线:你必须学会​​有效地调试你的程序。如果您认为专业工程师只是喷出正确的代码,请再想一想。平均而言,我们花费一半的时间(字面意思)调试编写的代码。如果您发现自己花费更少,很可能您没有对代码进行所需的尽职调查(坦率地说,这是应得的)。

于 2012-09-22T23:44:41.700 回答
0

我不确定为板上没有完整八个邻居的地方编码的最佳方法

您可能应该将这些视为特殊情况。例如,i=0与循环分开的代码可以从i = 1.

于 2012-09-22T23:45:47.727 回答