cconways-game-of-life

The second generation is bugged (C, Conways Game of Life)


Hey so my problem is that the when I go run this code and choose to "Zufallstand generieren" (Generate random state) and then type in the "Prozentualer Anteil lebender Zellen" (Percentage of living cells) and then "Schrittweise Animation" or "Fließende Animation" (Step-by-step animation/Flowing animation) the second generation is absolute trash it does not match the first generation in one thing.

The code:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include <string.h>

#pragma warning (disable: 4996)

#define MAX_ROWS 30
#define MAX_COLS 20

typedef struct {
    char data[MAX_ROWS][MAX_COLS];
    int rows;
    int cols;
} Matrix;

char neighbor_count(Matrix *m, int row, int col) {
    int count = 0;
    for (int i = row - 1; i <= row + 1; i++) {
        if (i < 0 || i >= m->rows) {
            continue;
        }
        for (int j = col - 1; j <= col + 1; j++) {
            if (j < 0 || j >= m->cols) {
                continue;
            }
            if (m->data[i][j] == '*' && (i != row || j != col)) {
                count++;
            }
        }
    }
    return count;
}

void check_cell(Matrix *m, int row, int col) {
    char neighbors_count = neighbor_count(m, row, col);
    char current_cell = m->data[row][col];

    if (neighbors_count < 2) { //Die Zelle stirbt an Vereinsamung
        m->data[row][col] = ' ';
    }
    else if (neighbors_count > 3 && current_cell == '*') { //Die Zelle stirbt an Übervölkerung
        m->data[row][col] = ' ';
    }
    else if (neighbors_count == 3 && current_cell == ' ') { //Aus der toten Zelle wird eine neue lebende Zelle
        m->data[row][col] = '*';
    }
    else if (neighbors_count == 2 || neighbors_count == 3) { //Die Zelle lebt weiter
        m->data[row][col] = '*';
    }
}

void load_from_file(Matrix *m, const char *filename) {
    FILE *f = fopen(filename, "r");

    if (f == NULL) {
        printf("File not found\n");
        exit(-1);
    }

    int row_idx = 0;
    char ch;
    while ((ch = fgetc(f)) != EOF && row_idx < MAX_ROWS) {
        if (ch == '\n') {
            row_idx++;
            continue;
        }
#
        m->data[row_idx][m->cols] = ch;
        m->cols++;
    }
    m->rows = row_idx;
    fclose(f);
}

void randomize(Matrix *m, int percent) {
    memset(m->data, (int)' ', MAX_COLS * MAX_ROWS);
    m->rows = MAX_ROWS;
    m->cols = MAX_COLS;
    int cells = (m->rows * m->cols) * (percent / 100.0f);
    srand(time(NULL));
    while (cells > 0) {
        int row = rand() % m->rows;
        int col = rand() % m->cols;
        if (m->data[row][col] == ' ') {
            m->data[row][col] = '*';
            cells--;
        }
    }
}

void print_matrix(Matrix *m) {
    for (int i = 0; i < m->rows; i++) {
        for (int j = 0; j < m->cols; j++) {
            printf("%c", m->data[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

void step(Matrix *m) {
    Matrix m_tmp = *m;
    for (int i = 0; i < m->rows; i++) {
        for (int j = 0; j < m->cols; j++) {
            check_cell(&m_tmp, i, j);
        }
    }
    *m = m_tmp;
}

int main() {
    Matrix m;

    // Menü zur Auswahl des Startzustands
    printf("1. Aus Datei laden\n");
    printf("2. Zufallszustand generieren\n");
    int selection;
    scanf("%d", &selection);

    switch (selection) {
    case 1: // Aus Datei laden
    {
        char  filename[20];
        printf("Bitte Dateinamen angeben: ");
        scanf("%s", filename);
        load_from_file(&m, filename);
        break;
    }
    case 2: // Zufallszustand generieren
    {
        int percent;
        printf("Prozentualer Anteil an lebenden Zellen: ");
        scanf("%d%%", &percent);
        randomize(&m, percent);
        break;
    }
    default:
        printf("Ungültige Eingabe\n");
        return 0;
    }

    // Menü zur Auswahl der Animation
    printf("1. Schrittweise Animation\n");
    printf("2. Fließende Animation\n");
    scanf("%d", &selection);
    switch (selection) {
    case 1: // Schrittweise Animation
        while (1) {
            print_matrix(&m);
            step(&m);
            getchar();

        }
        break;
    case 2: // Fließende Animation6
        while (1) {
            print_matrix(&m);
            step(&m);
            Sleep(2000);
        }
        break;
    default:
        printf("Ungültige Eingabe\n");
        break;
    }

    return 0;
}

I tried to change the how the matrix works but without any success.


Solution

  • As others have mentioned, you are modifying the current matrix. You need to have a copy.

    Ironically, your step function makes a copy. But, it still passes only one pointer to check_cell.

    check_cell needs to have two matrix pointers. One for old/current state and another for new/future state.

    Here are the changed functions:

    void
    check_cell(Matrix *mnew, Matrix *mold, int row, int col)
    {
        char neighbors_count = neighbor_count(mold, row, col);
        char current_cell = mold->data[row][col];
    
        do {
            // Die Zelle stirbt an Vereinsamung
            if (neighbors_count < 2) {
                current_cell = ' ';
                break;
            }
    
            // Die Zelle stirbt an Übervölkerung
            if (neighbors_count > 3 && current_cell == '*') {
                current_cell = ' ';
                break;
            }
    
            // Aus der toten Zelle wird eine neue lebende Zelle
            if (neighbors_count == 3 && current_cell == ' ') {
                current_cell = '*';
                break;
            }
    
            // Die Zelle lebt weiter
            if (neighbors_count == 2 || neighbors_count == 3) {
                current_cell = '*';
                break;
            }
        } while (0);
    
        mnew->data[row][col] = current_cell;
    }
    
    void
    step(Matrix *m)
    {
        Matrix m_tmp = *m;
    
        for (int i = 0; i < m->rows; i++) {
            for (int j = 0; j < m->cols; j++)
                check_cell(m, &m_tmp, i, j);
        }
    }