WaTor ist eine einfache Computersimulation des
Jäger und Beute Modells.
Der Planet WaTor hat die Form eines Torusses und ist völlig von
Wasser bedeckt. Im Wasser leben Haie, Fische und Pflanzen.
Fische ernähren sich von Pflanzen und Haie fressen Fische.
Wenn ein Fisch eine gewqisse Zeit überlebt und genug Raum in seiner
Umgebung vorhanden ist, entsteht ein neuer Fisch. Haie
vermehren sich auf die selbe Art wie die Fische.
Wenn ein Hai keine Fische findet, dann stirbt er. Es
entstehen zyklische Änerungen der Populationen von
Jäger und Beute. Diese Änderungen werden durch die
Lotka-Volterra-Gleichung beschrieben.
program wator (input,output); uses CRT, GRAPH, GRAPHIC1;
const MININD = 1; { Feldgroesse }
MAXIND = 118; { Feldgroesse }
ZOOM = 4; { Vergroesserungsfaktor }
MAXGENE = 4; { Anzahl Gene }
WASSERFARBE = Black; { Hintergrundfarbe }
PFFARBE = lightblue; { Pflanzenfarbe }
MAXPFALTER = 400; { Max. Pflanzenalter }
PFGESCHLREIFE = 298; { Pflanzenvermehrungsalter }
ANZPF = 150; { Anzahl Pflanzen beim Start }
FIFARBE = lightgreen; { Fischfarbe }
MAXFIALTER = 160; { Max Fischalter }
FIGESCHLREIFE = 115; { Fischvermehrungsalter }
FIVERMENERGIE = 200; { Zum Vermehren notwendige Energie }
MAXFIENERGIE = 900; { Max. Energievorrat }
ANZFI = 170; { Amzahl Fische beim Start }
FIFRESSENERGIE = 100;
HAIFARBE = white; { Haifarbe }
MAXHAIALTER = 450; { Max Haialter }
HAIGESCHLREIFE = 100; { Haivermehrungsalter }
HAIVERMENERGIE = 70; { Zum Vermehren notwendige Energie }
MAXHAIENERGIE = 2000; { Max. Energievorrat }
ANZHAI = 4; { Amzahl Haie beim Start }
HAIFRESSENERGIE= 230;
type tGen = array [0..1] of integer;
tGene = array [1..MAXGENE] of tGen;
tLebenArt = (Pflanze,Fisch,Hai);
tLebenRef = ^tLeben;
tLeben = record
x, y : integer;
Next : tLebenRef;
case Art : tLebenArt of
Pflanze: ( PfAlter : integer);
Fisch : ( FiAlter,
FiEnergie,
fiGenIndex : integer;
FiGen : tGene);
Hai : ( HaiAlter,
HaiEnergie,
HaiGenIndex : integer;
HaiGen : tGene)
end;
tMeer = array [MININD..MAXIND,MININD..MAXIND]
of tLebenRef;
var Ozean : tMeer;
Leben,
FreiListe : tLebenRef;
n : integer;
procedure melde(Botschaft : string);
begin
if Botschaft <> '' then
begin
setfillstyle(1,red);
bar(0,400,130,410);
textcolor(white);
outTextXY(2,402,Botschaft)
end;
if keypressed then halt
end;
function ZufallsInd : integer;
var z : integer;
begin
ZufallsInd:= MININD+random(MAXIND-succ(MININD))
end;
function ZufallsDelta : integer;
var z : integer;
begin
z:= random(3);
ZufallsDelta:= z-1
end; { ZufallsDelta }
function normal(k : integer) : integer;
begin
if k < MININD then
normal:= MAXIND
else if k > MAXIND then
normal:= MININD
else
normal:= k
end; { normal }
function leer(x,y : integer) : boolean;
begin
leer:= Ozean[x,y] = NIL
end; { leer }
function istPflanze(x,y : integer) : boolean;
begin
if not leer(x,y) then
istPflanze:= Ozean[x,y]^.Art = Pflanze
else
istPflanze:= FALSE
end; { istPflanze }
function istFisch(x,y : integer) : boolean;
begin
if not leer(x,y) then
istFisch:= Ozean[x,y]^.Art = Fisch
else
istFisch:= FALSE
end; { istFisch }
function istHai(x,y : integer) : boolean;
begin
if not leer(x,y) then
istHai:= Ozean[x,y]^.Art = Hai
else
istHai:= FALSE
end; { istFisch }
function istAmEnde(p : tLebenRef) : boolean;
begin
with p^ do
begin
case Art of
Pflanze : istAmEnde:= (PfAlter >= MAXPFALTER);
Fisch : istAmEnde:= (FiAlter >= MAXFIALTER)
or (FiEnergie <= 0);
Hai : istAmEnde:= (HaiAlter >= MAXHAIALTER)
or (HaiEnergie <= 0)
end { case }
end { with }
end; { istAmEnde }
function hatPlatz(p : tLebenRef) : boolean;
{ TRUE, wenn mind. 1 Feld in der Nachbarschaft frei ist }
var dx, dy : integer;
geeignet : boolean;
begin
with p^ do
begin
geeignet:= FALSE;
dx:= -1;
repeat
dy:= -1;
repeat
case Art of
Pflanze : geeignet:= leer(normal(x+dx),normal(y+dy));
Fisch : if leer(normal(x+dx),normal(y+dy)) then
geeignet:= TRUE
else
geeignet:= istPflanze(normal(x+dx),
normal(y+dy));
Hai : if leer(normal(x+dx),normal(y+dy)) then
geeignet:= TRUE
else
geeignet:= istFisch(normal(x+dx),
normal(y+dy))
end; { case }
inc(dy);
until (dy > 1) or geeignet;
inc(dx)
until (dx > 1) or geeignet
end; { with }
hatPlatz:= geeignet
end; { HatPlatz }
procedure init;
var x,y, n : integer;
begin
randomize;
for x:= MININD to MAXIND do for y:= MININD to MAXIND do
Ozean[x,y]:= NIL;
Leben:= NIL;
FreiListe:= NIL;
gr_init; gr_on;
rectangle
(MININD*ZOOM,MININD*ZOOM,2+ZOOM+MAXIND*ZOOM,2+ZOOM+MAXIND*ZOOM);
end; { init }
function Plazieren(inArt : tLebenArt; xk,yk : integer) :
tLebenRef;
var Neu : tLebenRef;
n : integer;
begin
if FreiListe = NIL then new(Neu)
else
begin
Neu:= FreiListe;
FreiListe:= FreiListe^.Next
end;
with Neu^ do
begin
Art:= inArt;
x:= xk;
y:= yk;
case Art of
Pflanze : PfAlter:= 0;
Fisch : begin
FiAlter:= 0;
FiEnergie:= MAXFIENERGIE;
for n:= 1 to MAXGENE do
begin
FiGen[n,0]:= ZufallsDelta;
FiGen[n,1]:= ZufallsDelta
end;
FiGenIndex:= 1
end;
Hai : begin
HaiAlter:= 0;
HaiEnergie:= MAXHAIENERGIE;
for n:= 1 to MAXGENE do
begin
HaiGen[n,0]:= ZufallsDelta;
HaiGen[n,1]:= ZufallsDelta
end;
HaiGenIndex:= 1
end
end { case }
end; { with }
Plazieren:= Neu
end; { Plazieren }
function Zufall(inArt : tLebenArt) : tLebenRef;
var Neu : tLebenRef;
n : integer;
begin
if FreiListe = NIL then new(Neu)
else
begin
Neu:= FreiListe;
FreiListe:= FreiListe^.Next
end;
Neu^.Art:= inArt;
case Neu^.Art of
Pflanze : with Neu^ do begin
repeat
x:= ZufallsInd;
y:= ZufallsInd;
until leer(x,y);
PfAlter:= random(MAXPFALTER)
end;
Fisch : begin
repeat
with Neu^ do
begin
x:= ZufallsInd;
y:= ZufallsInd
end;
until hatPlatz(Neu);
with Neu^ do
begin
FiAlter:= random(MAXFIALTER);
FiEnergie:= random(MAXFIENERGIE);
for n:= 1 to MAXGENE do
begin
FiGen[n,0]:= ZufallsDelta;
FiGen[n,1]:= ZufallsDelta
end;
FiGenIndex:= 1;
end
end;
Hai : begin
repeat
with Neu^ do
begin
x:= ZufallsInd;
y:= ZufallsInd
end;
until hatPlatz(Neu);
with Neu^ do
begin
HaiAlter:= random(MAXHAIALTER);
HaiEnergie:= random(MAXHAIENERGIE);
for n:= 1 to MAXGENE do
begin
HaiGen[n,0]:= ZufallsDelta;
HaiGen[n,1]:= ZufallsDelta
end;
HaiGenIndex:= 1;
end
end
end; { case }
Zufall:= Neu
end; { Zufall }
function Nachkomme(var Mutter : tLebenRef) : tLebenRef;
var Kind : tLebenRef;
Mut1, Mut2 : integer;
MutGen : tGen;
begin
if FreiListe = NIL then new(Kind)
else
begin
Kind:= FreiListe;
FreiListe:= FreiListe^.Next
end;
with Kind^ do
begin
x:= Mutter^.x;
y:= Mutter^.y;
Art:= Mutter^.Art;
repeat
x:= normal(x+ZufallsDelta);
y:= normal(y+ZufallsDelta)
until leer(x,y);
case Art of
Pflanze : PfAlter:= 0;
Fisch : begin
FiAlter:= 0;
FiEnergie:= Mutter^.FiEnergie div 2;
FiGen:= Mutter^.FiGen;
if random(100) > 98 then
begin
Mut1:= random(MAXGENE)+1;
Mut2:= random(MAXGENE)+1;
MutGen:= FiGen[Mut1];
FiGen[Mut1]:= FiGen[Mut2];
FiGen[Mut2]:= MutGen;
end;
FiGenIndex:= 1;
Mutter^.FiEnergie:= Mutter^.FiEnergie div 2
end;
Hai : begin
HaiAlter:= 0;
HaiEnergie:= Mutter^.HaiEnergie div 2;
HaiGen:= Mutter^.HaiGen;
if random(100) > 98 then
begin
Mut1:= random(MAXGENE)+1;
Mut2:= random(MAXGENE)+1;
MutGen:= HaiGen[Mut1];
HaiGen[Mut1]:= HaiGen[Mut2];
HaiGen[Mut2]:= MutGen;
end;
HaiGenIndex:= 1;
Mutter^.HaiEnergie:= Mutter^.HaiEnergie div 2
end
end; { case }
end; { with }
Nachkomme:= Kind
end; { Nachkomme }
procedure Zeichnen(inP : tLebenRef; Modus : integer);
const ZOOM2 = pred(pred(ZOOM));
var zx,zy : integer;
Farbe : integer;
begin
with inP^ do
begin
zx:= succ(succ(x*ZOOM));
zy:= succ(succ(y*ZOOM));
if Modus = 0 then
begin
setcolor(WASSERFARBE);
setFillStyle(1,WASSERFARBE);
end
else
begin
case Art of
Pflanze : Farbe:= PFFARBE;
Fisch : Farbe:= FIFARBE;
Hai : Farbe:= HAIFARBE;
end; { case }
setColor(Farbe);
setFillStyle(1,Farbe);
end;
bar (zx,zy,zx+ZOOM2,zy+ZOOM2);
end; { with }
end; { PflanzePositionieren }
procedure Erzeugen(ioLeben : tLebenRef);
begin
ioLeben^.next:= Leben;
Leben:= ioLeben;
Ozean[ioLeben^.x,ioLeben^.y]:=ioLeben;
Zeichnen(ioLeben,1);
end; {Erzeugen }
procedure Loeschen(var zuLoeschen : tLebenRef);
var hilf : tLebenRef;
begin
if zuLoeschen = Leben then { erstes Element in Liste }
begin
if Leben^.next = NIL then { einziges Element in Liste }
Leben:= NIL
else { es gibt Nachfolger }
Leben:= Leben^.next;
end
else { nicht erstes Element in Liste }
begin
hilf:= Leben;
while Hilf^.next <> zuLoeschen do
hilf:= hilf^.next;
{ jetzt zeigt hilf auf Vorgaenger von zuLoeschen }
hilf^.next:= zuLoeschen^.next;
end;
Zeichnen(zuLoeschen,0);
Ozean[zuLoeschen^.x,zuLoeschen^.y]:= NIL;
zuLoeschen^.Next:= FreiListe;
FreiListe:= zuLoeschen;
zuLoeschen:= NIL
end; { LebenLoeschen }
procedure Zug;
var p,q : tLebenRef;
xNeu, yNeu : integer;
procedure sterben;
begin
q:= p;
p:= p^.next;
Loeschen(q)
end; { stirbt }
procedure PflanzeZug;
begin
if hatPlatz(p) then
if p^.PfAlter >= PFGESCHLREIFE then
Erzeugen(Nachkomme(p));
inc(p^.PfAlter);
p:= p^.next
end; { PflanzeZug }
procedure FischZug;
procedure schwimme;
begin
Ozean[xNeu,yNeu]:= p;
Ozean[p^.x,p^.y]:= NIL;
zeichnen(p,0);
with p^ do
begin
x:= xNeu; y:= yNeu
end; { with }
zeichnen(p,1);
end; { schwimme }
procedure schwimmeUndFriss;
begin
Ozean[p^.x,p^.y]:= NIL;
q:= p;
p:= Ozean[xNeu,yNeu];
with p^ do
begin
Art:= Fisch;
FiEnergie:= q^.FiEnergie+FIFRESSENERGIE;
if FiEnergie > MAXFIENERGIE then
FiEnergie:= MAXFIENERGIE;
FiAlter:= q^.FiAlter;
FiGen:= q^.FiGen;
FiGenIndex:= q^.FiGenIndex
end; { with }
zeichnen(p,1);
loeschen(q);
end; { schwimmeUndFriss }
begin { FischZug }
if hatPlatz(p) then
begin
if p^.FiAlter >= FIGESCHLREIFE then
Erzeugen(Nachkomme(p))
else { schwimmen }
begin
{ suche Ziel }
with p^ do
begin
xNeu:= normal(x+FiGen[FiGenIndex,0]);
yNeu:= normal(y+FiGen[FiGenIndex,1]);
inc(FiGenIndex);
if FiGenIndex > MAXGENE then FiGenIndex:= 1
end; { with }
if leer(xNeu,yNeu) then schwimme
else if istPflanze(xNeu,yNeu) then schwimmeUndFriss
end; { else schwimmen }
end; { if hatPlatz }
with p^ do
begin
inc(FiAlter);
dec(FiEnergie)
end; { with }
p:= p^.next
end; {Fischzug }
procedure HaiZug;
procedure schwimme;
begin
Ozean[xNeu,yNeu]:= p;
Ozean[p^.x,p^.y]:= NIL;
zeichnen(p,0);
with p^ do
begin
x:= xNeu; y:= yNeu
end; { with }
zeichnen(p,1);
end; { schwimme }
procedure schwimmeUndFriss;
begin
Ozean[p^.x,p^.y]:= NIL;
q:= p;
p:= Ozean[xNeu,yNeu];
with p^ do
begin
Art:= Hai;
HaiEnergie:= q^.HaiEnergie+HAIFRESSENERGIE;
if HaiEnergie > MAXHAIENERGIE then HaiEnergie:=
MAXHAIENERGIE;
HaiAlter:= q^.HaiAlter;
HaiGen:= q^.HaiGen;
HaiGenIndex:= q^.HaiGenIndex
end; { with }
zeichnen(p,1);
loeschen(q);
end; { schwimmeUndFriss }
begin { HaiZug }
if hatPlatz(p) then
begin
if p^.HaiAlter >= HaiGESCHLREIFE then
Erzeugen(Nachkomme(p))
else { schwimmen }
begin
{ suche Ziel }
with p^ do
begin
xNeu:= normal(x+HaiGen[HaiGenIndex,0]);
yNeu:= normal(y+HaiGen[HaiGenIndex,1]);
inc(HaiGenIndex);
if HaiGenIndex > MAXGENE then HaiGenIndex:= 1
end; { with }
if leer(xNeu,yNeu) then schwimme
else if istFisch(xNeu,yNeu) then schwimmeUndFriss
end; { else schwimmen }
end; { if hatPlatz }
with p^ do
begin
inc(HaiAlter);
dec(HaiEnergie)
end; { with }
p:= p^.next
end; {Haizug }
begin { Zug }
p:= Leben;
while p <> NIL do
begin
if istAmEnde(p) then sterben
else
begin
case p^.Art of
Pflanze : PflanzeZug;
Fisch : FischZug;
Hai : HaiZug
end { case }
end { else }
end { while }
end; { Zug }
begin { P R O G R A M }
init;
for n:= 1 to ANZPF do Erzeugen(Zufall(Pflanze));
for n:= 1 to ANZFI do Erzeugen(Zufall(Fisch));
for n:= 1 to ANZHAI do Erzeugen(Zufall(Hai));
while not (Leben = NIL) and not keypressed do
begin
Zug;
if random(100) > 75 then Erzeugen(Zufall(Pflanze))
end;
melde('FERTIG')
end.