-4

我正在尝试使用 C++ 编写元胞自动机,但是由于某种原因,当程序运行时,我的规则似乎应用不正确,或者根本没有应用。任何意见,将不胜感激。

主要模拟功能:

/* Simulate Array */
int beginSimulation(char parentArray[],char childArray[],int width, int ruleSet[]){

  //get the amount of generations the program produces
    int generationNum;
    cout << "Please enter how many generations you would like to simulate" << endl;
    cin >> generationNum;

  for(int times=0; times< generationNum; times++){  

    //loop for applying ruleset to each cell in array

    for(int i=0; i< width; i ++){

        char left = parentArray[i-1];
        char middle = parentArray[i];
        char right = parentArray[i+1];


    // if statement that compares the current cells and its neighbours 
    // with the rules in the ruleset to define the current generation.

        if(left == 'X' && middle == 'X' && right == 'X'){

          if(ruleSet[7] == 1){
            childArray[i] = 'X';
          } else {
            childArray[i] = '~';
          }
          childArray[i] = ruleSet[7];
        }

         else if(left == 'X' && middle == 'X' && middle == '~'){

           if(ruleSet[6] == 1){                 //do this for each rule should work
            childArray[i] = 'X';
          } else {
            childArray[i] = '~';
          }
          childArray[i] = ruleSet[6];
        }

         else if (left == 'X' && middle == '~' && middle == 'X'){

          if(ruleSet[5] == 1){
            childArray[i] = 'X';
          } else {
            childArray[i] = '~';
          }
          childArray[i] = ruleSet[5];
         }

         else if (left == 'X' && middle == '~' && middle == '~'){

          if(ruleSet[4] == 1){
            childArray[i] = 'X';
          } else {
            childArray[i] = '~';
          }
          childArray[i] = ruleSet[4];
         }

         else if (left == '~' && middle == 'X' && middle == 'X'){

          if(ruleSet[3] == 1){
            childArray[i] = 'X';
          } else {
            childArray[i] = '~';
          }
          childArray[i] = ruleSet[3];
         }


         else if (left == '~' && middle == 'X' && middle == '~'){

          if(ruleSet[2] == 1){
            childArray[i] = 'X';
          } else {
            childArray[i] = '~';
          }
          childArray[i] = ruleSet[2];
         }

         else if (left == '~' && middle == '~' && middle == 'x'){

          if(ruleSet[1] == 1){
            childArray[i] = 'X';
          } else {
            childArray[i] = '~';
          }
          childArray[i] = ruleSet[1];
         }

         else if (left == '~' && middle == '~' && middle == '~'){
          childArray[i] = ruleSet[0];
          if(ruleSet[0] == 1){
            childArray[i] = 'X';
          } else {
            childArray[i] = '~';
          }
          childArray[i] = ruleSet[0];
         }

    }



      //for loop that iterates through the array and display all its elements
      for(int i = 0; i < width; i++)
      {

      cout << childArray[i];
      }

      cout<< endl;

      // loop to make the current generation the past generation for the next 
      //iteration of the code

      for(int c=0; c< width; c ++){
        parentArray[c] = childArray[c];
      }

  }
}

使用 beginSimulation 的函数:

/* Initialize Array */
int initializeArrays(char parentArray[],char childArray[],int width, int ruleSet[]){
  //cout << "Please enter the size of the array" << endl;
  //cin >> width;

  cout << "Please enter the rule you would like to simulate" << endl;
  int userInput = 0; //initialises userInput variable to be passed
  cin >> userInput;     //into the insertItem function    

    for(int x=0; x<width; x++){

      if(x==(width/2)){
        parentArray[(width/2)] = 'X';
        continue;
      }
        cout << "";
        parentArray[x] = '~'; /* or whatever number you want */

    }
    /* parentArray[0..width-1] = "~~...~~X~...~~"
     *                                   ^
     *                                   \- at width/2
     */

    cout << parentArray << endl;

    for(int i=0; i<width; i++){
      childArray[i] = '~'; /* or whatever number you want */
      cout << "";
    }
    /* childArray[0...width - 1] = "~~...~~" */

    cout << childArray << endl;

    /* User input is bit mask to activate rules 0..7
     * e.g. input = 10 = 0x0A = 0b1010 => rule 1 and 3 activated */
    for (int z=7; z>(-1); z --){

      ruleSet[z] = userInput % 2;
      userInput = userInput/2;
     } 



     cout << ruleSet[0] << endl;
     cout << ruleSet[1] << endl;
     cout << ruleSet[2] << endl;
     cout << ruleSet[3] << endl;
     cout << ruleSet[4] << endl;
     cout << ruleSet[5] << endl;
     cout << ruleSet[6] << endl;
     cout << ruleSet[7] << endl;

    beginSimulation(parentArray, childArray, width, ruleSet);

    return 0;

}
4

2 回答 2

0

这似乎是一种生命游戏的算法/模拟,用户可以在其中决定游戏领域的宽度以及哪些规则处于活动状态,以便研究几代人的结果。

游戏字段为 array[width],初始化为“~”(空?),在width / 2. ruleSet 中的规则将作用于这个数组,在一个模拟步骤后产生下一代。

首先,您显然没有为该站点运行此代码并对其进行编辑,请参见第 13 行:

    for(int i=0; i< width; i ++){

        char left = parentArray[i-1]; // <-- What will happen for i == 0?
        char middle = parentArray[i];
        char right = parentArray[i+1];
        ...
    }

你可能有一些特殊情况需要处理i == 0,可能

if (i == 0)
  left = '~';

所以我会假设。

其次,您在第 84 行错误地输入了第 1 条规则:

