Tutoriál k vytváření organismů

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.

Obsah

1. část

2. část

Co je to organismus?

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í).

Založení projektu

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.

Postup

  1. Spusťte Delphi.
  2. Zvolte File|Open... a vyberte soubor Default.dpr v podadresáři Org.
  3. Zvolte File|Save Project As... a napište jméno svého organismu. To smí obsahovat jen písmena, čísla a podtržítko ("_"), přičemž první znak smí být jen písmeno nebo podtržítko (pravidla jsou tedy shodná jako pravidla pro identifikátor v Object Pascalu). Pro začátek zvolte jméno Organismus1.

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í:

  1. Je to knihovna DLL. Na tom není nic překvapivého, protože jak bylo řečeno v úvodu, organismy jsou tvořeny knihovnami DLL.
  2. Používá se unita 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.
  3. Nachází se tu procedura OrgRun. Ano, správně, jsme u toho — toto je ona kontrolní procedura, nejdůležitější věc na celém organismu.
  4. Kromě 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.

Prostředí

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í".

Vlastnosti a příkazy

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.

Čím začít? Jídlem!

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:

Postup

  1. Najeďte na řádek s komentářem v proceduře OrgRun.
  2. Komentář smažte a místo něj napište:
if Mass < 5 then Eat(1);
  1. Stiskněte F9. Tím se organismus zkompiluje a spustí se The Life!
  2. Klikněte levým tlačítkem myši na tlačítku Přidat organismus. Objeví se seznam, ze kterého vyberte jméno vašeho organismu (pokud jste se důsledně drželi tutoriálu, mělo by to být Organismus1).
  3. Klikněte kdekoli na žlutohnědé "šachovnici". Tím se organismus, který jste předtím vybrali v menu, přidá do prostředí.

Energetické potřeby

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.

Postup

  1. Ukončete The Life! — objeví se zas editor Delphi.
  2. V proceduře 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;
  1. Stiskněte F9 a opakováním předešlého postupu přidejte organismus do prostředí.

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.

Pohybem ku zdraví

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.

Vědět o potravě je skoro stejně důležité jako ji mít

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:

Organismus a relativní souřadnice

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.

Souřadnice + kam až můžu?

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.

Barvičky

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.

Stáří a mládí

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!).

Buněčné harakiri

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ů.

Pár drobností

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...


Nejlepší obrana je útok

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!

Kdo jsem a kdo je to pode mnou?

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.

Pár drobností podruhé

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.

Buněčná paměť

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.

Cizí paměť taky paměť

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.

Závěr

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:

Schéma energetických a potravních přesunů v organismu