2016-10-17 2 views
2

Я пытаюсь закодировать игру жизни в C. Я сидел в течение 7 часов, размышляя о том, как ее решить. Я зашел далеко, но есть что-то, что делает код не работает так, как должно. Я считаю, что я сделал что-то неправильно между следующей и текущей переменными в структуре. Может быть, ошибаться в подсчете, если сосед жив или мертв. Во всяком случае, я был бы признателен за любую помощь!C Игра жизни вопросы

void checkField(const int rows, const int cols, cell field[rows][cols]) { 
    int neighborCount; 

    for (int r = 0; r < rows; r++) { 
     for (int c = 0; c < cols; c++) { 
       neighborCount = getNeighborCount(rows, cols, r, c, field); 
       nextGeneration(rows, cols, r, c, neighborCount, field); 
     } 
    } 
} 

int getNeighborCount(const int rows, const int cols, 
    int r, int c, cell field[rows][cols]) { 

    int neighborCount = 0; 

    neighborCount += checkNeighbors(rows, cols, r - 1, c - 1, field); 
    neighborCount += checkNeighbors(rows, cols, r - 1, c, field); 
    neighborCount += checkNeighbors(rows, cols, r - 1, c + 1, field); 
    neighborCount += checkNeighbors(rows, cols, r, c - 1, field); 
    neighborCount += checkNeighbors(rows, cols, r, c + 1, field); 
    neighborCount += checkNeighbors(rows, cols, r + 1, c - 1, field); 
    neighborCount += checkNeighbors(rows, cols, r + 1, c, field); 
    neighborCount += checkNeighbors(rows, cols, r + 1, c + 1, field); 

    return neighborCount; 
} 


int checkNeighbors(const int rows, const int cols, 
    int r, int c, cell field[rows][cols]) { 

    int neighborAlive; 

    if (r < 0 || r > rows || c < 0 || c > cols || field[r][c].current != ALIVE){ 
     return neighborAlive = 0; 
    } 
    else { 
     return neighborAlive = 1; 
    } 
} 

void nextGeneration(const int rows, const int cols, 
    int r, int c, int neighborCount, cell field[rows][cols]) { 

    for (int r = 0 ; r < rows ; r++) { 
     for (int c = 0 ; c < cols ; c++) { 
      field[r][c].current = DEAD; 
      field[r][c].next = DEAD; 
     } 
    } 

    if (neighborCount < 2){ 
     field[r][c].current = DEAD; 
     field[r][c].next = DEAD; 
    } 

    if (neighborCount == 2 || neighborCount == 3) { 
     field[r][c].current = ALIVE; 
     field[r][c].next = ALIVE; 

    } 

    if ((field[r][c].current == DEAD) && neighborCount == 3) { 
     field[r][c].current = ALIVE; 
     field[r][c].next = ALIVE; 
    } 

    if (neighborCount >= 4) { 
     field[r][c].current = DEAD; 
     field[r][c].next = DEAD; 
    } 
} 
+0

hey @ Cows42 не снимает вопрос, потому что будущие пользователи не смогут связать ответы на вопрос :) – Cherubim

+0

как «отлаживать мой код» вопрос с большой дампом кода и без четкой формулировки проблемы получает так много upvotes? – bolov

+0

@bolov Я четко заявил, где я думал, что проблемы были. Очевидно, я был прав на обоих. «Я считаю, что я сделал что-то не так между следующей и текущей переменными в структуре. Может быть, ошибается в подсчете, если сосед жив или мертв». – Cows42

ответ

3

Теперь, когда условие в функции checkNeighbors() работает, у вас есть несколько проблем в способе обновления от одного поколение к следующему. В функции nextGeneration() вам не нужно очищать массив ячеек, потому что вы все равно перезапите следующее поколение. И в каждом из тестов в этой функции, у вас есть, например .:

if (neighborCount < 2){ 
    field[r][c].current = DEAD; 
    field[r][c].next = DEAD; 
} 

Но вам нужно только field[r][c].next = DEAD;. Это ваша новая nextGeneration() функция:

