N
N
nikbond2015-12-20 17:13:33
C++ / C#
nikbond, 2015-12-20 17:13:33

How to find an error in the code (Game of Life)?

Please help me find the error.
I wrote the cellular automaton "Life" (description can be found on Wikipedia, or in the comments to the code below).
When everything seemed to be done, I found that the algorithm actually does not work correctly.
For example, this can be seen when the input is such a file ("1.txt"):
10 10
0 0 0 0 0 0 0 0 0 0
0 1 1 0 0 0 0 1 0 0
0 1 1 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
According to the logic of the game, the "square" has a stable position and should not change, the "strip" should "rotate", and the figure below should be a glider . But that doesn't happen.
At first I thought the mistake was that I didn’t overload the assignment operator, and the standard one assigned not the values ​​of a two-dimensional array, but a pointer to it (thus, both objects referred to the same array, and gibberish came out). But after I overloaded the assignment operator, the behavior of the program did not change.

/** \file
  * \brief Клеточный автомат "Жизнь"
  *
  * Программа реализует клеточный автомат "Жизнь"("Life").
  * Дано поле, в котормо каждая клетка может быть либо "живой", либо "мертвой".
  * Пользователь задает начальные условия - первое поколение. Программа генерирует новое поколения (состояние поля) по таким правилам:
  * Если клетка имеет более 3 или менее 2 соседей, она становится/остается мертвой.
  * Если клетка имеет строго 3 соседя, она становится/остается живой.
  * Новые поколения генерируется до тех пор, пока все клетки клетки не умрут либо не образуют стабильное состояние (перестанут меняться).
*/

#include <iostream>
#include <fstream>
#include <iomanip>
#include <ctime>
#include <random>
#include <windows.h>

//#include <chrono>
//#include <thread>

using namespace std;

class Fields {
    /* Класс описывает состояние поля ("Поколения жизни"). */
    private:
        int n; // количество рядков поля
        int m; // количество столбцов поля
        bool **array; //игровое поле. Если клетка поля true - она жива, если false - мертва.
    public:
        Fields(int a, int b);
        Fields(const Fields& );
        Fields(ifstream &);
        Fields& operator= (Fields&r);
        void print();
        void run( Fields last);
};

int countOfChanges = 1; //счетчик изменений состояния игрового поля .

int main(){
    int countLife = 0; //счетчик состояний игрового поля("Поколений жизни")
    int n, m; //длинна и ширина поля
    cout << "Hello. This is game of life. " << endl
         << "1. Create the random generated field" << endl
         << "2. Create the field with file" << endl;
    int choice;
    cin >> choice;

    Fields current(0, 0); // текущее поколение


    switch(choice){
        case 1:{
            cout << "Enter the number of rows and columns of field" << endl;
            cout << setw(9) << "Rows: ";
            cin >> n;
            cout << setw(9) << "Columns: ";
            cin >> m;
            Fields randomField = Fields(n, m);
            current = randomField;
            break;
        }
        case 2:{
            ifstream fin("1.txt");
            Fields fileField = Fields(fin);
            current = fileField;
            break;
        }
    }

    Fields next(current); // следующее поколение

    cout << "Field: "<< endl;
    current.print();

    while (countOfChanges != 0){
        //system("cls");
        cout << ++countLife << "st generation: " << endl;
        countOfChanges = 0;
        next.run(current);
        current = next;
        current.print();
        Sleep(1000);
        //std::this_thread::sleep_for (std::chrono::seconds(1));
    }

    //system("cls");

    cout << endl << "This system has been alive for " << countLife - 1 << " steps." << endl;

    return 0;
}

