351 lines
7.5 KiB
ObjectPascal
351 lines
7.5 KiB
ObjectPascal
// Игра Жизнь на торе
|
||
// Оптимизация хешированием по равномерной сетке
|
||
|
||
uses GraphABC;
|
||
|
||
const
|
||
w =3;
|
||
w1=1;
|
||
k=20;
|
||
m=300;
|
||
n=220;
|
||
graphW=0;
|
||
mk=m div k;//15;
|
||
nk=n div k;//10;
|
||
mm=m+1;
|
||
nn=n+1;
|
||
x0=1;
|
||
y0=21;
|
||
ClearColor=clBlack;
|
||
FillColor=clLimeGreen;
|
||
|
||
var
|
||
FiledColor := RGB(0,40,0);
|
||
FiledColor2 := RGB(0,70,0);
|
||
|
||
{ClearColor=clWhite;
|
||
FillColor=clBlack;
|
||
FiledColor=clLightGray;
|
||
FiledColor2=clGray;{}
|
||
|
||
|
||
var
|
||
//a,b,sosedia,sosedib: array [0..nn,0..mm] of byte;
|
||
a,b,sosedia,sosedib:array of array of byte;
|
||
//obnovA,obnovB: array [1..nk,1..mk] of boolean;
|
||
obnovA,obnovB: array of array of boolean;
|
||
count: integer;
|
||
obn: boolean;
|
||
mil,mil1: integer;
|
||
hn,hm: integer;
|
||
|
||
procedure AssignArray(var arr:array of array of boolean; n,m:integer);
|
||
begin
|
||
SetLength(arr,n);
|
||
for var i:=0 to n-1 do
|
||
SetLength(arr[i],m);
|
||
end;
|
||
procedure AssignArray(var arr:array of array of byte; n,m:integer);
|
||
begin
|
||
SetLength(arr,n);
|
||
for var i:=0 to n-1 do
|
||
SetLength(arr[i],m);
|
||
end;
|
||
procedure CopyArray(arr1,arr2:array of array of byte);
|
||
begin
|
||
for var i:=0 to arr1.Length-1 do
|
||
arr1[i].CopyTo(arr2[i],0);
|
||
end;
|
||
procedure CopyArray(arr1,arr2:array of array of boolean);
|
||
begin
|
||
for var i:=0 to arr1.Length-1 do
|
||
arr1[i].CopyTo(arr2[i],0);
|
||
end;
|
||
|
||
procedure DrawCell(i,j: integer);
|
||
begin
|
||
if BrushColor<>FillColor then begin
|
||
SetBrushColor(FillColor);
|
||
SetPenColor(FillColor);
|
||
end;
|
||
FillRect(x0+(j-1)*w,y0+(i-1)*w,x0+j*w-w1,y0+i*w-w1);
|
||
end;
|
||
|
||
|
||
procedure ClearCell(i,j: integer);
|
||
begin
|
||
if BrushColor<>clearColor then begin
|
||
SetBrushColor(clearColor);
|
||
SetPenColor(clearColor);
|
||
end;
|
||
FillRect(x0+(j-1)*w,y0+(i-1)*w,x0+j*w-w1,y0+i*w-w1);
|
||
end;
|
||
|
||
procedure DrawConfiguration;
|
||
begin
|
||
for var i:=1 to n do
|
||
for var j:=1 to m do
|
||
if a[i,j]=1 then
|
||
DrawCell(i,j)
|
||
end;
|
||
|
||
procedure DrawField;
|
||
begin
|
||
SetBrushColor(ClearColor);
|
||
FillRectangle(x0,y0,x0+m*w,y0+n*w);
|
||
SetPenColor(FiledColor);
|
||
for var i:=0 to m do
|
||
Line(x0+i*w-1,y0,x0+i*w-1,y0+n*w);
|
||
for var i:=0 to n do
|
||
Line(x0,y0+i*w-1,x0+m*w,y0+i*w-1);
|
||
SetPenColor(FiledColor2);
|
||
for var i:=0 to m div hm do
|
||
Line(x0+i*w*hm-1,y0,x0+i*w*hm-1,y0+n*w);
|
||
for var i:=0 to n div hn do
|
||
Line(x0,y0+i*w*hn-1,x0+m*w,y0+i*w*hn-1);
|
||
end;
|
||
|
||
procedure IncSosedi(i,j: integer);
|
||
begin
|
||
var i1 := i=1 ? n : i-1;
|
||
var i2 := i=n ? 1 : i+1;
|
||
var j1 := j=1 ? m : j-1;
|
||
var j2 := j=m ? 1 : 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;
|
||
|
||
procedure DecSosedi(i,j: integer);
|
||
begin
|
||
var i1 := i=1 ? n : i-1;
|
||
var i2 := i=n ? 1 : i+1;
|
||
var j1 := j=1 ? m : j-1;
|
||
var j2 := j=m ? 1 : 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;
|
||
|
||
procedure SetCell(i,j: integer);
|
||
begin
|
||
if b[i,j]=0 then
|
||
begin
|
||
b[i,j]:=1;
|
||
obn:=true;
|
||
IncSosedi(i,j);
|
||
end;
|
||
count += 1;
|
||
end;
|
||
|
||
procedure UnSetCell(i,j: integer);
|
||
begin
|
||
if b[i,j]=1 then
|
||
begin
|
||
b[i,j]:=0;
|
||
obn:=true;
|
||
DecSosedi(i,j);
|
||
end;
|
||
count -= 1;
|
||
end;
|
||
|
||
type
|
||
ColonyType = (Big, LD, RD, LU, RU);
|
||
procedure AddColonyType(xc,yc:integer; ctype:ColonyType);
|
||
begin
|
||
case ctype of
|
||
ColonyType.Big:begin
|
||
SetCell(xc,yc);
|
||
SetCell(xc,yc+1);
|
||
SetCell(xc,yc+2);
|
||
SetCell(xc-1,yc+2);
|
||
SetCell(xc+1,yc+1);
|
||
end;
|
||
ColonyType.LD:begin
|
||
SetCell(xc,yc-1);
|
||
SetCell(xc,yc);
|
||
SetCell(xc,yc+1);
|
||
SetCell(xc-1,yc-1);
|
||
SetCell(xc-2,yc);
|
||
end;
|
||
end;
|
||
//SosediA:=SosediB;
|
||
CopyArray(sosedib,sosedia);
|
||
for var ik:=1 to nk do
|
||
for var jk:=1 to mk do
|
||
obnovB[ik,jk]:=true;
|
||
//obnovA:=obnovB;
|
||
CopyArray(obnovB,obnovA);
|
||
end;
|
||
|
||
procedure Init;
|
||
begin
|
||
Count:=0;
|
||
AddColonyType(n div 2,m div 2, ColonyType.Big);
|
||
end;
|
||
|
||
procedure OnlyCase(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);
|
||
count -= 1;
|
||
end;
|
||
3: if b[i,j]=0 then
|
||
begin
|
||
b[i,j]:=1;
|
||
obn:=true;
|
||
IncSosedi(i,j);
|
||
DrawCell(i,j);
|
||
count += 1;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure NextGen;
|
||
var
|
||
i,j,ik1,jk1,ik2,jk2,ifirst,jfirst,ilast,jlast: integer;
|
||
l,r,u,d,lu,ld,ru,rd: boolean;
|
||
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*hn;
|
||
jfirst := (jk-1)*hm+1;
|
||
jlast := jk*hm;
|
||
if obnovA[ik,jk] then
|
||
begin
|
||
for i:=ifirst to ilast do
|
||
for j:=jfirst to jlast do
|
||
OnlyCase(i,j);
|
||
end
|
||
else
|
||
begin
|
||
ik1 := ik=1 ? nk : ik-1;
|
||
ik2 := ik=nk ? 1 : ik+1;
|
||
jk1 := jk=1 ? mk : jk-1;
|
||
jk2 := jk=mk ? 1 : jk+1;
|
||
l:=obnovA[ik,jk1];
|
||
r:=obnovA[ik,jk2];
|
||
u:=obnovA[ik1,jk];
|
||
d:=obnovA[ik2,jk];
|
||
lu:=obnovA[ik1,jk1];
|
||
ld:=obnovA[ik2,jk1];
|
||
ru:=obnovA[ik1,jk2];
|
||
rd:=obnovA[ik2,jk2];
|
||
if u then
|
||
begin
|
||
i:=ifirst;
|
||
for j:=jfirst+1 to jlast-1 do
|
||
OnlyCase(i,j);
|
||
end;
|
||
if d then
|
||
begin
|
||
i:=ilast;
|
||
for j:=jfirst+1 to jlast-1 do
|
||
OnlyCase(i,j);
|
||
end;
|
||
if l then
|
||
begin
|
||
j:=jfirst;
|
||
for i:=ifirst+1 to ilast-1 do
|
||
OnlyCase(i,j);
|
||
end;
|
||
if r then
|
||
begin
|
||
j:=jlast;
|
||
for i:=ifirst+1 to ilast-1 do
|
||
OnlyCase(i,j);
|
||
end;
|
||
if u or l or lu then
|
||
OnlyCase(ifirst,jfirst);
|
||
if u or r or ru then
|
||
OnlyCase(ifirst,jlast);
|
||
if d or l or ld then
|
||
OnlyCase(ilast,jfirst);
|
||
if d or r or rd then
|
||
OnlyCase(ilast,jlast);
|
||
end;
|
||
obnovB[ik,jk]:=obn;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure MouseDown(x,y,b:integer);
|
||
begin
|
||
case b of
|
||
1:AddColonyType((y-y0)div w,(x-x0)div w, ColonyType.LD);
|
||
|
||
end;
|
||
end;
|
||
|
||
begin
|
||
SetConsoleIO;
|
||
AssignArray(obnovA,nk+1,mk+1);
|
||
AssignArray(obnovB,nk+1,mk+1);
|
||
AssignArray(a,nn+1,mm+1);
|
||
AssignArray(b,nn+1,mm+1);
|
||
AssignArray(sosedia,nn+1,mm+1);
|
||
AssignArray(sosedib,nn+1,mm+1);
|
||
SetWindowCaption('Игра "Жизнь"');
|
||
if (m mod mk<>0) or (n mod nk<>0) then
|
||
begin
|
||
writeln('Размер кластера не согласован с размером поля. Программа завершена');
|
||
exit
|
||
end;
|
||
hm:=m div mk;
|
||
hn:=n div nk;
|
||
SetBrushColor(ClearColor);
|
||
SetWindowSize(x0+m*w,y0+n*w+graphW);
|
||
CenterWindow;
|
||
ClearWindow(ClearColor);
|
||
SetFontName('Courier New');
|
||
SetFontSize(10);
|
||
Init;
|
||
DrawField;
|
||
DrawConfiguration;
|
||
OnMouseDown:=MouseDown;
|
||
mil:=Milliseconds;
|
||
var gen:=0;
|
||
DrawInBuffer := false;
|
||
while true do begin
|
||
gen+=1;
|
||
//SosediA:=SosediB;
|
||
//obnovA:=obnovB;
|
||
CopyArray(sosedib,sosedia);
|
||
CopyArray(obnovB,obnovA);
|
||
NextGen;
|
||
if gen mod 10 = 0 then begin
|
||
DrawInBuffer := True;
|
||
SetBrushColor(ClearColor);
|
||
SetFontColor(FillColor);
|
||
TextOut(25, 0,'Поколение: '+IntToStr(gen));
|
||
TextOut(765,0,'Жителей: '+IntToStr(count)+' ');
|
||
if gen mod 1000 = 0 then begin
|
||
mil1:=Milliseconds;
|
||
writeln(gen,' ',(mil1-mil)/1000);
|
||
mil:=mil1;
|
||
end;
|
||
DrawInBuffer := false;
|
||
end;
|
||
end;
|
||
end.
|