Опубликован: 05.03.2013 | Доступ: свободный | Студентов: 2195 / 622 | Длительность: 07:41:00
Самостоятельная работа 5:

Клеточная модель "Игра Жизнь" Дж.Конвея

< Лекция 7 || Самостоятельная работа 5 || Лекция 8 >
Аннотация: Применение шаблонов Paralle.For, Parallel.Invoke.

Задания

  1. Реализуйте Windows-приложение, которое последовательно отображает состояния клеточной модели "Игра жизнь".
  2. Реализуйте последовательный алгоритм расчета состояний модели.
  3. Реализуйте параллельные алгоритмы расчета состояний модели. Для распараллеливания используйте задачи (tasks) или метод Parallel.For.
  4. Реализуйте возможность отмены расчета с помощью объекта CancellationToken.
  5. Выполните анализ эффективности разработанных алгоритмов.

Методические указания

Клеточная модель представляет собой множество клеток (ячеек таблицы), принимающих одно из нескольких состояний. Состояние каждой клетки определяется состоянием её ближайших соседей. Одной из известных моделей является "Игра Жизнь" математика Дж. Конвея.

В модели Конвея каждая клетка может находиться в двух состояниях: живая или неживая. Состояние клетки на следующем шаге определяется потенциалом клетки (числом живых соседних клеток):

  • если потенциал клетки равен двум, то клетка сохраняет свое состояние;
  • если потенциал равен трем, то клетка оживает;
  • если потенциал меньше двух или больше трех, то клетка погибает.

Правила изменения состояния клетки можно описать следующим лямбда-выражением:

var lifeRules = new Func<int, bool, bool>((p, state) => 
 { 
  if(p == 3) 
   return true; 
  else if (p == 2) 
   return state; 
  else 
   return false; 
 }); 
 

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

LifeTable tableNew = new LifeTable; 
for(int i=0; i < Height; i++) 
  for(int j=0; j < Width; j++) 
  { 
   p = CalcPotential(table[i,j]); 
     tableNew[i, j] = lifeRules(p, table[i, j]); 
  } 
table = tableNew; 

 

Потенциал клетки вычисляется по восьми ближайшим соседям клетки.

int CalcPotential(int i, int j) 
{ 
 int p=0; 
 for(int x = i-1; x <= i + 1; x++) 
  for(int y = j-1; y <= j + 1;y++) 
  { 
   if(x < 0 || y < 0 || x >= Height || y >= Width 
      ||  (x == i && y == j)) 
    continue; 
 
   if(table[x,y])  p++; 
 
  } 
return p; 
} 
 

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

Parallel.For(0, Height, (i) => { 
 for(int j=0; j < Width; j++) 
  { 
   p = CalcPotential(table[i,j]); 
     tableNew[i, j] = lifeRules(p, table[i, j]); 
  } 
}); 
 

Также можно изменить порядок расчета и распараллелить внешний цикл по столбцам:

Parallel.For(0, Width, (j) => { 
 for(int i=0; i < Height; i++) 
  { 
   p = CalcPotential(table[i,j]); 
     tableNew[i, j] = lifeRules(p, table[i, j]); 
  } 
} 
 

Вывод таблицы состояний клеточной модели может быть следующим:


Вопросы и упражнения

  1. Имеет ли смысл распараллеливание внутреннего цикла расчета? Почему?
    for(int i=0; i < Height; i++) 
    { 
     Parallel.For(0, Width, j => 
      { 
       p = CalcPotential(table[i,j]); 
         tableNew[i, j] = lifeRules(p, table[i, j]); 
      }); 
    } 
     
  2. Как вариант расчета – по строкам или по столбцам – более эффективен и с чем это связано?
  3. Продумайте вариант блочной декомпозиции, где блок выступает матрицей размера K x K. В чем достоинства и недостатки блочной декомпозиции для этой задачи? Какое значение параметра K следует выбирать?
< Лекция 7 || Самостоятельная работа 5 || Лекция 8 >