Cellular Automaton,C ++,给应用规则带来麻烦

时间:2015-11-02 20:06:33

标签: c++ automaton

我试图使用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;

}

2 个答案:

答案 0 :(得分:0)

首先,当您评估细胞自动机时,您需要正确处理边缘条件。当您编写:

时,您正在从数组的两端走向未定义的行为
char left = parentArray[i-1];
char middle = parentArray[i];
char right = parentArray[i+1];

因为i0转到width-1。因此,当i0时,i-1将成为数组的索引-1,并在数组开头之前向后访问。当i+1等于i时,索引width-1同样会向前访问数组末尾。

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

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

ruleSet[7]是否包含1并不重要,因为您会立即使用childAray[i]中的内容覆盖ruleSet[7]。您为所有其他规则处理执行此操作。所以,是的,你的规则根本不影响结果。

答案 1 :(得分:0)

这似乎是一种游戏生命类型的算法/模拟,用户可以决定游戏领域的宽度以及哪些规则是活跃的,以便研究多代的结果。

游戏字段是数组[宽度],初始化为&#34;〜&#34; (空?)单个&#34; X&#34; (有效)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]

你的阵列是&#39; X&#39;和&#39;〜&#39; - 但你存储整数0和1,这将是字符&#39; \ x00&#39;和&#39; \ x01&#39;分别在你完成之后。 也许那仅仅是为了调试,但你把它留在了?或者那可能是你之后的错误?

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

我建议您改进数据结构,以便更轻松地使用。规则有两种模式: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 ++。