void Fields:: run( Fields last ){

    /* Метод реализует логику игры. Проходит по всем клеткам поля last,
       считает количество соседей у каждой клетки и устанавливает новое состояние аналогичной клетки своего поля.
       Если изменения происходят, счетчик изменений увеличивается.
    */

    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){

            int neighbors = 0; //количество живых клеток-соседей

            if ( j - 1 > 0 ){   //тут и далее: проверка, не выходит ли "сосед" за пределы массива, чтобы можно было к нему обратиться
                if(last.array[i][j-1]){
                    neighbors++;
                }
            }
            if ( i + 1 < n && j - 1 > 0) {
                if(last.array[i+1][j-1]){
                    neighbors++;
                }
            }
            if ( i + 1 < n) {
                if(last.array[i+1][j] ){
                    neighbors++;
                }
            }
            if ( i + 1 < n && j - 1 > 0) {
                if(last.array[i+1][j-1]){
                    neighbors++;
                }
            }
            if ( j - 1  > 0) {
                if(last.array[i][j-1]){
                    neighbors++;
                }
            }
            if ( i - 1 > 0 && j + 1 < m ){
                if(last.array[i-1][j+1]){
                    neighbors++;
                }
            }
            if ( i - 1 > 0 ){
                if(last.array[i-1][j]){
                    neighbors++;
                }
            }
            if (  i -1 > 0 && j - 1 > 0){
                if(last.array[i-1][j-1]){
                    neighbors++;
                }
            }


            if (neighbors == 3 && last.array[i][j] == false){
                //если соседей строго 3, мертвая клетка оживает
                array[i][j] = true;
                ::countOfChanges++;
            }

            if ( (neighbors <= 2 || neighbors > 3 ) && last.array[i][j] == true) {
                //если соседей меньше или равно 2 или больше 3, живая клетка умирает
                array[i][j] = false;
                ::countOfChanges++;
            }
        }
    }
}

Fields:: Fields(int a, int b): n(a), m(b){

    array = new bool* [n];                         // объявление динамического двумерного массива
    for(int count = 0; count < n; count ++){        //
        array[count] = new bool [m];                //
    }                                               //

    mt19937 gen(time(0));                           // генератор псевдо-случайных чисел из с++11
    uniform_int_distribution <> dist(0, 1);         // распределение рандомайзера - целые числа 0 и 1
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            array[i][j] = dist(gen);                // рандомное заполнение двумерного массива 0 и 1
        }
    }
}

Fields:: Fields(const Fields& last){
    /* Конструктор копирования */

    n = last.n;
    m = last.m;

    array = new bool* [n];                         // объявление динамического двумерного массива
    for(int count = 0; count < n; count ++){        //
        array[count] = new bool [m];                //
    }

    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            array[i][j] = last.array[i][j];
        }
    }
}

Fields:: Fields(ifstream & fin){
    /* Создание поля с файла*/
    fin >> n;
    fin >> m;

    array = new bool * [n];                         // объявление динамического двумерного массива
    for(int count = 0; count < n; count ++){        //
        array[count] = new bool [m];                //
    }

    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            fin >> array[i][j];
        }
    }
}

Fields& Fields:: operator = (Fields &right){
    n = right.n;
    m = right.m;


    delete []array;

    array = new bool * [n];                         // объявление динамического двумерного массива
    for(int count = 0; count < n; count ++){        //
        array[count] = new bool [m];                //
    }

    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            array[i][j] = right.array[i][j];
        }
    }
    return *this;
}

void Fields:: print(){

    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            if(array[i][j]){
                cout << "*";
            }
            else{
                cout << " ";
            }
        }
        cout << endl;
    }
    cout << endl;
}

In general, help to find an error.

Answer the question

In order to leave comments, you need to log in

3 answer(s)
Владимир Мартьянов, 2015-12-20
@vilgeforce

Берете отладчик и смотрите как обсчитывается ваш файл.

Олег Цилюрик, 2015-12-20
@Olej

обнаружил, что алгоритм на самом деле работает не правильно.

Алгоритм не может работать неправильно ;-)
Неправильно работает ваш код, которым вы пытались реализовать этот алгоритм :-(
P.S. Неужели вы всерьёз рассчитывали, что кто-то станет разгребать такую простыню как вы приводите?
Научитесь задавать вопросы более конкретно.

Александр Ручкин, 2015-12-20
@VoidEx

1. Минимизируйте неправильный пример. Что именно неправильно? Полоска, квадрат?
2. Создайте как можно меньший пример, который работает некорректно, а с ним уже работайте отладчиком.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question