else if (left == '~' && middle == '~' && middle == 'x'){ // <-- small Latin x

我不确定会发生什么,因为除了规则 #0 之外的所有规则都是相同的代码,并且所有规则都做同样的事情。因此,您不应该在原始帖子中包含这么多代码。

无论如何,看看任何规则:

childArray[i] = ruleSet[0]; // this line in ruleSet[0] only
if(ruleSet[0] == 1){
  childArray[i] = 'X';
} else {
  childArray[i] = '~';
}
childArray[i] = ruleSet[0]; // overwrite childArray[i]

您的数组是 'X' 和 '~' 的序列 - 但是您存储整数 0 和 1,完成后它们将分别是字符 '\x00' 和 '\x01'。也许那只是为了调试,但你把它留在里面了?或者也许这就是你所追求的错误?

由于所有 if 子句仅匹配 '~' 和 'X'(和 'x')的组合,因此您的模拟将在第一步之后停止,并且在打开任何规则时始终产生相同的结果。


我建议你改进你的数据结构以便更容易使用。规则有两种模式:search,找到时将替换为replace

typedef struct rule {
    char search[3];
    char replace[3];

    rule(char* searchPattern, char* replacePattern) {

        memcpy(&search, searchPattern, sizeof(search));
        memcpy(&replace, replacePattern, sizeof(replace));

    }
} rule_t;

比赛场地是一个保存其宽度和实际数据的结构。自定义operator=为我们创建了整个字段的深层副本。

typedef struct field {
    size_t width;
    char* data;

    field(size_t field_width) {

        width = field_width;
        data = new char[width + 1];
        memset(data, '~', width);
        data[width] = '\0';
        /* catch out of memory exception here */
    }

    ~field() {

        width = 0;
        delete[] data;

    }

    field& operator=(const field& rhs) {
        /* prevent self-assignment */
        if (this == &rhs)
            return *this;
        this->width = rhs.width;
        delete[] data;
        this->data = new char[width + 1];
        /* catch out of memory exception here */
        memcpy(this->data, rhs.data, width + 1);
        return *this;

    }

} field_t;

主要算法

for (int generation = 0; generation < numGenerations; generation++) {

    myFieldAfter = myFieldBefore; /* deep copy of field */

    /* sliding window pointers */
    char *windowBefore = myFieldBefore.data;
    char *windowAfter = myFieldAfter.data;
    /* we have to stop sizeof(rule_t.search) - 1 = 3 - 1 = 2 bytes before end */
    for (size_t x = 0; x < myFieldBefore.width - 2; x++) {

        /* apply rules hierarchically */
        for (auto it = activeRules.begin(); it != activeRules.end(); it++) {

            if (!(memcmp(it->search, windowBefore, sizeof(it->search)))) {
                memcpy(windowAfter, it->replace, sizeof(it->replace));
                break; /* only apply first matching rule */
            }

        }

        /* move windows */
        windowBefore++;
        windowAfter++;

    }

    std::cout << "Generation " << generation << ": " << myFieldBefore.data << "\n";
    myFieldBefore = myFieldAfter; /* deep copy back */

}

我建议您从命令行解析参数,例如调用可能看起来像myCellAutomaton 32 5 "1,3"获取宽度为 32 的字段,模拟 5 代并使用规则 #1 和 #3。看看 Boost.Program_options。最终程序的粗略草图如下所示:

#include <iostream>
#include <string>
#include <cstring>
#include <vector>

/* definitions from above */

int main(int argc, char** argv) {

    int numGenerations;
    int width;
    std::vector<rule_t> activeRules;

    /* parse command line arguments */
    numGenerations = 5;
    width = 32;

    /* example rule */
    rule_t myRule("X~~", "XX~");
    /* vector of active rules */
    activeRules.push_back(myRule);

    field_t myFieldBefore(width);
    myFieldBefore.data[width / 2] = 'X';
    field_t myFieldAfter(width);

    /* algorithm here */

}

输出如下:

Generation 0: ~~~~~~~~~~~~~~~~X~~~~~~~~~~~~~~~
Generation 1: ~~~~~~~~~~~~~~~~XX~~~~~~~~~~~~~~
Generation 2: ~~~~~~~~~~~~~~~~XXX~~~~~~~~~~~~~
Generation 3: ~~~~~~~~~~~~~~~~XXXX~~~~~~~~~~~~
Generation 4: ~~~~~~~~~~~~~~~~XXXXX~~~~~~~~~~~

我希望这个答案能让您大致了解该怎么做。我使用简单的结构和标准调用来保持简单,尽管这使得整个程序是 C-ish 而不是纯 C++。

于 2015-11-02T22:01:33.117 回答
0

首先,在评估元胞自动机时,需要正确处理边缘条件。当您编写时,您正在从数组的两端进入未定义的行为:

char left = parentArray[i-1];
char middle = parentArray[i];
char right = parentArray[i+1];

因为i0width-1。因此 when iis 0,i-1将被索引-1到您的数组中并在数组开始之前向后访问。当等于时,索引i+1同样将向前访问数组的末尾。iwidth-1

其次,您尝试使用您的规则根据当前值驱动单元格的下一个值会被下一条语句无条件地覆盖。你有这样的陈述:

if(ruleSet[7] == 1){
    childArray[i] = 'X';
} else {
    childArray[i] = '~';
}
childArray[i] = ruleSet[7];

ruleSet[7]是否包含 a无关紧要,1因为您会立即childAray[i]ruleSet[7]. 您为所有其他规则处理执行此操作。所以是的,你的规则根本不会影响结果。

于 2015-11-02T21:34:36.343 回答