Trò chơi đời sống
Trần Thông Quế và Trần Văn Lộ
Các kiểu dữ liệu trừu tượng có nhiều ứng dụng trong thực tế đó là Bảng (TABLE).
Một trong các ứng dụng của bảng là Trò chơi đời sống (GAME LIFE). Đó là bài toán
được nhà toán học Anh J.H Conway nêu ra vào năm 1970.
Trước hết ta hãy làm quen với các khái niệm cơ bản của bài toán GAME LIFE.
Về mặt toán học, ta coi đời sống của một quần thể sống diễn ra trên một bảng vuông (lưới
ô vuông) không giới hạn.
Mỗi ô vuông có thể tồn tại cơ thể sống hoặc không.
Ô vuông có một cơ thể sống gọi là tế bào sống, ngược lại gọi là tế bào chết.
Các tế bào thay đổi từ thế hệ này sang thế hệ sau tuỳ thuộc vào các tế bào sống ở lân cận.
Mỗi tế bào có tám tế bào lân cận tiếp giáp với tế bào đã cho theo các cạnh và góc.
Các tế bào thay đổi theo những quy luật sau:
- Nếu số tế bào sống lân cận với tế bào cho trước mà không nhiều hơn 1 thì đến thế hệ sau
nó sẽ chết (chết vì cô độc).
- Nếu số tế bào sống lân cận với tế bào cho trước mà là 2 hoặc 3 thì tới thế hệ sau tế bào
cho trước ấy vẫn sống.
- Nếu số tế bào sống lân cận với tế bào cho trước mà nhiều từ 4 trở lên thì đến thế hệ sau
nó sẽ chết (chết vì quá đông).
- Nếu có đúng 3 tế bào sống lân cận với một tế bào chết thì ở thế hệ sau nó sẽ trở thành tế
bào sống. Trong trường hợp còn lại, một tế bào chết thì vẫn còn chết ở thế hệ sau.
- Trong mỗi thế hệ, sự sinh ra và chết đi diễn ra đồng thời và không ảnh hưởng tới nhau.
Dưới đây là các ví dụ minh hoạ (ký tự x biểu thị tế bào sống):
Để lập trình mô tả GAME LIFE ta có thể cài đặt các thế hệ của một cộng đồng nhờ một
mảng hai chiều khá lớn (dùng PASCAL FREE). Ta quy ước 1 biểu diễn tế bào sống, 0 biểu
diễn tế bào chết.
Để xác định được sự thay đổi của các tế bào từ thế hệ này sang thế hệ khác, ta chỉ cần đếm
số tế bào sống lân cận với tế bào đang xét và áp dụng các luật từ 1 đến 4 nêu trên.
Trong chương trình dưới đây, chúng tôi biểu diễn tế bào sống bằng những ô tô màu đỏ, còn
các tế bào chết là các ô trống (có màu nền).
Chương trình này cũng tạo hai phương thức nhập liệu: một là nhập liệu từ bàn phím, hai là
máy tính tự phát sinh ngẫu nhiên các quần thể các tế bào.
Program Tro_Choi_Doi_Song;
Uses crt,graph;
Type table=array[0..49,0..48] of boolean;
Var t,newt:table;c:char;
{========================}
Procedure Initgr;
Var gd,gm:integer;
Begin
gd:=detect;
initgraph(gd,gm,'C:BpBgí);
if graphresult<>grok
then
begin
write('Loi Do Hoa ! Go Enter Ket Thuc');
readln;
halt(1)
end
End;
{========================}
Procedure Input_Table;
Var i,j,n:integer;
Begin
textbackground(blue);clrscr;
textcolor(white);
for i:=0 to 49 do
for j:=0 to 48 do t[i,j]:=false;
writeln(' Ban Tu Nhap Du Lieu Hay De May Tinh Tu Tao(1/0)?');
Write(' (1 la tu nhap, 0 la may tinh tu tao du lieu):');
readln(i);
if i=1 then
begin
n:=1;
writeln(' Nhap Toa Do Cac Te Bao Song Cua Cong Dong (hang cot),');
writeln(' Dieu Kien : 1<=hang<=47, 1<=cot<=48), Ket Thuc Go : 0 0');
repeat
repeat
write(' Toa Do Te Bao Song Thu ',n,' : ');
readln(i,j)
until (0<=i) and (49>i) and (0<=j) and (48>j);
if (i>0) and (j>0) then
begin
t[i,j]:=true;inc(n)
end;
until (i=0) and
(j=0);
end
else
begin
n:=100+random(500);
for i:=1 to n do
t[1+random(48),1+random(47)]:=true
end;
End;
{========================}
Function Number(i,j:integer):integer;
Var n,k:integer;
Begin
n:=0;
for k:=i-1 to i+1 do
begin
if t[k,j-1] then inc(n);
if t[k,j+1] then inc(n)
end;
if t[i-1,j] then inc(n);
if t[i+1,j] then inc(n);
Number:=n
End;
{========================}
Procedure New_Table;
Var i,j:integer;
Begin
for i:=1 to 48 do
for j:=1 to 47 do
case number(i,j) of
0,1:newt[i,j]:=false;
2 :newt[i,j]:=t[i,j];
3 :newt[i,j]:=true
else
newt[i,j]:=false;
end;
for i:=1 to 48 do
for j:=1 to 47 do t[i,j]:=newt[i,j];
End;
{========================}
Procedure Draw_T;
var i:integer;
Begin
setcolor(lightgray);
Setbkcolor(blue);
rectangle(0,0,480,470);
for i:=1 to 47 do
line(i*10,1,i*10,469);
for i:=1 to 46 do
line(1,i*10,479,i*10);
settextstyle(0,0,2);
setcolor(red);
outtextxy(485,30,'Life Gamé);
settextstyle(0,0,1);
setcolor(white);
outtextxy(485,90,'Hit Anykey to Go on');
outtextxy(495,150,'Enter to Restart');
outtextxy(510,210,'Esc to Stop');
End;
{========================}
Procedure Draw_cell(i,j:integer);
Begin
if t[i,j] then
begin
setfillstyle(1,red);
bar((i-1)*10+1,(j-1)*10+1,i*10-1,j*10-1);
end
else
begin
setfillstyle(1,blue);
bar((i-1)*10+1,(j-1)*10+1,i*10-1,j*10-1);
end;
End;
{========================}
Procedure Draw_Table;
Var i,j:integer;
Begin
for i:=1 to 48 do
for j:=1 to 47 do
Draw_Cell(i,j);
End;
{========================}
Procedure Life_Table;
Begin
while keypressed do
c:=readkey;
repeat
Draw_Table;
New_Table;
c:=readkey;
until (c=#27) or
(c=#13);
End;
{========================}
BEGIN
Randomize;
Initgr;
Repeat
Restorecrtmode;
Input_Table;
Setgraphmode(getgraphmode);
Draw_T;
Life_Table;
Until c=#27;
Closegraph;
END.