void nextGeneration(const int rows, const int cols, 
    int r, int c, int neighborCount, cell field[rows][cols]) { 

    if (neighborCount < 2) 
     field[r][c].next = DEAD; 

    if (neighborCount == 2 || neighborCount == 3) 
     field[r][c].next = ALIVE; 

    if ((field[r][c].current == DEAD) && neighborCount == 3) 
     field[r][c].next = ALIVE; 

    if (neighborCount >= 4) 
     field[r][c].next = DEAD; 
} 

Затем, в конце функции checkField(), вам необходимо скопировать следующее поколение в текущем поколении. Это ваша новая checkField() функция:

void checkField(const int rows, const int cols, cell field[rows][cols]) { 

    int neighborCount; 
    int r, c; 

    for (r = 0; r < rows; r++) { 
     for (c = 0; c < cols; c++) { 
       neighborCount = getNeighborCount(rows, cols, r, c, field); 
       nextGeneration(rows, cols, r, c, neighborCount, field); 
     } 
    } 
    /* Now, copy next generation into current */ 
    for (r = 0; r < rows; r++) 
     for (c = 0; c < cols; c++) 
      field[r][c].current = field[r][c].next; 
} 

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

. . X . . . . . . . . . . . . . . . . . 
X . X X . . . . . . . . . . . . . . . . 
. X X X . . . . . . . . . . . . . . . . 
X X X . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 

Spoiler Alert:

Вот обновленный nextGeneration() функция с правилами, которые правильно реализовать игру Конвея жизни. Ваши первоначальные правила регенерировали мертвые клетки только с двумя соседями.

void nextGeneration(const int rows, const int cols, 
    int r, int c, int neighborCount, cell field[rows][cols]) { 

    if (field[r][c].current == ALIVE) { 
     if ((neighborCount < 2) || (neighborCount > 3)){ 
      field[r][c].next = DEAD; 
     } else { 
      field[r][c].next = ALIVE; 
     } 
    } else { 
     if (neighborCount == 3) { 
      field[r][c].next = ALIVE; 
     } else { 
      field[r][c].next = DEAD; 
     } 
    } 
} 

Update:

После всего вышесказанного, я теперь вижу, что вы пытаетесь перевернуть экран вперед и назад между текущим и следующим поколениям. Это усложняет логику обновления, поскольку вам также нужно чередоваться между поколениями. Суть в том, что этот код просто сложнее, чем нужно. Вы можете реализовать это так, как хотите, но по-прежнему существует множество проблем с обновлением, вызывающих проблемы, и ваш основной цикл в main() не мог чередоваться между поколениями. Вы можете сохранить изменения, которые я предлагаю, и удалить все ссылки на printCurrentField и printNextField. Это позволяет упростить функцию printField().

2
int checkNeighbors(const int rows, const int cols, 
    int r, int c, cell field[rows][cols]) { 
    int neighborAlive; 

    if (r < 0 || r > rows || c < 0 || c > cols || field[r][c].current != ALIVE){ 
     return neighborAlive = 0; 
    } 
    else { 
     return neighborAlive = 1; 
    } 
} 

Пусть rows является 7. Это означает, что существует семь рядов. Но этот код будет иметь доступ к восьми строкам: ноль, один, два, три, четыре, пять, шесть и семь. Это не так.

+0

строки - это постоянный набор до 20? По моему мнению, функция if будет проверять, находится ли переменная 'r' или 'c' вне границы. Если это так, то он просто добавляет 0 к счетчику, который ничего не влияет. – Cows42

+0

'(r < 0 || r > rows || c < 0 || c > cols || field [r] [c] .current! = ALIVE' Я бы дважды проверял эти условия в отладчике – tesseract

+0

@ Cows42 Если вы прочтете мой ответ, я объясню, почему это не так, т. Это означает, что если для строк установлено значение 20, это значит, что есть 20 строк, но этот тест позволит 21 строку (подсчитать их). –

0
void loadCustom(const int rows, const int cols, cell field[rows][cols]) { 

    printf("Give custom format string: "); 
    do { 
    int r, c; 
    scanf("%d,%d", &r, &c); 
    field[r][c].current = ALIVE; 
    } while (getchar() != '\n'); 
} 

scanf возвращает значение попытаться исправить ошибку sig seg после неудачного ввода, я полагаю, что лучше комментировать код и использовать valgrind. Управление памятью плохо, поэтому вы выходите из массива. Я думаю, что есть проблема. Попробуйте проверить его вручную.

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