- •Курсова робота з курсу: “ Програмування та алгоритмічні мови” на тему: Гра “Сапер”
- •1. Постановка задачі
- •2. Метод розв’язку
- •3. Алгоритм розв’язку
- •4. Опис програмного продукту
- •4.1. Опис головних структур і змінних програми
- •4.2. Опис головних процедур та функцій програми
- •5. Опис інтерфейсу
- •6. Результати роботи програмного продукту
- •Додаток а. Лістинг програми
6. Результати роботи програмного продукту
На рисунках 6.1 – 6.3 представлені результати роботи програми у вигляді скріншотів.
Рисунки 6.1 та 6.2 демонструють процеси еволюції різних популяцій клітин при різному масштабі ігрового поля:
Рисунок 6.3 демонструє дію алгоритму розфарбування на довільний популяції:
Рис 6.1 Робота програми при великому масштабі
Рис 6.2 Робота програми за малого масштабу
Рис 6.3 Робота алгоритму розфарбування
Висновки
В ході цієї роботи було розроблено програмний продукт – ігрову програму «Game Life», що є комп’ютерною реалізацією гри «Життя», винайденої Дж. Конвеєм. Отримана розробка є класичною версією гри. Реалізовано гру на двовимірній ортогональній площині за стандартними правилами; реалізовано гру на торообразній поверхні, а також обмежених поверхнях з різним типом меж; розроблено та реалізовано алгоритм фарбування живих клітин, що спрощує аналіз еволюції популяції. Дана розробка дає користувачеві можливість збереження за завантаження ігрових світів із зовнішніх файлів з розширенням GLF.
Переваги даної розробки: низькі вимоги до апаратного та програмного забезпечення, порівняно з конкурентними продуктами, низькі вимоги до оперативної пам’яті, стабільна та коректна робота програми, зручний інтерфейс, гнучка система налаштувань, реалізація гри на торі, можливість збереження та завантаження гри в власний формат.
Серед недоліків варто зазначити: уповільнення роботи програми із ігровим полем велкого розміру розмірів на близькій до максимальної швидкості, неможливість створення поля більшого за 100x100 клітин.
Список використаної літератури
-
Архангельский О. Я. 100 компонентов общего назначения Delphi 5 [Текст] : навч. посiбник / Олексій Якович Архангельский. - М.: Біном, 1999 - 134 с.
-
Немнюгін С.А. Turbo Pascal. Программирование на языке высокого уровня [Текст] : навч. посiбник / Сергій Андрійович Немнюгін. - М.: Питер, 2008. - 544 с.
-
Wikipedia, the free encyclopedia [Електронний ресурс]: Conway’s Game of Life.- Режим доступу: http://en.wikipedia.org/wiki/Conway's_Game_of_Life, вільний.- Назва з екрану.
-
Wikipedia [Електронний ресурс]: Жызнь (игра).- Режим доступу: http://ru.wikipedia.org/wiki/Жызнь_(Игра), вільний.- Назва з екрану.
-
Gamedev – Разработка игр [Електронний ресурс]: Форум разработчиков игр. - Режим доступу: http://www.gamedev.ru/forum/, вільний.- Назва з екрану.
Додаток а. Лістинг програми
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, ComCtrls, Buttons;
type
TForm1 = class(TForm)
gametimer: TTimer;
TorusBordersButton: TRadioButton;
DeadBorderButton: TRadioButton;
AliveBorderButton: TRadioButton;
SpeedBar: TTrackBar;
MultiColorButton: TCheckBox;
RandomButton: TSpeedButton;
LifeImage: TImage;
PauseButton: TSpeedButton;
ClearFieldButton: TSpeedButton;
StartButton: TSpeedButton;
OpenGLF: TOpenDialog;
SaveGLF: TSaveDialog;
StepButton: TSpeedButton;
ResizeButton: TSpeedButton;
HelpButton: TSpeedButton;
SpeedLabel: TLabel;
CellSizeTrackBar: TTrackBar;
SaveButton: TSpeedButton;
LoadButton: TSpeedButton;
procedure FormInitialization(Sender: TObject);
procedure ontimerevent(Sender: TObject);
procedure TorusBordersButtonOn(Sender: TObject);
procedure AliveBorderOn(Sender: TObject);
procedure DeadBorderButtonOn(Sender: TObject);
procedure SpeenChange(Sender: TObject);
procedure RandomButtonClick(Sender: TObject);
procedure PauseButtonClick(Sender: TObject);
procedure MultiColorButtonClick(Sender: TObject);
procedure LifeImageMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure LifeImageMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure LifeImageMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure ClearFieldButtonClick(Sender: TObject);
procedure StartButtonClick(Sender: TObject);
procedure StepButtonClick(Sender: TObject);
procedure ResizeButtonClick(Sender: TObject);
procedure CellSizeTrackBarChange(Sender: TObject);
procedure HelpButtonClick(Sender: TObject);
procedure LoadButtonClick(Sender: TObject);
procedure SaveButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
procedure FieldInit(FieldX00,FieldY00,FieldX11,FieldY11,xmaFieldX0,ymaFieldX0:integer);
procedure RandomizeField;
procedure SetTypeCell(x,y:integer;typee:integer);{set cell's type}
procedure SetCell(x,y:integer;state:integer);{set cell's state if it's type is 0}
procedure XorCell(x,y:integer);{change cell's state if it's type is 0}
procedure draw;
procedure DrawConsoleWithStep;
procedure DrawWithStep;
function max(a,b:integer):integer;
function min(a,b:integer):integer;
procedure StepForward;
function HSV2RGB(h: integer; s,v: double):TColor;
procedure ClearField;
function BecomeDead(a:integer):Boolean;
function BecomeAlive(a:integer):Boolean;
function TrickyMod(a,b:integer):Integer;
procedure FieldResize(FieldX00,FieldY00,FieldX11,FieldY11:Integer); overload;
procedure FieldResize(CellNumber:integer); overload;
procedure SetBorders(BorderType:integer);
{Tricky mod function for torus field}
const MaxMatrixSize=257;
type MatrixType=array[0..MaxMatrixSize]of array[0..MaxMatrixSize] of integer;
var
Form1: TForm1;
CellState:MatrixType;
{state: 0- dead, 1- alive}
CellType:MatrixType;
{type: 0- usual cell, 1- always alive cell, 2- always dead cell}
CellAge:MatrixType;
{Number of steps cell exist. Used to color cells}
temp:MatrixType;
{array for temporary use}
CellChangedOnMouseDown:array[0..MaxMatrixSize]of array[0..MaxMatrixSize]of Boolean;
xmax,ymax:integer;
FieldX0,FieldX1,FieldY0,FieldY1:integer;
colors:array[0..255]of TColor;
BordersAreDead: boolean;
FieldIsTorus: boolean;
BecomeAliveMin,BecomeAliveMax:Integer;
StayAliveMin,StayAliveMax:Integer;
MaxCellAge: integer;
FieldYStart: integer;
MultiColorMode: boolean;
CellSize: Double;
CurrMaxCellAge: integer;
CurrMouseButton: TMouseButton;
MouseButtonDown: boolean;
CurrRules: integer;
BordersType: integer;
procedure FieldWipe;
procedure FieldLoad(FileName: TFileName);
procedure FieldSave(FileName: TFileName);
implementation
uses Unit2;
{$R *.dfm}
function HSV2RGB(h: integer; s,v: double):TColor;
var
Hi: integer;
f,p,q,t,r,g,b: double;
begin
Hi:=(h div 60) mod 6;
f:=h/60-(h div 60);
p:=v*(1-s);
q:=v*(1-f*s);
t:=v*(1-(1-f)*s);
if Hi=0 then begin
r:=v;
g:=t;
b:=p;
end;
if Hi=1 then begin
r:=q;
g:=v;
b:=p;
end;
if Hi=2 then begin
r:=p;
g:=v;
b:=t;
end;
if Hi=3 then begin
r:=p;
g:=q;
b:=v;
end;
if Hi=4 then begin
r:=t;
g:=p;
b:=v;
end;
if Hi=5 then begin
r:=v;
g:=p;
b:=q;
end;
HSV2RGB:=256*256*round(r*255)+256*round(g*255)+round(b*255);
end;
function max(a,b:integer):integer;
begin
if (a>b) then b:=a;
max:=b;
end;
function min(a,b:integer):integer;
begin
if (a<b) then b:=a;
min:=b;
end;
function BecomeDead(a:integer):Boolean;
begin
BecomeDead:=(a<StayAliveMin) or (a>StayAliveMax);
end;
function BecomeAlive(a:integer):Boolean;
begin
BecomeAlive:=(a>=BecomeAliveMin) and (a<=BecomeAliveMax) ;
end;
function TrickyMod(a,b:integer):Integer;
begin
if(a<0)then TrickyMod:=b+1+1+a else
if(a>(b+1))then TrickyMod:=b+2-a else
TrickyMod:=a;
end;
procedure StepForward;
var i,imin,imax,j,jmin,jmax,NeighborN:integer;
begin
if(FieldIsTorus)then
begin
imin:=0;
imax:=xmax+1;
jmin:=0;
jmax:=ymax+1
end
else
begin
imin:=1;
imax:=xmax;
jmin:=1;
jmax:=ymax;
end;
CurrMaxCellAge:=1;
for i:=imin to imax do
for j:=jmin to jmax do
begin
NeighborN:=
CellState[TrickyMod(i+1,xmax) ][TrickyMod(j+1,ymax) ]+
CellState[TrickyMod(i+1,xmax) ][TrickyMod(j,ymax) ]+
CellState[TrickyMod(i+1,xmax) ][TrickyMod(j-1,ymax) ]+
CellState[TrickyMod(i,xmax) ][TrickyMod(j-1,ymax) ]+
CellState[TrickyMod(i-1,xmax) ][TrickyMod(j-1,ymax) ]+
CellState[TrickyMod(i-1,xmax) ][TrickyMod(j,ymax) ]+
CellState[TrickyMod(i-1,xmax) ][TrickyMod(j+1,ymax) ]+
CellState[TrickyMod(i,xmax) ][TrickyMod(j+1,ymax) ];
if BecomeDead(NeighborN) then
begin
temp[i,j]:=0;
CellAge[i,j]:=0;
end
else
if ((CellState[i,j]=0) and BecomeAlive(NeighborN)) then
begin
temp[i,j]:=1;
CellAge[i,j]:=0;
end
else
temp[i,j]:=CellState[i,j];
if(CellType[i,j]=0) then CellAge[i,j]:=CellAge[i,j]+1;
if(CellAge[i,j]>MaxCellAge)then CellAge[i,j]:=MaxCellAge;
if(CellType[i,j]=0) then CurrMaxCellAge:=max(CellAge[i,j],CurrMaxCellAge);
end;
for i:=imin to imax do
for j:=jmin to jmax do
if (CellType[i,j]=0) then
CellState[i,j]:=temp[i,j];
end;
procedure FieldWipe;
var i,j:Integer;
begin
for i:=0 to MaxMatrixSize do
for j:=0 to MaxMatrixSize do
begin
CellState[i,j]:=0;
CellType[i,j]:=0;
CellAge[i,j]:=0;
end;
end;
procedure FieldInit(FieldX00,FieldY00,FieldX11,FieldY11,xmaFieldX0,ymaFieldX0:integer);
var i,j:integer;
begin
begin
FieldX0:=FieldX00;
FieldX1:=FieldX11;
FieldY0:=FieldY00;
FieldY1:=FieldY11;
xmax:=xmaFieldX0;
ymax:=ymaFieldX0;
FieldWipe;
end;
end;
procedure FieldResize(CellNumber:integer); overload;
begin
xmax:=cellnumber;
ymax:=CellNumber;
ClearField;
end;
procedure FieldResize(FieldX00,FieldY00,FieldX11,FieldY11:Integer); overload;
begin
FieldX0:=FieldX00;
FieldX1:=FieldX11;
FieldY0:=FieldY00;
FieldY1:=FieldY11;
end;
procedure ClearField;
var i,imin,imax,j,jmin,jmax:integer;
begin
if(FieldIsTorus)then
begin
imin:=0;
imax:=xmax+1;
jmin:=0;
jmax:=ymax+1
end
else
begin
imin:=1;
imax:=xmax;
jmin:=1;
jmax:=ymax;
end;
for i:=imin to imax do
for j:=jmin to jmax do
begin
CellState[i,j]:=0;
end;
end;
procedure RandomizeField;
var i,imin,imax,j,jmin,jmax:integer;
begin
if(FieldIsTorus)then
begin
imin:=0;
imax:=xmax+1;
jmin:=0;
jmax:=ymax+1
end
else
begin
imin:=1;
imax:=xmax;
jmin:=1;
jmax:=ymax;
end;
for i:=imin to imax do
for j:=jmin to jmax do if(CellType[i,j]=0)then
CellState[i,j]:=random(2);
end;
procedure SetTypeCell(x,y:integer;typee:integer);{set cell's type}
begin
end;
procedure SetCell(x,y:integer;state:integer);{set cell's state if it's type is 0}
begin
if(CellType[x,y]=0)then
begin
CellState[x,y]:=STATE;
CellAge[x,y]:=0;
end;
end;
procedure XorCell(x,y:integer);{change cell's state if it's type is 0}
begin
if(CellType[x,y]=0)then
begin
CellState[x,y]:=1-CellState[x,y];
CellAge[x,y]:=0;
end;
end;
procedure draw;
var
i,j:integer;
begin
cellsize:=((FieldX1-FieldX0-1)/(xmax+2));//,(FieldY1-FieldY0+1)/(ymax+2));
for i:=0 to xmax+1 do
for j:=0 to ymax+1 do
begin
if(Form1.MultiColorButton.Checked)then
begin
if(CellState[i,j]=0)then
Form1.LifeImage.Canvas.Brush.Color:=colors[0]
else
Form1.LifeImage.Canvas.Brush.Color:=HSV2RGB((100+(240*(CellAge[i,j]))div (currMaxCellAge)),1,1)
end
else
Form1.LifeImage.Canvas.Brush.Color:=colors[CellState[i,j]];
Form1.LifeImage.Canvas.Rectangle(Round(FieldX0+i*cellsize),round(FieldY0+j*cellsize),round(FieldX0+(1+i)*cellsize)+1,1+round(FieldY0+(1+j)*cellsize));
end;
end;
procedure DrawConsoleWithStep;
var i,j:integer;
begin
stepForward;
for j:=0 to ymax+1 do
begin
writeln;
for i:=0 to xmax+1 do
if(CellState[i,j]=0)then
write(' ')
else
write('#');
end;
end;
procedure DrawWithStep;
begin
stepforward;
draw;
end;
procedure TForm1.FormInitialization(Sender: TObject);
begin
FieldIsTorus:=True;
BordersType:=0;
CurrRules:=1;
StayAliveMin:=2;
StayAliveMax:=3;
BecomeAliveMin:=3;
BecomeAliveMax:=3;
FieldYStart:=50;
MaxCellAge:=20;
FieldInit(1,1,form1.LifeImage.Width,form1.LifeImage.Height,24,24);
FieldResize(10);
randomizefield;
colors[1]:=HSV2RGB(100,1,1);
colors[0]:=$00FFFFFF;
draw;
end;
procedure TForm1.ontimerevent(Sender: TObject);
begin
DrawWithStep;
end;
procedure SetBorders(bordertype:integer);
var i,j,borderstate:Integer;
begin
BordersType:=bordertype;
if(BordersType<>0)then
begin
borderstate:=2-borderstype;
for i:=0 to xmax+1 do
begin
CellState[i,0]:=borderstate;
CellState[i,ymax+1]:=borderstate;
CellAge[i,0]:=0;
CellAge[i,ymax+1]:=0;
end;
for j:=0 to ymax+1 do
begin
CellState[0,j]:=borderstate;
CellState[xmax+1,j]:=borderstate;
CellAge[0,j]:=0;
CellAge[xmax+1,j]:=0;
end;
end
else
borderstype:=0;
for i:=0 to xmax+1 do
begin
CellType[i,0]:=borderstype;
CellType[i,ymax+1]:=borderstype;
end;
for j:=0 to ymax+1 do
begin
CellType[0,j]:=borderstype;
CellType[xmax+1,j]:=borderstype;
end;
end;
procedure TForm1.TorusBordersButtonOn(Sender: TObject);
const bordertype=0;
var i,j:Integer;
begin
FieldIsTorus:=True;
SetBorders(0);
draw;
end;
procedure TForm1.AliveBorderOn(Sender: TObject);
var i,j:Integer;
const bordertype=1;
const BorderState=1;
begin
FieldIsTorus:=False;
BordersAreDead:=False;
SetBorders(1);
draw;
end;
procedure TForm1.DeadBorderButtonOn(Sender: TObject);
var i,j:integer;
const bordertype=2;
const BorderState=0;
begin
FieldIsTorus:=False;
BordersAreDead:=true;
SetBorders(2);
draw;
end;
procedure TForm1.SpeenChange(Sender: TObject);
var r:Real;
begin
r:=(1024+60-SpeedBar.Position)/1024;
gametimer.Interval:=Trunc(1000*(r*r))
end;
procedure TForm1.RandomButtonClick(Sender: TObject);
begin
RandomizeField;
draw;
end;
procedure TForm1.PauseButtonClick(Sender: TObject);
begin
gametimer.Enabled:=false;
end;
procedure TForm1.MultiColorButtonClick(Sender: TObject);
begin
draw;
end;
procedure TForm1.LifeImageMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var i,j:Integer;
begin
MouseButtonDown:=false;
end;
procedure TForm1.LifeImageMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var i,j:integer;
begin
for i:=0 to MaxMatrixSize do
for j:=0 to MaxMatrixSize do
CellChangedOnMouseDown[i,j]:=False;
MouseButtonDown:=True;
CurrMouseButton:=Button;
if(x>0)and(y>0)and(CellSize>0)
then
begin
i:=trunc(x / CellSize);
j:=trunc(y / CellSize);
if(not CellChangedOnMouseDown[i,j])and(MouseButtonDown) then
begin
if(CurrMouseButton=mbLeft)then
begin
SetCell(i,j,1);
end else
if(CurrMouseButton=mbRight)then
begin
SetCell(i,j,0);
end else
if(CurrMouseButton=mbMiddle)then
begin
XorCell(i,j);
end;
CellChangedOnMouseDown[i,j]:=True;
draw;
end;
end;
end;
procedure TForm1.LifeImageMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var i,j:Integer;
begin
if(x>0)and(y>0)and(CellSize>0)
then
begin
i:=Trunc(x / CellSize);
j:=trunc(y / CellSize);
if(not CellChangedOnMouseDown[i,j])and(MouseButtonDown) then
begin
if(CurrMouseButton=mbLeft)then
begin
SetCell(i,j,1);
end else
if(CurrMouseButton=mbRight)then
begin
SetCell(i,j,0);
end else
if(CurrMouseButton=mbMiddle)then
begin
XorCell(i,j);
end;
CellChangedOnMouseDown[i,j]:=True;
draw;
end;
end;
end;
procedure TForm1.ClearFieldButtonClick(Sender: TObject);
begin
ClearField;
draw;
end;
procedure TForm1.StartButtonClick(Sender: TObject);
begin
gametimer.Enabled:=True;
end;
procedure TForm1.StepButtonClick(Sender: TObject);
begin
DrawWithStep;
end;
procedure TForm1.ResizeButtonClick(Sender: TObject);
begin
FieldWipe;
FieldResize(CellSizeTrackBar.Position);
SetBorders(BordersType);
draw;
end;
procedure TForm1.CellSizeTrackBarChange(Sender: TObject);
begin
ResizeButton.Caption:='Resize to '+inttostr(CellSizeTrackBar.Position+2);
end;
procedure TForm1.HelpButtonClick(Sender: TObject);
begin
if(not form2.visible)then
begin
Form2.Width:=300;
Form2.Height:=700;
end;
form2.visible:=not form2.visible;
end;
procedure TForm1.LoadButtonClick(Sender: TObject);
begin
gametimer.Enabled:=false;
if OpenGLF.Execute then
begin
fieldload(openglf.FileName);
end;
end;
procedure FieldLoad(FileName: TFileName);
var lfile:Text;
i,j,t:Integer;
begin
FieldWipe;
AssignFile(lfile,FileName);
Reset(lfile);
read(lfile,xmax);
read(lfile,ymax);
read(lfile,t);
FieldIsTorus:=t=1;
read(lfile,t);
BordersAreDead:=t=1;
if(fieldistorus)then
Form1.TorusBordersButton.Checked:=True
else
if(BordersAreDead)then
Form1.DeadBorderButton.Checked:=true
else
Form1.AliveBorderButton.Checked:=True;
read(lfile,borderstype);
SetBorders(borderstype);
for i:=0 to xmax+1 do
for j:=0 to ymax+1 do
read(lfile,cellstate[i,j]);
for i:=0 to xmax+1 do
for j:=0 to ymax+1 do
read(lfile,celltype[i,j]);
for i:=0 to xmax+1 do
for j:=0 to ymax+1 do
read(lfile,cellage[i,j]);
closefile(lfile);
draw;
end;
procedure FieldSave(FileName: TFileName);
var sfile:Text;
i,j:Integer;
begin
i:=Length(FileName);
AssignFile(sfile,FileName);
Rewrite(sfile);
Writeln(sfile,xmax,' ',ymax);
if(FieldIsTorus)then
Writeln(sfile,'1')
else
Writeln(sfile,'0');
if(BordersAreDead)then
Writeln(sfile,'1')
else
Writeln(sfile,'0');
Writeln(sfile,borderstype);
for i:=0 to xmax+1 do
begin
writeln(sfile,'');
for j:=0 to ymax+1 do
Write(sfile,cellstate[i,j],' ')
end;
for i:=0 to xmax+1 do
begin
writeln(sfile,'');
for j:=0 to ymax+1 do
Write(sfile,celltype[i,j],' ')
end;
for i:=0 to xmax+1 do
begin
writeln(sfile,'');
for j:=0 to ymax+1 do
Write(sfile,cellage[i,j],' ')
end;
closefile(sfile);
end;
procedure TForm1.SaveButtonClick(Sender: TObject);
begin
gametimer.Enabled:=false;
if saveGLF.Execute then
begin
FieldSave(saveglf.FileName);
end;
end;
end.
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;
type
TForm2 = class(TForm)
HelpRichEdit: TRichEdit;
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.FormActivate(Sender: TObject);
begin
HelpRichEdit.Lines.LoadFromFile('help.rtf');
end;
end.