Задать вопрос
@nikbond

Как найти ошибку в коде (Игра "Жизнь")?

Помогите найти ошибку.
Писал клеточный автомат "Жизнь"(описание можно посмотреть на википедии, либо в комментариях к коду ниже).
Когда все вроде бы сделал, обнаружил, что алгоритм на самом деле работает не правильно.
Например, это видно, когда на вход идет такой файл("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

По логике игры, "квадратик" имеет стабильное положение и не должен меняться, "полоска" должна "вращаться", а фигура снизу представлять из себя глайдер. Но этого не происходит.
Сначала я думал, ошибка в том, что я не перегрузил оператор присваивания, а стандартный присваивал не значения двумерного массива, а указатель на него (таким образом, оба объекта ссылались на один и тот же массив, и выходила билиберда). Но после того как я оператор присваивания таки перегрузил, поведение программы не изменилось.

/** \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;
}


В общем, помогите найти ошибку.
  • Вопрос задан
  • 297 просмотров
Подписаться 2 Оценить 1 комментарий
Пригласить эксперта
Ответы на вопрос 3
@vilgeforce
Раздолбай и программист
Берете отладчик и смотрите как обсчитывается ваш файл.
Ответ написан
Комментировать
Olej
@Olej
инженер, программист, преподаватель
обнаружил, что алгоритм на самом деле работает не правильно.

Алгоритм не может работать неправильно ;-)
Неправильно работает ваш код, которым вы пытались реализовать этот алгоритм :-(

P.S. Неужели вы всерьёз рассчитывали, что кто-то станет разгребать такую простыню как вы приводите?
Научитесь задавать вопросы более конкретно.
Ответ написан
Комментировать
1. Минимизируйте неправильный пример. Что именно неправильно? Полоска, квадрат?
2. Создайте как можно меньший пример, который работает некорректно, а с ним уже работайте отладчиком.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы