2013-11-25 2 views
-1

Я создал упрощенную игру жизни.Игра жизни - что с этим алгоритмом

Это моя клетка, где фактический материал происходит:

class Cell 
{ 
    public Cell(MainWindow correspondingMainWindow){ 
     this.mainWindow = correspondingMainWindow; 
    } 

    public bool excluded; 

    public Boolean Occupied { get; set; } 

    public Control correspondingPanel; 

    private int[] coordinates; 

    private MainWindow mainWindow; 

    public int[] Coordinates 
    { 
     get { return this.coordinates; } 
     set { 
      if(value.Length != 2) 
      { 
       throw new ArgumentException(); 
      } 
      else if(value[0] < 0 || value [1] < 0 
        || value[0] > Settings.FIELDWIDTH 
        || value[1] > Settings.FIELDHEIGHT) 
      { 
       throw new ArgumentException(); 
      } 
      else{ 
       correspondingPanel = mainWindow.FieldArea.Controls 
         .Find(String.Format("panel{0}_{1}", value[0], value[1]), true) 
         .FirstOrDefault(); 
       this.coordinates = value; 
      } 
     } 

    } 

    //Surrounding Cells in the 3x3 around the current cell 
    //this is to speed up the updating as soon as the algorithm runs on many cells 
    public Cell Top { get; set; } 
    public Cell TopRight { get; set; } 
    public Cell Right { get; set; } 
    public Cell BotRight { get; set; } 
    public Cell Bot { get; set; } 
    public Cell BotLeft { get; set; } 
    public Cell Left { get; set; } 
    public Cell TopLeft { get; set; } 

    public void die() 
    { 
     this.Occupied = false; 
     this.correspondingPanel.BackColor = Color.Beige; 
    } 

    public void populate() 
    { 
     this.Occupied = true; 
     this.correspondingPanel.BackColor = Color.DarkRed; 
    } 
} 

Вот алгоритм в вопросе:

//should return true if there were any changes to any "living" state 
bool Algorithm.runOver(Cell target) 
{ 
    if (target.Occupied && !target.excluded) 
    { 
     target.Right.populate(); 
     target.Left.populate(); 
     target.Top.populate(); 
     target.Bot.populate(); 

     target.Right.excluded = true; 
     target.Left.excluded = true; 
     target.Top.excluded = true; 
     target.Bot.excluded = true; 
     return true; 
    } 
    else 
    { 
     return false; 
    } 
} 

исключены и уже проложенные будут сброшены к ложному каждый раз алгоритм завершения работы все клеток один раз. это предотвращает вызов walkOver() на Ячейке, обновленный в этой прогулке.

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

Фактически он обновляет Cell в разработанном виде, но затем просто останавливается.

Я сохраняю свои ячейки в статическом списке в программе (я знаю, что не должен, но это самый простой способ, пока он работает правильно). ячейки имеют несколько панелей для соответствия. эти панели находятся в GroupBox с именем FieldArea. они генерируются динамически на основе некоторых статических константных настроек (которые вы видите в установленной проверке для координат).

Я уверен, что ячейки соответствуют панелям правильно. эта проблема возникает в диагонали через FieldArea слева вверху (0,0) вправо справа. любая другая стартовая точка работает правильно. так или иначе, когда большее количество клеток поступает из «верхней», ячейки образуют границу на верхнем и левом краю поля.

Вопрос: это то, что я делаю неправильно? Почему мое поле работает неправильно?

ответ

4

Вы должны хранить две копии своего «мира», при этом вы должны оставаться неизменными, пока вы применяете правила. Если вы применяете правила только к одному миру, это приведет к смешанной конфигурации, когда некоторые ячейки будут иметь старое состояние, а другие уже будут иметь новый.

Поэтому делать что-то вроде этого:

private Cell[,] activeWorld = new Cell[w,h]; 
private Cell[,] hiddenWorld = new Cell[w,h]; 

Populate(activeWorld); 
while (true) { 
    Display(activeWorld); 
    ApplyRules(activeWorld, hiddenWorld); 

    // Swap worlds 
    var temp = activeWorld; 
    activeWorld = hiddenWorld; 
    hiddenWorld = temp; 
} 

ApplyRules Метод должен читать ячейки из «activeWorld» и записать результат в hiddenWorld.


ОБНОВЛЕНИЕ: Ваш фактический дизайн, по-видимому, слишком разработан для меня. Простой 2-й булевой массив, указывающий, занята или нет ячейка, должна быть достаточной. Не начинайте с оптимизации. Это, скорее всего, приведет к сложному, трудно читаемому и ошибочному коду. Вместо этого сосредоточьте свое внимание на алгоритме и на хорошей структуре кода. Если позже вы столкнетесь с проблемами производительности, проанализируете проблемы и примените соответствующие оптимизации. В> 95% случаев проблема не связана с деталями кодирования и алгоритмами, а с I/O. В случае этой игры отображение ячеек, вероятно, займет гораздо больше времени, чем применение правил. И, вероятно, это будет слишком быстро, и вам придется добавить паузу в игровой цикл.

Не пытайтесь оптимизировать логику получения индексов окружающих ячеек. Это не стоит боль.

Одним из хороших способов решения проблемы ячеек маржи является обертывание мира. Сделайте вещи, выходящие из поля зрения справа, снова появятся с левой стороны и так далее.Для этого используйте операцию modulo (%). x % N всегда дает значение в диапазоне 0 ... N-1. Вы можете получить координаты 3 х 3 клеток в подобных Дано х и у координат:

for (int dx = -1; dx <= +1; dx++) { 
    int i = (x + dx + Width) % Width; 
    for (int dy = -1; dy <= +1; dy++) { 
     int j = (y + dy + Height) % Height; 
     bool occupied = world[i, j]; 
     ... 
    } 
} 

+ Width и + Height гарантировать, что мы всегда имеют положительные значения.

1

Хорошо, как и обещал вот моя личная победа, из-за неделю:

упомянутый выше алгоритм был «дефектный»

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

Я переместил исключение на функции die() и populate().

public void die(){ 
    this.Occupied = false; 
    this.correspondingPanel.BackColor = Color.Beige; 
    this.excluded = true; 
} 

тогда я также должен был убедиться, что петля получает правильно сломана:

public Algorithm.walkOver(Cell target) 
{ 
    if (target.Occupied && !target.excluded) 
    { 
     bool b = true; 

    //if there could no changes be made, we also have to return there were no changes... 
    //else the while loop continues forever and we lose the process :(
     if (target.Right.Occupied && target.Left.Occupied 
      && target.Bot.Occupied && target.Top.Occupied) 
     b = false; 

     if(!target.Right.Occupied) 
      target.Right.populate(); 

     if (!target.Left.Occupied) 
      target.Left.populate(); 

     if (!target.Top.Occupied) 
      target.Top.populate(); 

     if (!target.Bot.Occupied) 
      target.Bot.populate(); 

     return b; 
    } 
    else 
    { 
     return false; 
    } 
} 

Я также переместил сброс в начале цикла в то время, как «они выбрали» клетка исключал его.

+0

Если у вас возникли проблемы, пожалуйста, забудьте мой комментарий. –

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