{ -- Dreadnaut's Life 0.1 "textmode" --
l'ennesima implementazione del solito vecchio gioco :-)
Comandi:
<Spazio> - avvia e ferma l'animazione continua
<K>ill - svuota il mondo e ferma l'animazione
<P>asso - esegue un singolo passo di animazione
<R>andom - aggiunge organismi al mondo
<Q>uit - esce dal programma
Ad animazione ferma, con il mouse e' possibile aggiungere
o togliere organismi dal mondo
}
uses crt, fmouse;
{ --[ gestione diretta della memoria video ]-------- }
type
CrtCell = record Ch,At: byte; end;
CrtMap = array [1..50,1..80] of CrtCell;
const
Text50 : word = 259;
var
CrtMem : CrtMap absolute $B800:$0000;
{ -------------------------------------------------- }
const
{ costanti per i vari stati di ogni cella. Sono usati anche per riconoscere
lo stato `vitale' quindi _devono_ essere diversi fra loro }
ALIVE = 15; { vivo }
DYING = 7; { morto al prossimo passo }
BORN = 10; { vivo al prossimo passo }
EMPTY = 2; { cella vuota / morto }
{ numero di organismi da generare all'avvio e a ogni nascita casuale }
RB_NUM = 500;
{ costanti per le posizioni relative dei vicini }
vicini : array[0..7] of record x,y: shortint; end =
( (x:-1; y: 1), (x: 0; y: 1), (x: 1; y: 1),
(x:-1; y: 0), (x: 1; y: 0),
(x:-1; y:-1), (x: 0; y:-1), (x: 1; y:-1) );
{ data una cella restituisce il numero di celle vicine occupate }
function ContaVicini(y,x: byte): byte;
var
n,num : byte;
begin
num := 0;
for n := 0 to 7 do
{ il mod serve per uscire da un lato ed entrare dall'altro come se il
`mondo' fosse la superficie di una ciambella }
if (CrtMem[ 1+ (y+49 + vicini[n].y) mod 50 ,
1+ (x+79 + vicini[n].x) mod 80 ].At = ALIVE) or
(CrtMem[ 1+ (y+49 + vicini[n].y) mod 50 ,
1+ (x+79 + vicini[n].x) mod 80 ].At = DYING) then inc(num);
ContaVicini := num;
end;
{ esegue un passo di calcolo }
procedure PassoLife;
var
x,y: byte;
begin
HideMouse;
for y := 1 to 50 do
for x := 1 to 80 do
begin
case ContaVicini(y,x) of
{ meno di due vicini - morte per solitudine }
0,1,
{ piu' di tre vicini - morte per sovraffollamento }
4,5,6,7,8: if CrtMem[y,x].At = ALIVE then CrtMem[y,x].At := DYING;
{ menage a trois - nascita }
3 : if CrtMem[y,x].At = EMPTY then CrtMem[y,x].At := BORN;
{ due vicini - stabile, non faccio niente }
end;
end;
{ sopprimo i morenti e confermo i nuovi nati }
for y := 1 to 50 do
for x := 1 to 80 do
if CrtMem[y,x].At = DYING then CrtMem[y,x].At := EMPTY
else if CrtMem[y,x].At = BORN then CrtMem[y,x].At := ALIVE;
ShowMouse;
end;
var
m,n,b : integer;
{ strage di massa - svuota il mondo }
procedure MassKill;
begin
HideMouse;
for n := 1 to 50 do
for m := 1 to 80 do
begin
CrtMem[n,m].Ch := ord('Û');
CrtMem[n,m].At := EMPTY; {}
end;
ShowMouse;
end;
{ nascita casuale - aggiunge RB_NUM celle vive }
procedure RandomBirth;
begin
HideMouse;
for b := 1 to RB_NUM do
CrtMem[1+random(50), 1+random(80)].At := ALIVE;
ShowMouse;
end;
var
c : char;
running: boolean;
oldmode: integer;
begin
{ modalita' testo, 80x50 caratteri. Teniamo da parte quella originale }
oldmode := LastMode;
TextMode(Text50);
{ inizializza il mondo }
MassKill;
RandomBirth;
{ inizializza la gestione del mouse }
InitEvents;
repeat
if keypressed then c := readkey;
if (c <> #0) and (c <> 'q') then
begin
case c of
{ <Spazio> - avvia e ferma l'animazione continua }
' ': begin
running := not running;
if running then HideMouse else ShowMouse;
end;
{ <k> - svuota il mondo e ferma l'animazione }
'k': begin
MassKill;
running := false;
ShowMouse;
end;
{ <p> - esegue un singolo passo di animazione }
'p': begin
if not running then HideMouse
else running := false;
PassoLife;
ShowMouse;
end;
{ <r> - aggiunge RB_NUM organismi al mondo }
'r': RandomBirth;
end;
c := #0;
end;
{ ritorna le informazioni sulla pressione del mouse }
MousePressed(m,n,b);
{ alla pressione di un qualsiasi tasto del mouse si ferma l'animazione
e si passa alla modalita' di modifica del mondo - clickando si riempie
o svuota una cella }
if b <> 0 then
begin
if not running then
begin
HideMouse;
if CrtMem[1+n shr 3,1+m shr 3].At = ALIVE
then CrtMem[1+n shr 3,1+m shr 3].At := EMPTY
else CrtMem[1+n shr 3,1+m shr 3].At := ALIVE;
end;
running := false;
ShowMouse;
end;
{ se e' attiva l'animazione continua esegue un passo }
if running then PassoLife;
{ <q> - esce dal programma }
until c = 'q';
{ ritorna alla modalita' testo precedente }
TextMode(oldmode);
end.