2015-12-28 14:25:15 +03:00
|
|
|
|
// Игра "Жизнь" на торе
|
|
|
|
|
|
// Оптимизация хешированием по равномерной сетке
|
2015-05-14 22:35:07 +03:00
|
|
|
|
uses Utils,GraphABC;
|
|
|
|
|
|
|
|
|
|
|
|
const
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Ширина клетки
|
2015-05-14 22:35:07 +03:00
|
|
|
|
w = 4;
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Количество клеток по ширине
|
2015-05-14 22:35:07 +03:00
|
|
|
|
m = 300;
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Количество клеток по высоте
|
2015-05-14 22:35:07 +03:00
|
|
|
|
n = 220;
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Отступ поля от левой границы окна
|
2015-05-14 22:35:07 +03:00
|
|
|
|
x0 = 1;
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Отступ поля от верхней границы окна
|
2015-05-14 22:35:07 +03:00
|
|
|
|
y0 = 21;
|
|
|
|
|
|
mm = m + 1;
|
|
|
|
|
|
nn = n + 1;
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Количество клеток сетки по горизонтали
|
2015-05-14 22:35:07 +03:00
|
|
|
|
mk = 15;
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Количество клеток сетки по вертикали
|
2015-05-14 22:35:07 +03:00
|
|
|
|
nk = 10;
|
|
|
|
|
|
|
|
|
|
|
|
var
|
|
|
|
|
|
a,b,sosedia,sosedib: array [0..nn,0..mm] of byte;
|
|
|
|
|
|
obnovA,obnovB: array [1..nk,1..mk] of boolean;
|
|
|
|
|
|
CountCells: integer;
|
|
|
|
|
|
obn: boolean;
|
|
|
|
|
|
gen: integer;
|
|
|
|
|
|
hn,hm: integer;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Нарисовать ячейку
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure DrawCell(i,j: integer);
|
|
|
|
|
|
begin
|
|
|
|
|
|
DrawInBuffer := False;
|
|
|
|
|
|
SetBrushColor(clBlack);
|
|
|
|
|
|
FillRectangle(x0+(j-1)*w,y0+(i-1)*w,x0+j*w-1,y0+i*w-1);
|
|
|
|
|
|
DrawInBuffer := True;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Стереть ячейку
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure ClearCell(i,j: integer);
|
|
|
|
|
|
begin
|
|
|
|
|
|
DrawInBuffer := False;
|
|
|
|
|
|
SetBrushColor(clWhite);
|
|
|
|
|
|
FillRectangle(x0+(j-1)*w,y0+(i-1)*w,x0+j*w-1,y0+i*w-1);
|
|
|
|
|
|
DrawInBuffer := True;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Нарисовать все изменившиеся ячейки
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure DrawConfiguration;
|
|
|
|
|
|
begin
|
|
|
|
|
|
for var i:=1 to n do
|
|
|
|
|
|
for var j:=1 to m do
|
|
|
|
|
|
begin
|
|
|
|
|
|
var bb := b[i,j];
|
|
|
|
|
|
if a[i,j]<>bb then
|
|
|
|
|
|
if bb=1 then DrawCell(i,j)
|
|
|
|
|
|
else ClearCell(i,j);
|
|
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Нарисовать все ячейки
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure DrawConfigurationFull;
|
|
|
|
|
|
begin
|
|
|
|
|
|
for var i:=1 to n do
|
|
|
|
|
|
for var j:=1 to m do
|
|
|
|
|
|
if b[i,j]=1 then DrawCell(i,j)
|
|
|
|
|
|
else ClearCell(i,j);
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Нарисовать поле
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure DrawField;
|
|
|
|
|
|
begin
|
|
|
|
|
|
Pen.Color := clLightGray;
|
|
|
|
|
|
for var i:=0 to m do
|
|
|
|
|
|
begin
|
|
|
|
|
|
if i mod hm = 0 then
|
|
|
|
|
|
Pen.Color := clGray
|
|
|
|
|
|
else Pen.Color := clLightGray;
|
|
|
|
|
|
Line(x0+i*w-1,y0,x0+i*w-1,y0+n*w);
|
|
|
|
|
|
end;
|
|
|
|
|
|
for var i:=0 to n do
|
|
|
|
|
|
begin
|
|
|
|
|
|
if i mod hn = 0 then
|
|
|
|
|
|
Pen.Color := clGray
|
|
|
|
|
|
else Pen.Color := clLightGray;
|
|
|
|
|
|
Line(x0,y0+i*w-1,x0+m*w,y0+i*w-1);
|
|
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Увеличить массив соседей для данной клетки
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure IncSosedi(i,j: integer);
|
|
|
|
|
|
var i1,i2,j1,j2: integer;
|
|
|
|
|
|
begin
|
|
|
|
|
|
if i=1 then i1:=n else i1:=i-1;
|
|
|
|
|
|
if i=n then i2:=1 else i2:=i+1;
|
|
|
|
|
|
if j=1 then j1:=m else j1:=j-1;
|
|
|
|
|
|
if j=m then j2:=1 else j2:=j+1;
|
|
|
|
|
|
SosediB[i1,j1] += 1;
|
|
|
|
|
|
SosediB[i1,j] += 1;
|
|
|
|
|
|
SosediB[i1,j2] += 1;
|
|
|
|
|
|
SosediB[i,j1] += 1;
|
|
|
|
|
|
SosediB[i,j2] += 1;
|
|
|
|
|
|
SosediB[i2,j1] += 1;
|
|
|
|
|
|
SosediB[i2,j] += 1;
|
|
|
|
|
|
SosediB[i2,j2] += 1;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Уменьшить массив соседей для данной клетки
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure DecSosedi(i,j: integer);
|
|
|
|
|
|
var i1,i2,j1,j2: integer;
|
|
|
|
|
|
begin
|
|
|
|
|
|
if i=1 then i1:=n else i1:=i-1;
|
|
|
|
|
|
if i=n then i2:=1 else i2:=i+1;
|
|
|
|
|
|
if j=1 then j1:=m else j1:=j-1;
|
|
|
|
|
|
if j=m then j2:=1 else j2:=j+1;
|
|
|
|
|
|
SosediB[i1,j1] -= 1;
|
|
|
|
|
|
SosediB[i1,j] -= 1;
|
|
|
|
|
|
SosediB[i1,j2] -= 1;
|
|
|
|
|
|
SosediB[i,j1] -= 1;
|
|
|
|
|
|
SosediB[i,j2] -= 1;
|
|
|
|
|
|
SosediB[i2,j1] -= 1;
|
|
|
|
|
|
SosediB[i2,j] -= 1;
|
|
|
|
|
|
SosediB[i2,j2] -= 1;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Поставить ячейку в клетку (i,j)
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure SetCell(i,j: integer);
|
|
|
|
|
|
begin
|
|
|
|
|
|
if b[i,j]=0 then
|
|
|
|
|
|
begin
|
|
|
|
|
|
b[i,j] := 1;
|
|
|
|
|
|
obn := True;
|
|
|
|
|
|
IncSosedi(i,j);
|
|
|
|
|
|
end;
|
|
|
|
|
|
CountCells += 1;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Убрать ячейку из клетки (i,j)
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure UnSetCell(i,j: integer);
|
|
|
|
|
|
begin
|
|
|
|
|
|
if b[i,j]=1 then
|
|
|
|
|
|
begin
|
|
|
|
|
|
b[i,j] := 0;
|
|
|
|
|
|
obn := True;
|
|
|
|
|
|
DecSosedi(i,j);
|
|
|
|
|
|
end;
|
|
|
|
|
|
CountCells -= 1;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Инициализировать массивы и конфигурацию поля
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure Init;
|
|
|
|
|
|
var
|
|
|
|
|
|
xc := n div 2;
|
|
|
|
|
|
yc := m div 2;
|
|
|
|
|
|
begin
|
|
|
|
|
|
for var i:=0 to n+1 do
|
|
|
|
|
|
for var j:=0 to m+1 do
|
|
|
|
|
|
b[i,j] := 0;
|
|
|
|
|
|
a := b;
|
|
|
|
|
|
SosediB := b;
|
|
|
|
|
|
SosediA := SosediB;
|
|
|
|
|
|
for var ik:=1 to nk do
|
|
|
|
|
|
for var jk:=1 to mk do
|
|
|
|
|
|
obnovB[ik,jk] := True;
|
|
|
|
|
|
obnovA := obnovB;
|
|
|
|
|
|
CountCells := 0;
|
|
|
|
|
|
|
|
|
|
|
|
SetCell(xc,yc);
|
|
|
|
|
|
SetCell(xc,yc+1);
|
|
|
|
|
|
SetCell(xc,yc+2);
|
|
|
|
|
|
SetCell(xc-1,yc+2);
|
|
|
|
|
|
SetCell(xc+1,yc+1);
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Обработать ячейку
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure ProcessCell(i,j: integer);
|
|
|
|
|
|
begin
|
|
|
|
|
|
case SosediA[i,j] of
|
|
|
|
|
|
0..1,4..9:
|
|
|
|
|
|
if b[i,j]=1 then
|
|
|
|
|
|
begin
|
|
|
|
|
|
b[i,j] := 0;
|
|
|
|
|
|
obn := True;
|
|
|
|
|
|
DecSosedi(i,j);
|
|
|
|
|
|
ClearCell(i,j);
|
|
|
|
|
|
Dec(CountCells);
|
|
|
|
|
|
end;
|
|
|
|
|
|
3: if b[i,j]=0 then
|
|
|
|
|
|
begin
|
|
|
|
|
|
b[i,j] := 1;
|
|
|
|
|
|
obn := True;
|
|
|
|
|
|
IncSosedi(i,j);
|
|
|
|
|
|
DrawCell(i,j);
|
|
|
|
|
|
Inc(CountCells);
|
|
|
|
|
|
end;
|
|
|
|
|
|
end; {case}
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Перейти к следующему поколению
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure NextGen;
|
|
|
|
|
|
var ifirst,jfirst,ilast,jlast: integer;
|
|
|
|
|
|
begin
|
|
|
|
|
|
for var ik:=1 to nk do
|
|
|
|
|
|
begin
|
|
|
|
|
|
for var jk:=1 to mk do
|
|
|
|
|
|
begin
|
|
|
|
|
|
obn := False;
|
|
|
|
|
|
ifirst := (ik-1)*hn+1;
|
|
|
|
|
|
ilast := (ik-1)*hn+hn;
|
|
|
|
|
|
jfirst := (jk-1)*hm+1;
|
|
|
|
|
|
jlast := (jk-1)*hm+hm;
|
|
|
|
|
|
if obnovA[ik,jk] then
|
|
|
|
|
|
begin
|
|
|
|
|
|
for var i:=ifirst to ilast do
|
|
|
|
|
|
for var j:=jfirst to jlast do
|
|
|
|
|
|
ProcessCell(i,j);
|
|
|
|
|
|
end
|
|
|
|
|
|
else
|
|
|
|
|
|
begin
|
|
|
|
|
|
var ik1,jk1,ik2,jk2: integer;
|
|
|
|
|
|
if ik=1 then ik1:=nk else ik1:=ik-1;
|
|
|
|
|
|
if ik=nk then ik2:=1 else ik2:=ik+1;
|
|
|
|
|
|
if jk=1 then jk1:=mk else jk1:=jk-1;
|
|
|
|
|
|
if jk=mk then jk2:=1 else jk2:=jk+1;
|
|
|
|
|
|
var l := obnovA[ik,jk1];
|
|
|
|
|
|
var r := obnovA[ik,jk2];
|
|
|
|
|
|
var u := obnovA[ik1,jk];
|
|
|
|
|
|
var d := obnovA[ik2,jk];
|
|
|
|
|
|
var lu := obnovA[ik1,jk1];
|
|
|
|
|
|
var ld := obnovA[ik2,jk1];
|
|
|
|
|
|
var ru := obnovA[ik1,jk2];
|
|
|
|
|
|
var rd := obnovA[ik2,jk2];
|
|
|
|
|
|
if u then
|
|
|
|
|
|
for var j:=jfirst+1 to jlast-1 do
|
|
|
|
|
|
ProcessCell(ifirst,j);
|
|
|
|
|
|
if d then
|
|
|
|
|
|
for var j:=jfirst+1 to jlast-1 do
|
|
|
|
|
|
ProcessCell(ilast,j);
|
|
|
|
|
|
if l then
|
|
|
|
|
|
for var i:=ifirst+1 to ilast-1 do
|
|
|
|
|
|
ProcessCell(i,jfirst);
|
|
|
|
|
|
if r then
|
|
|
|
|
|
for var i:=ifirst+1 to ilast-1 do
|
|
|
|
|
|
ProcessCell(i,jlast);
|
|
|
|
|
|
if u or l or lu then
|
|
|
|
|
|
ProcessCell(ifirst,jfirst);
|
|
|
|
|
|
if u or r or ru then
|
|
|
|
|
|
ProcessCell(ifirst,jlast);
|
|
|
|
|
|
if d or l or ld then
|
|
|
|
|
|
ProcessCell(ilast,jfirst);
|
|
|
|
|
|
if d or r or rd then
|
|
|
|
|
|
ProcessCell(ilast,jlast);
|
|
|
|
|
|
end;
|
|
|
|
|
|
obnovB[ik,jk] := obn;
|
|
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Перерисовка содержимого окна
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure LifeRedrawProc;
|
|
|
|
|
|
begin
|
|
|
|
|
|
Redraw;
|
|
|
|
|
|
DrawConfigurationFull;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/// Вывод номера поколения и количества ячеек
|
2015-05-14 22:35:07 +03:00
|
|
|
|
procedure DrawInfo;
|
|
|
|
|
|
begin
|
|
|
|
|
|
Brush.Color := clWhite;
|
2015-12-28 14:25:15 +03:00
|
|
|
|
TextOut(25,0,'Поколение '+IntToStr(gen));
|
|
|
|
|
|
TextOut(WindowWidth - 130,0,'Жителей: '+IntToStr(CountCells)+' ');
|
2015-05-14 22:35:07 +03:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
|
SetConsoleIO;
|
|
|
|
|
|
if (m mod mk<>0) or (n mod nk<>0) then
|
|
|
|
|
|
begin
|
2015-12-28 14:25:15 +03:00
|
|
|
|
writeln('Размер кластера не согласован с размером поля. Программа завершена');
|
2015-05-14 22:35:07 +03:00
|
|
|
|
exit
|
|
|
|
|
|
end;
|
|
|
|
|
|
hm := m div mk;
|
|
|
|
|
|
hn := n div nk;
|
|
|
|
|
|
SetWindowSize(x0+m*w,y0+n*w);
|
|
|
|
|
|
CenterWindow;
|
2015-12-28 14:25:15 +03:00
|
|
|
|
Window.Title := 'Игра "Жизнь"';
|
2015-05-14 22:35:07 +03:00
|
|
|
|
Window.IsFixedSize := True;
|
|
|
|
|
|
Font.Name := 'Arial';
|
|
|
|
|
|
Font.Size := 10;
|
|
|
|
|
|
Init;
|
|
|
|
|
|
|
|
|
|
|
|
LockDrawing;
|
|
|
|
|
|
DrawInfo;
|
|
|
|
|
|
DrawField;
|
|
|
|
|
|
DrawConfiguration;
|
|
|
|
|
|
UnLockDrawing;
|
|
|
|
|
|
|
|
|
|
|
|
var mil := Milliseconds;
|
|
|
|
|
|
gen := 0;
|
|
|
|
|
|
RedrawProc := LifeRedrawProc;
|
|
|
|
|
|
while True do
|
|
|
|
|
|
begin
|
|
|
|
|
|
gen += 1;
|
|
|
|
|
|
|
|
|
|
|
|
if gen mod 11 = 0 then
|
|
|
|
|
|
DrawInfo;
|
|
|
|
|
|
|
|
|
|
|
|
SosediA := SosediB;
|
|
|
|
|
|
obnovA := obnovB;
|
|
|
|
|
|
NextGen;
|
|
|
|
|
|
|
|
|
|
|
|
if gen mod 1000 = 0 then
|
|
|
|
|
|
begin
|
|
|
|
|
|
var mil1 := Milliseconds;
|
|
|
|
|
|
writeln(gen,' ',(mil1-mil)/1000);
|
|
|
|
|
|
mil := mil1;
|
|
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
end.
|