Постановка задачи. Проект «Жизнь клеток» моделирует жизнь поколений гипотетической колонии живых клеток, которые выживают, размножаются или погибают по определенным правилам. Эти правила заключаются в следующем. Клетка выживает в том и только том случае, если она имеет двух или трех соседей из восьми возможных. Если у клетки только один сосед или вовсе ни одного, она погибает в изоляции. Если клетка имеет четырех или более соседей, она погибает от перенаселения. В любой пустой позиции, у которой ровно три соседа, в следующем поколении появляется новая клетка. Один из моментов жизни колонии изображен на рис. 22.
Рис. 22. Проект «Жизнь клеток»
Реализация. Жизнедеятельность колонии протекает на поле размером 15 х 15 позиций, каждую из которых может занять лишь одна клетка. Начальное размещение клеток на поле задается играющим с помощью мыши. Мышью можно закрасить одну клетку по щелчку, а можно «возить» мышью по полю и перекрашивать клетки. Для простоты будем рисовать на компоненте TPaintBox. Также положим на форму таймер и три кнопки «Заселить колонию», «Старт» и «Стоп».
Играющий может указать, какое число поколений исходной колонии следует отобразить на экране (это необязательно). Понадобятся следующие глобальные переменные:
const
n=15;
dx=20;
dy=20;
type Tpole=array[1..n,1..n]of integer;
var x0,y0,cw,ch:integer;
pr_kolonia:boolean;
pole,pole1:Tpole;
// Два массива для хранения текущего и следующего поколения
Напишем три своих процедуры mas_clear, put_kletka и DrawPole. Процедура mas_clear (var a:Tpole) обнуляет массив. Процедура put_kletka (i,k:integer; cl, cl_bordur:TColor) рисует закрашенную клетку с границей другого цвета. Процедура DrawPole выводит поле на форму. Разместим эти процедуры в разделе implementation.
Для каждого элемента массива pole обнуляем переменную sum и в ней подсчитываем число соседей (перебором). В зависимости от значения переменной sum во второй массив pole1 будем ставить 1 или 0. Массив pole1 – это следующее поколение колонии. Затем копируем массив pole1 в массив pole и делаем прорисовку массива pole. Ниже приведен код всех обработчиков.
procedure TForm1.FormCreate(Sender: TObject);
begin
cw:=clientwidth; {Вычисление ширины и высоты формы}
ch:=clientheight;
PaintBox1.Left:=10;
PaintBox1.Top:=10;
PaintBox1.Width:=n*dx;
PaintBox1.Height:=n*dy;
Timer1.Enabled:=false;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var sum,sum1,i,k:integer;
begin
for i:=1 to n do
for k:=1 to n do
begin
sum:=0;
{Подсчитаем, сколько соседей у каждой клетки}
if (i>1) then
begin
sum:=sum+pole[i-1,k];
if (k>1) then
sum:=sum+pole[i-1,k-1];
if (k<n) then
sum:=sum+pole[i-1,k+1];
end;
if (i<n)then
begin
sum:=sum+pole[i+1,k];
if(k>1)then
sum:=sum+pole[i+1,k-1];
if (k<n)then
sum:=sum+pole[i+1,k+1];
end;
if (k>1)then
sum:=sum+pole[i,k-1];
if (k<n)then
sum:=sum+pole[i,k+1];
{У пустой клетки три соседа, клетка начинает жить}
if (pole[i,k]=0)and(sum=3)then
pole1[i,k]:=1; // В массиве pole1 – следующее поколение
{Клетка погибает, если число соседей меньше 2 и больше 3}