Game of Life, C проверка условий жизни

Я смотрел на это некоторое время и переписывал код три раза, это то, что у меня есть, и то, что я не понимаю.

У меня есть метод, который проверяет соседство, через различные строки печати и мой пробег по нему, это работает.

int getLiveCellCount(Generation *currentGeneration, int i, int j)
{
int liveCellCount = 0;
// check top row
if( i > 0 )
{
    if( j > 0 && currentGeneration->generation[i-1][j-1] == 'X' )
    {
        liveCellCount++;
    }
    if( currentGeneration->generation[i-1][j] == 'X' )
    {
        liveCellCount++;
    }
    if( j < currentCols && currentGeneration->generation[i-1][j+1] == 'X' )
    {
        liveCellCount++;
    }

}

// check mid row
if( j > 0 && currentGeneration->generation[i][j-1] == 'X' )
{
    liveCellCount++;
}
if( j < currentCols && currentGeneration->generation[i][j+1] == 'X' )
{
    liveCellCount++;
}

// check bottom row
if( i < currentRows )
{
    if( j > 0 && universe[i+1][j-1] == 'X' )
    {
        liveCellCount++;
    }
    if( currentGeneration->generation[i+1][j] == 'X' )
    {
        liveCellCount++;
    }
    if( j < currentCols && currentGeneration->generation[i+1][j+1] == 'X' )
    {
        liveCellCount++;
    }
}

return liveCellCount;
}

У меня есть определенные условия, в которых клетка живет или умирает, живые клетки содержат X, а мертвые клетки представляют собой пустое место.

If the cell is alive:
   it dies if it has 0, 1, 4 or more living neighbours (starvation), or
   it lives if it has 2 or 3 living neighbours (balance).
If the cell is dead:
   it springs to life if it has exactly 3 neighbours (procreation).

Я реализую код следующим образом:

for( i=0; i<currentRows; i++ )
        {
            for( j=0; j<currentCols; j++ )
            {
                int livingCells = 0;
                livingCells = getLiveCellCount(currentGeneration, i,j);
                if(universe[i][j] == 'X' )
                {
                    if( livingCells == 2 || livingCells == 3 )
                    {
                        universe[i][j] = 'X';
                    }
                    else
                    {
                        universe[i][j] = ' ';
                    }
                }
                else
                {
                    if( livingCells == 3 )
                    {
                        universe[i][j] = 'X';
                    }
                }
            }
        }

Знайте, что universe[][] - это переменная области видимости файла, моя идея с этим кодом читается в начальном состоянии в universe, это работает. Я копирую этот массив в массив структур (хранение на потом и в настоящее время закомментировано). Я сканирую universe и проверяю каждую ячейку на наличие живых клеток по соседству, следуя приведенным выше правилам, и редактирую universe поэлементно. Что мне не хватает в этом? Где-то условие не читается мной правильно и я его не вижу.

Хочу поблагодарить вас всех за помощь, которую вы мне оказали! Как многие из вас упоминали, я упустил из виду маленькую деталь, что каждая ячейка во вселенной должна обновляться одновременно! Как я уже упоминал, я копирую текущее состояние вселенной в двумерный массив в структуре и сохраняю его в массиве для последующего использования, используя текущий снимок вселенной для подсчета количества ячеек, а затем редактируя вселенную, все работает отлично! Большое спасибо!


person Michael Miner    schedule 18.06.2015    source источник
comment
Вы должны включить небольшой пример, демонстрирующий проблему, которую вы видите. Вы должны учитывать, что то, как вы сканируете стол, влияет на ваше игровое состояние. Вы убиваете и оживляете клетки одновременно, поэтому клетка может умереть в позиции x, y, и это повлияет на то, выживет или умрет x+1,j+1, потому что к тому времени, когда вы доберетесь до этой второй клетки, вы уже уже обновил x,y. Это своего рода каскадный эффект за один виток. Хотя, возможно, это то, чего вы хотите.   -  person Walter Delevich    schedule 18.06.2015
comment
В getLiveCellCount вы не защищаете от превышения верхней границы.   -  person ooga    schedule 18.06.2015
comment
getLiveCellCount всегда вызывается только из моих циклов for, они должны охватывать верхние границы, верно?   -  person Michael Miner    schedule 18.06.2015


Ответы (2)


Я думаю, у вас есть две проблемы с вашим кодом:

  1. Как сказал @ogga в комментариях, вы не проверяете верхние границы в getlivecellcounts. Вы проверили нижние границы, когда проверяете, что i и j больше 0, но вам нужно сделать это и для верхней границы (просто убедитесь, что она не превышает размер массива, чтобы проверить, является ли ячейка мертвой или живой).

  2. Я думаю, что в вашем цикле for вы подсчитываете количество живых клеток на лету. Проблема с этим подходом заключается в том, что когда вы находитесь в какой-то ячейке [x][y], и она активна, и у нее есть некоторое количество z ​​соседей, и вы меняете ее на мертвую ячейку, а затем переходите к следующей ячейке. Что даст вам неправильное количество соседей в ячейке [x] [y+1], потому что вы уже изменили статус ячейки x y на новое поколение, которое сейчас мертво и было живо раньше.

*Смена ячейки должна производиться в том же поколении.

Другим способом может быть создание другого массива 2d и сохранение там новой версии или нового поколения, а затем копирование в предыдущую после ее завершения. Таким образом, вы будете менять поколения сразу.

person Deepak    schedule 18.06.2015
comment
Если я правильно понимаю, я могу сделать второй массив 2d для хранения текущего состояния вселенной, просканировать этот массив и на основе соседей ячеек обновить ячейки во вселенной. Затем повторите. - person Michael Miner; 18.06.2015
comment
Спасибо, прочитав ваш пост, я вернулся на страницу правил игры и увидел это The first generation is created by applying the above rules simultaneously to every cell in the seed, эта новая идея с двумя массивами должна работать, поскольку она удовлетворяет этому условию. - person Michael Miner; 18.06.2015
comment
также убедитесь, что ваши нижние и верхние границы верны при подсчете живых клеток. это тоже может создать проблему. - person Deepak; 18.06.2015
comment
это работает, я обновил приведенный выше код, чтобы показать свою проверку привязки, и я написал небольшое размытие о том, как я обработал запасной массив 2d! - person Michael Miner; 19.06.2015

в целом,

1) проверка состояния соседних ячеек всегда должна проверять, что проверяемая ячейка находится в границах 2D массива.

2) один и тот же массив нельзя использовать для обновления содержимого целевой ячейки, потому что это может изменить количество соседей, когда какая-то соседняя ячейка становится целевой ячейкой. Обойти это можно, сохранив два 2D-массива и используя указатель для переключения на последнюю версию после применения всех обновлений.

person user3629249    schedule 18.06.2015
comment
Значит, я могу скопировать вселенную во временный массив 2d, отсканировать временный массив и на основе соседства ячеек обновить исходную вселенную? - person Michael Miner; 18.06.2015