Конвейс Игра Жизни Визуализация

Я закончил реализацию игры «Жизнь», но столкнулся с проблемой при рендеринге сетки после применения правил игры. У меня есть игровой цикл, который выглядит так:

while (gameIsRunning)
{
    //Needed for accessing UIControls from the background
    //thread.

    if (InvokeRequired)
    {
        //Process the array.
        MainBoard.Cells = engine.ApplyGameRules(MainBoard.Cells, MainBoard.Size.Height, MainBoard.Size.Width, BOARD_DIMENSIONS);
        //Check if there is a state such as
        //all states being dead, or all states being
        //alive.
        //Update the grid with the updated cells.
        this.Invoke(new MethodInvoker(delegate
                                     {
                                         timeCounter++;
                                         lblTimeState.Text = timeCounter.ToString();
                                         pictureBox1.Invalidate();
                                         pictureBox1.Update();
                                         Thread.Sleep(100);
                                     }));

        }
    }

и функция рисования, которая выглядит так:

for (int x = 0; x < MainBoard.Size.Height; x++)
{
    for (int y = 0; y < MainBoard.Size.Width; y++)
    {
        Cell individualCell = MainBoard.Cells[y, x];
        if (individualCell.IsAlive() == false)
        {
            e.Graphics.FillRectangle(Brushes.Red, MainBoard.Cells[y, x].Bounds);
        }
        //White indicates that cells are alive
        else if (individualCell.IsAlive() == true)
        {
            e.Graphics.FillRectangle(Brushes.White, MainBoard.Cells[y, x].Bounds);
        }
        else if (individualCell.IsInfected() == true)
        {
            e.Graphics.FillRectangle(Brushes.Green, MainBoard.Cells[y, x].Bounds);
        }
        //Draws the grid background itself.
        e.Graphics.DrawRectangle(Pens.Black, MainBoard.Cells[y, x].Bounds);
    }
}

Проблема, с которой я сталкиваюсь, заключается в том, что я применяю все правила игры к каждой ячейке в сетке, а затем рисую эту сетку, а затем снова применяю все правила, поэтому я никогда не получаю капли форм жизни, которые я должен видеть. . Должны ли правила игры применяться к ячейке за ячейкой, чтобы это было примерно так: применить правило игры к ячейке, нарисовать сетку, применить правило игры к другой ячейке, нарисовать сетку...?


person zic10    schedule 20.03.2014    source источник
comment
Насколько я понимаю, вы применяете правила ко всей сетке, а затем перерисовываете. Таким образом, вам нужно взять состояние сетки как есть, а затем обновить копию в зависимости от ситуации в исходной сетке.   -  person Matt Burland    schedule 20.03.2014
comment
Хорошо, я попробую что-то подобное, я помню, где-то читал, что при отображении сетки должна использоваться копия, и я использую оригинал как для применения правил, так и для рендеринга.   -  person zic10    schedule 20.03.2014


Ответы (1)


Похоже, текущее намерение программы правильное.

Что вы должны делать (псевдокод):

  Board oldBoard = new Board(start cell definitions);
  while(not finished) {
      Board newBoard = calculate(oldBoard);
      display(newBoard);
      oldBoard = newBoard();
  }

Если вы не видите формы, которые ожидаете, то либо ваш код отображения неверен, либо код правила неверен.

В псевдокоде я выбрасываю плату предыдущего поколения, когда она больше не нужна, и делаю новую плату для каждого поколения. calculate() содержит оператор new Board().

Конечно, если делать новую плату дорого, вы можете использовать ее повторно и просто переключаться между «текущей» и «другой» платой. Просто имейте в виду, что каждый раз, когда вы записываете на доску, ее новое состояние должно на 100% зависеть от состояния предыдущего поколения и никоим образом не зависеть от его собственного начального состояния. то есть вы должны писать в каждую ячейку.

Альтернативный метод заключается в том, чтобы каждая ячейка содержала два значения. Таким образом, вместо двух досок с одним значением в ячейке у вас есть одна доска, каждая ячейка которой содержит «текущее» и «предыдущее» значение.

  Board board = new Board(initial state);
  while(not finished) {
      board.calculate(); // fills "current" cells based on "previous" cells.
      display(board);
      board.tick(); // "current" becomes "previous".
                    // "previous" becomes current, but is "dirty" until calculated.
  }

Есть много способов сделать это. Один из способов:

  public class Cell {
      private boolean[] state = new boolean[2];
      private int generation = 0;

      public void setCurrentState(boolean state) {
          state[generation] = state;
      }

      public void getCurrentState() {
          return state[generation];
      }

      public void getLastState() {
          return state[ (generation + 1) % 2 ];
      }

      public void tick() {
          generation = (generation + 1) % 2;
      }

  }
person slim    schedule 20.03.2014
comment
В этой последней строке псевдо-инициализации все старые ячейки повторно инициализируются? - person zic10; 20.03.2014
comment
Спасибо за ваш отзыв! Я все еще не уверен, что понимаю напрямую. Например, в моем коде мой MainBoard.Cells представляет собой двумерный массив или таблицу. Я применяю правила к этой таблице, а затем перерисовываю эту таблицу за одно поколение. Мое исходное состояние - все клетки живы. Поколение 2. Я использую тот же MainBoard.Cells, который теперь имеет обновленное состояние для каждой ячейки. Я снова применяю правила и перерисовываю. Также каждая ячейка в моей таблице имеет свойство isAlive, чтобы определить, мертва она или жива. - person zic10; 20.03.2014
comment
Проблема с этим заключается в том, что при вычислении ячейки (n) необходимо знать состояние ячейки (n-1) в предыдущем поколении. Возможно, вы просто изменили значение ячейки (n-1). - person slim; 20.03.2014
comment
Так, например, с сеткой 4x4, где все ячейки начинают жить как начальное состояние. Если я вычислю новую доску, основываясь только на стартовой доске, то все клетки будут мертвы? Потому что при использовании оригинальной доски, ячейка за ячейкой, каждая ячейка новой доски была бы мертва из-за переполненности. Затем эта новая плата становится предыдущей платой, и для третьего поколения необходимо создать еще одну новую плату, верно? - person zic10; 20.03.2014
comment
Правильный. Чтобы получить интересные результаты, вы должны инициализировать свою первую сетку шаблоном, который будет жить. - person slim; 20.03.2014