2015-11-02 3 views
-4

im пытается кодировать Cellular Automaton с использованием C++, по какой-то причине, когда программа запускается, мои правила либо, кажется, применяются неправильно или вообще не применяются. Любой совет будет принят во внимание.Cellular 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; 

} 
+1

Этот путь слишком расплывчатый: правила применяются неправильно. Постарайтесь быть очень конкретными в том, что он должен делать, что он делает и как это неправильно. Кроме того, вы можете попробовать пройти через это с помощью отладчика. – MicroVirus

ответ

0

Во-первых, когда вы оцениваете клеточных автоматов, вам нужно обработать краевые условия должным образом. Вы идете от обоих концов массивов в неопределенное поведение, когда вы пишете:

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

Поскольку i идет от 0 к width-1. Поэтому, когда i равен 0, 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]. Вы делаете это для всей вашей другой обработки правил. Так что да, ваши правила не влияют на результат вообще.

0

Это похоже на алгоритм/симуляцию Game-of-Life, где пользователь может определить ширину игрового поля и какие правила активны для изучения результатов для нескольких поколений.

Поле игры представляет собой массив [ширина], инициализированный «~» (пустой?) С одним «X» (активным) в 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 = '~'; 

Итак, я это допущу.

Во-вторых, вы неправильно набранный правило № 1 вокруг линии # 84:

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++.

Смежные вопросы