Tento tutoriál by měl začátečníka naučit vytvářet organismy v The Life!. Předpokládá se, že čtenář umí základy Pascalu a Delphi, nepožadují se žádné další speciální programátorské znalosti. Tutoriál doporučuji procházet krok za krokem a opravdu dělat to, co se v něm říká — je to nejlepší metoda, jak se naučit organismy efektivně vytvářet.
V zájmu srozumitelnosti výkladu jsou místy některé věci zjednodušeny; pokud chcete znát přesnější technický popis, podívejte se do Referenční příručky k unitě OrgInterface.
Organismus je ve The Life! chápán jako objekt, existující v nějakém
prostředí, který má (mimo jiné) kontrolní proceduru, která
je spuštěna vždy jedou během každého kroku simulace. V kontrolní proceduře
je popsáno, co má organismus během jednoho kroku simulace dělat. Procedura
je uložena v knihovně DLL, která je umístěna v podadresáři
Org. Pokud je The Life! např. nainstalován v adresáři
C:\Program Files\The Life!, pak budou knihovny organismů
nainstalovány v adresáři C:\Program Files\The Life!\Org. Jméno
souboru knihovny DLL určuje jméno druhu organismu. Pokud se organismus
jmenuje např. NovyOrg, pak jeho knihovna bude mít název
NovyOrg.dll.
Organismus lze technicky vzato vtvořit v libovolném programovacím jazyce, který umí kompilovat knihovny DLL. V tomto návodu se však budu zabývat jen tvorbou v Delphi (tím je myšleno Delphi 6.0, postupy by ale měly fungovat s drobnými obměnami ve všech 32-bitových verzích tohoto vývojového prostředí).
K vytvoření organismu musíte nejdříve založit nový projekt Delphi, který
musí být uložen v podadresáři Org. Nejjednodušším způsobem,
jak to udělat, je načtení předem připravené standardní šablony a její
uložení pod jiným jménem.
Default.dpr v podadresáři Org.Pokud dodržíte výše uvedený postup, zobrazí se vám v editoru následující úsek kódu:
library Default;
uses
OrgInterface;
procedure OrgRun(Organism: IVLFOrganism); stdcall;
begin
with Organism do
begin
{ Sem napište kód kontrolní procedury. }
end;
end;
exports
OrgRequiredVersion,
OrgRun;
end.
Pokud si ho dobře prohlédnete, zjistíte několik věcí:
OrgInterface. Tato unita
zajišťuje komunikaci mezi knihovnou a samotným programem
Life.exe. Jsou v ní deklarovány všechny potřebné konstanty,
datové typy a funkce/procedury potřebné pro běh kontrolní procedury.
Přesný popis všeho, co v ní je, najdete v Referenci.OrgRun. Ano, správně, jsme
u toho — toto je ona kontrolní procedura, nejdůležitější věc na celém
organismu.OrgRun
knihovna exportuje ještě proceduru
OrgRequiedVersion. To je
interní procedura deklarovaná v unitě OrgInterface. Slouží
ke zajištění kompatibility verzí Life.exe a organismu. Její
existencí se nemusíte nijak zatěžovat, pro vás jako by tam nebyla.Každý organismus žije v prostředí. To si lze představit jako čtvercovou síť s rozměry N×N čtverečků, kde N je číslo od 1 do 255. Na každém čtverečku je nějaké (zpočátku náhodné) množství potravy v rozsahu 0-255 a může (ale nemusí a zpočátku tam vůbec není) tam být i jedna z 255 chemikálií. Organismy se v tomto prostředí pohybují a "žijí".
Organismus má své vlastnosti a příkazy. Vlastnosti jsou něco jako proměnné a příkazy jsou procedury či funkce. Skutečná technická implementace tohoto mechanismu do The Life! je poněkud složitější, a proto to ponecháme takto trochu zjednodušené. Vlastnosti organismu nelze měnit přímo (tzn. přiřazením), ale jen nepřímo přes příkazy. Jsou tedy "read-only". Seznam všech vlastností a příkazů najdete v referenci. Nyní už se vrhněme do psaní kontrolní procedury.
Zkusíme nejprve vytvořit jednoduchý organismus. Tento organismus nebude
dělat nic jiného, než že bude jíst, pokud bude jeho hmotnost menší než 5
jednotek. Příkaz na jedení se jmenuje Eat a jako parametr se
zadává počet jednotek potravy, které má organismus sníst, tj. přemístit z
venkovního prostředí do své trávicí vakuoly. V té může být maximálně 255
jednotek potravy. V programu budeme též potřebovat zjistit hmotnost
organismu, k čemuž je určena vlastnost Mass. Maximální
hmotnost organismu je 255 jednotek. Organismus má také energii
(Energy). Té může být také maximálně 255 jednotek (jak časem
zjistíte, 255 je v The Life! dost důležité číslo). Obě hodnoty má
organismus ve chvíli svého vzniku nastaveny na hodnotu 0. Ale začněme už s
programem:
OrgRun.if Mass < 5 then Eat(1);
Ale ouha, zdánlivě se skoro nic nestalo. Ať budete klikat sebevíc,
organismus v nejbližším kroku simulace zmizí. Důvod je prostý. Organismus
je sice najedený (příkaz Eat), ale potravu nemá organismus
přeměněnou na energii a také nemá žádnou hmotnost. Obojí je důvodem, proč
hned po prvním kroku simulace zahyne. Tuto chybu musíme napravit.
OrgRun a přepište kód na následující:if Mass < 5 then begin Eat(1); Build(1) end; if Energy < 5 then begin Eat(1); Digest(1); end;
Organismus se opravdu umístí do prostředí, a trochu povyroste. Příkaz
Build totiž způsobí že se potrava, kterou má organismus ve
vakuole, se změní na tělesnou hmotu. Množství potravy předáváme příkazu
jako parametr. Obdobně funguje i příkaz Digest, akorát že
potravu "stráví" a tím přemění na energii.
Docela důležitá věc, o které jsem se zatím nezmínil, je, že při každém kroku simulace ubývá organismu jedna jednotka energie. je to proto, že jinak by se mohl jednou za život najíst a pak už jen stát na místě a nic nedělat. Ubývající energie nutí organismus se pohybovat za potravou.
Z předchozího odstavce vyplývá, že stání na místě organismu k užitku
příliš není. Organismus se potřebuje pohybovat, což zajišťuje příkaz
Move. Prvním parametrem je směr (Direction). Ten
se zadává jako první písmeno anglického názvu světové strany (N = north = sever, S = south = jih, E = east = východ, W = west = západ). Druhým parametrem
je počet políček, o které se organismus pohne. Maximální délku pohybu v
jednom kroku simulace můžete zjistit pomocí vlastnosti
MaxMoveDist. V současné verzi je to 5 políček. Za každé
políčko, o které se organismus pohne, se odečte jedna jednotka energie.
Postup bude tentokrát jednoduchý: Přidejte k existujícímu kódu následující sekci:
Eat(1); Digest(1); Move(E, 1);
Pokud organismus spustíte, uvidíte, jak se pomalu pohybuje směrem doprava.
Organismus by (ve svém vlastním zájmu) měl mít přehled o množství
potravy ve svém okolí. Od toho je tu funkce FoodAt. Jako
parametry si bere souřadnice políčka, vztažené relativně k organismu. Pokud
je např. organismus na souřadnicích [150, 80] a organismus zavolá funkci
FoodAt s parametry X = -1 a Y = 1,
je vrácena hodnota potravy na políčku se souřadnicemi [149, 81]. Obě
souřadnice musí mít hodnotu -1, 0 nebo 1, tj. musí to být políčko pod
organismem nebo v těsném okolí. Nejlépe to vyjádří obrázek:
Nyní poupravíme část kódu, kterou jsme do procedury přidali posledně. Tato část bude vypadat takto:
if FoodAt(1, 0) > FoodAt(0, 0) then begin Eat(1); Digest(1); Move(E, 1); end;
Organismus se tedy bude pohybovat vpravo jen tehdy, bude-li se na políčku vpravo od něj nacházet více potravy, než na políčku pod ním.
Organismus má možnost zjistit své souřadnice pomocí svých vlastností
X, Y. Taktéž si může zjistit, jak velké je
prostředí, v němž se pohybuje. Vlastnosti pro zjištění rozměrů se jmenují
MaxX a MaxY, a udávají nejvyšší možnou hodnotu
příslušných souřadnic. Nejnižší možná hodnota je udávána pomocí vlastností
MinX a MinY, které v současné verzi mají vždy
hodnotu 0. Nyní následuje příklad na toto téma. Je jím organismus, který se
přesune do pravého horního rohu. Před opsáním uvedeného kódu smažte všechen
kód z minulých příkladů, který je v proceduře OrgRun.
Eat(4); Digest(3); Build(1); if X < MaxX then Move(E, 1); if Y < MaxY then Move(S, 1);
Pokud organismus spustíte, nemůžete si nevšimnout, že kromě jiného nekontroluje svoji hmotnost, takže časem naroste do podoby slušného tlouštíka.
Organismus má jako jednu ze svých základních vlastností i barvu. Tu lze
zjistit vlastností Color, která vrací Delphácký typ
TColor, a nastavit ji lze příkazem SetColor.
Tento příkaz má 3 parametry: hodnotu červené, zelené a modré bary, které se
smíchají a dají dohromady výslednou barvu (je to tedy klasické RGB schéma).
Každá z těchto barev může nabývat hodnoty 0-255. Typické využití této
funkce je signalizace určitého stavu organismu. My si ukážeme postupný
přeliv z černé do červené, který bude závislý na x-ové souřadnici. K
předcházejícímu příkladu připojte následující řádek kódu:
SetColor(X, 0, 0);
Výsledek se dostaví po spuštění programu. Předpokládám, že při tvorbě vlastních organismů najdete i smysluplnější využití barev, než je signalizace polohy.
Další z věcí, které je možno o organismu zjišťovat, je jeho stáří. Je to
vlastně počet kroků simulace uběhlých od vzniku organismu. Vlastnost, která
ho udává se jmenuje Age. Při prvním běhu kontrolní procedury
je Age = 0, při dalším Age = 1 atd. Maximální
věk, kterého mohou organismy dosáhnout najdete ve vlastnosti
MaxAge. Pokud organismus dosáhne stáří MaxAge,
umírá. MaxAge je nyní nastaven na pevně danou hodnotu
MaxInt, tj. 2147483647. To je věk téměř neomezený, protože
např. při frekvenci 1 okénko za sekundu by organismus zahynul stářím za 68
let! V budoucích verzích The Life! ale může být všechno jinak a
MaxAge může být nastavitelná uživatelem.
Funkce Age se velmi často využívá při kontrole
rozmnožování. Jediná možná forma rozmnožování organismů v The Life!je
buněčné dělení, které se vyvolává funkcí DivCell. Obě buňky
mají poloviční hmotnost původní buňky (Mass), poloviční
množství potravy v trávicí vakuole (FoodIn) a poloviční
energii (Energy).
Příklad na tyto dvě funkce začneme tím, že smažeme příkazy v kontrolní proceduře. Pak napíšeme několik následujících řádků kódu, které způsobí náhodný pohyb organismu:
Eat(5); if Mass < 5 then Build(1); Digest(2); case Random(4) of 0: Move(N, 1); 1: Move(S, 1); 2: Move(W, 1); 3: Move(E, 1); end;
K tomu přidáme kód, který způsobí rozmnožení organismu, pokud je jeho věk 10.
if Age = 10 then DivCell;
Pokud program spustíte, velmi rychle zjistíte, že organismus se za chvíli přemnoží (Ať žije populační exploze!).
Přemnožení zabrání jednoduchý příkaz Die, který způsobí
úhyn organismu. Přidáme proto jeden řádek, který způsobí smrt organismu ve
věku 35:
if Age = 35 then Die;
Nyní se organismus bude udržovat v počtu 3-4 jedinců.
Občas je pro dobrou životosprávu organismu nutné vědět, kolik potravy se
nachází v jeho trávicí vakuole. Od toho je funkce FoodIn.
Potravy ve vakuole může klasicky být 0-255 jednotek.
Příkaz Spread je opakem příkazu Build, mění
totiž tělesnou hmotu zpět na potravu ve vakuole. Příkaz
Secrete je zas opčný příkaz k příkazu Eat - jak
jste již jistě uhodli, provádí cosi jako "zvracení", tedy vylučování
potravy z vakuoly ven do prostředí. Příklad na tyto dva příkazy si tady
uvádět nebudeme, protože jsou téměř nepoužívané a existují spíš kvůli
pocitu autora The Life!, že všechny operace by měly být vratné.
Nyní už znáte celkem dost příkazů na to, abyste mohli začít experimentovat se svými vlastními organismy. Takže, pokud chcete, přerušte teď četbu tohoto manuálu a věnujte se programování.
Přestávka na aktivní činnost vyvíjenou čtenářem...
Pokud jste se opravdu věnovali vlastním experimentům s The Life!, asi
jste velmi brzo zjistili, že je sice hezké, že organismy můžou jíst,
trávit, pohybovat se, měnit barvu či umírat, ale co je to platné, když
neumějí reagovat na sebe navzájem. A reakcí, která každého napadne jistě
jako první, je útok. Ten se realizuje příkazem Attack. Příkaz
zjistí, jestli se pod organismem (tj. na stejném políčku) nachází jiný
organismus, a pokud ano, tak zahájí boj. S trochou nepřesnosti se dá říct,
že vyhrává ten, jehož součet hmotnosti a energie je vyšší. Poražený zahyne.
Přesné podmínky výhry a prohry se dají nastavit přímo v The Life! (dialog
Nástroje|Možnosti...). Někdy je možné, že zahynou oba
organismy, protože i tomu vítěznému se snižuje hmotnost a energie, což může
znamenat i smrt.
Nyní můžete přidat na konec kódu řídící procedury přidat magické slůvko
Attack;
a organismus spustit. Organismy — perte se a žerte se!
Po spuštění velmi rychle zjistíte, že organismus je pěkný kanibal. On se
totiž pokusí zaútočit na svého potomka těsně po jeho zrodu. Ovšem protože
oba dva jsou stejně hmotní a mají stejně energie, oba dva pravděpodobně
zahynou. Takhle bychom to daleko nedopracovali. Nabízí se dvě řešení. Buď
příkaz Attack přesunout někam na začátek programu, ještě před
narození potomka, nebo použít funkce Species a
OrgAt. Funkce Species vrací název druhu organismu
jako řetězec. V našem případě to bude 'Organismus1'. Funkce
OrgAt je obdobná funkci FoodAt v tom, že si za
parametry bere souřadnice vztažené relativně k organismu, akorát že místo
potravy vrací řetězec s druhem organismu na daném políčku. V případě, že se
na políčku žádný organismus nenachází, vrací prázdný řetězec. Tak, a teď už
náležitě vybaveni znalostmi můžeme přepsat řádek s příkazem
Attack na následující:
if OrgAt(0, 0) <> Species then Attack;
Teto řádek útok podmíní tím, že kořist není stejného druhu, jako útočící organismus. Tím jsme efektivně vyřešili problém kanibalismu. Jakmile se ale našemu organismu připlete do cesty jiný organismus, bude na něj nemilosrdně zaútočeno.
Organismus má možnost si zjistit, kolikáté je generace. Dělá se pomocí
vlastnosti GenCount. Pokud přidáte do prostředí nový
organismus, bude mít GenCount = 0, jeho potomci
GenCount = 1, jejich potomci GenCount = 2
atd.
Dále je zde možnost, aby organismus vylučoval chemikálie. Od toho je tu
příkaz Exclude. Má dva parametry: poloměr kruhu, ve kterém má
chemikálii kolem sebe vyloučit, a druh chemikálie. Za každé "poskvrněné"
políčko se odebírá 1 jednotka energie. Pokud je jí nedostatek na pokrytí
kruhu o daném poloměru, poloměr se zmenší tak, aby množství energie bylo
dostačující. Chemikálií je celkem 254 (hodnoty 1-255), 0 se chápe tak, jako
by na políčku žádná chemikálie nebyla. Pro chemikálie existuje obdobná
mapa, jako pro potravu, a také obdobná funkce na zjišťování druhu
chemikálie na daném políčku. Ta se jmenuje ChemAt a její
princip je navlas stejný jako u FoodAt.
Tak a teď nějaký příklad na GenCount a
Exclude. Jelikož mě nic lepšího nenapadá, bude to organismus
zanechávající za sebou chemickou stopu, přičemž druh chemikálie bude
vyjadřovat číslo jeho generace. Samozřejmě nesmíme zapomenout na zajištění
přísunu potravy a energie na tuto činnost. Proto na konec kódu kontrolní
procedury přidejte toto:
Eat(10); Digest(10); Exclude(1, GenCount);
Organismus spusťte a uvidíte (pokud v The Life! zapnete vrstvu chemikálií — klávesa C), jak se kolem organismů tvoří políčka různých barev — to jsou ony chemikálie.
Další drobností je možnost získat nastavení simulace pomocí příkazu
GetOptions. Protože to běžně není potřeba, odkážu vás na její
popis v referenci.
Pokud začnete tvořit složitější organismy, přijdete brzy na to, že je
třeba je vybavit pamětí, aby si mezi jednotlivými okénky pamatovaly různé
veličiny. Tuto paměť představuje pole UR (odvozeno od
"uživatelský registr"). Pole má maximální rozsah 0-255 (jako obvykle) a
jeho prvky jsou typu Integer. Paměť je tedy určena k
zapamatování čísel (I když při troše programátorského umu se do ní dají
nacpat i pointery na různé struktury apod. Ale to není čisté, protože
organismus nemá vždy možnost případně alokovanou paměť uvolnit. To ale jen
tak na okraj.). Hodnoty prvků se nastavují příkazem SetUR.,
kde jako první parametr zadáváme index prvku pole (tj. do kterého z 256ti
hodnotu zapsat) a druhý parametr (typu Integer) je hodnota
onoho prvku, kterou mu chceme přiřadit. Zvláštností pole UR je
to, že se při přístupu k němu používají kulaté závorky ("()")místo
hranatých ("[]"), protože technicky vzato je to vlastně funkce.
Někdy na začátku života organismu je potřeba deklarovat, kolik
uživatelských registrů organismus bude používat. Dělá se to pomocí příkazu
AllocUR, kterému za parametr předáme počet registrů. Tento
počet můžeme kdykoliv během života organismu změnit. Protože potomek
organismu dědí od rodiče i počet alokovaných registrů, stačí typicky
AllocUR zavolat jen u "hlavní matky" (organismu s hodnotou
GenCount rovnou 0).
Nyní smažte kód kontrolní procedury a napište místo něj tento:
if GenCount = 0 then AllocUR(2);if (Age = 0) or ((X = UR(0)) and (Y = UR(1))) then begin SetUR(0, Random(MaxX)); SetUR(1, Random(MaxY)); end; Eat(4); if Mass < 5 then Build(1); Digest(3); if X < UR(0) then Move(E, 1); if X > UR(0) then Move(W, 1); if Y < UR(1) then Move(S, 1); if Y > UR(1) then Move(N, 1); if OrgAt(0, 0) <> Species then Attack;
Výše uvedený kód hýbe organismem na nastavené souřadnice. Ty nastavuje těsně po narození, nebo když na ně dojede, tak nastaví nové. Přidána je i útočná část. Množení je pro jednoduchost vynecháno. Po spuštění bude organismus pobíhat po obrazovce sem tam.
Poslední specialitkou je nastavování UR cizích organismů.
Děje se tak pomocí příkazu SetForeignUR, který má parametry
shodné s příkazem SetUR, akorát nastavuje uživatelské registry
organismu, který je pod organismem, jehož procedura teď běží. Pokud tento
organismus pod sebou žádný jiný nemá, nenastaví se samozřejmě nic. Funkce
se používá převážně ve dvou případech: Buď pro nastavování inicializačních
hodnot UR potomků nebo pro "rozházení" hodnot nepřátelského
organismu. My si ukážeme první způsob. Jednoduše modifikujeme kód
předchozího organismu tak, aby potomek dostal cílové souřadnice už určeny
od svého rodiče. Samozřejmě musíme pamatovat na případ, že organismus byl
přidán do prostředí uživatelem, tudíž žádné rodiče nemá
(GenCount = 0)
if (GenCount = 0) or ((X = UR(0)) and (Y = UR(1))) then begin SetUR(0, Random(MaxX)); SetUR(1, Random(MaxY)); end; Eat(4); if Mass < 5 then Build(1); Digest(3); if X < UR(0) then Move(E, 1); if X > UR(0) then Move(W, 1); if Y < UR(1) then Move(S, 1); if Y > UR(1) then Move(N, 1); if OrgAt(0, 0) <> Species then Attack; if Age = 10 then begin DivCell; SetForeignUR(0, Random(MaxX)); SetForeignUR(1, Random(MaxY)); end;
Cizí registry se dají i číst pomocí ForeignUR (funguje
obdobně jako UR), ale tato funkce nebývá příliš využívána. Ale
když například víte, že organismus určitého druhu si některém registru
pamatuje souřadnice svého rodiče, není problém je přečíst a pak jet jeho
rodiče ztřeba zabít.
Počet cizích alokovaných registrů zjistíte pomocí funkce
ForeignAllocedURCount.
Tak to by bylo z tutoriálu vše. Naučili jste se základy psaní organismů
v The Life!. Tuším, že už teď Vás napadají desítky nápadů, co udělat za
"brouka". Můžu vám jen popřát hodně štěstí do tvorby a doporučit vám
prostudování si zdrojových textů příkladů organismů v adresáři Org.
Na konec ještě malý bonus — kompletní schéma energetických a potravních přesunů v organismu. Doporučuji vytisknout a přilepit před monitor, než se s The Life! trochu naučíte pracovat:
