Predchádzajúci článok bol venovaný základným princípom hry Robocode. Dnes si povieme niečo o postupoch, bez ktorých žiadny robot v tvrdej konkurencii neobstojí. A vlastne ani žiadny programátor. Reč bude o trigonometrii, dátových štruktúrach, vstupe/výstupe, návrhu kódu a o distribuovaných systémoch. No nečakajte vyčerpávajúce vysvetlenie týchto techník. Robocode je hra pre začínajúcich „pokročilých“ programátorov a pre tých je aj nasledujúci text.
Trigonometria
Základom pre úspech robota v boji je presná streľba a vyhýbanie sa zásahom. Keďže aréna je vlastne dvojrozmerná súradnicová sústava a tanky sú odsúdené pohybovať sa po jej povrchu, väčšina ich práce sa bude týkať prepočítavania súradníc, vzdialeností a rýchlostí.
Pohyb
Najjednoduchšie je pohybovať sa po úsečkách. Takýto pohyb je však ľahko predvídateľný (viď nasledujúci odstavec o zameriavaní). Pohyb po krivkách je iste lepší, ale vyžaduje od programátora viac počítania a tiež použitie neblokovacích volaní API (viď predchádzajúci článok).
Je veľa spôsobov, ako sa pohybovať medzi ostatnými robotmi – podľa presných pravidiel alebo úplne náhodne. Jedna z pokročilejších techník je antigravitačný pohyb, ktorá je založená na určení príťažlivých a odpudivých bodov v aréne. Výslednica síl týchto bodov potom určuje pohybový vektor nášho robota. Príťažlivosť môžeme priradiť slabším protivníkom, odpudivosť silnejším. Veľmi podrobne o tomto postupe pojednáva tento článok.
Ďaľšou motiváciou pre zlepšenie pohybu je vyhýbanie sa cudzej streľbe. Letiaci projektil je pre nás a náš kód neviditeľný, no ak sledujeme energiu nepriateľa, môžeme z jej náhleho poklesu zistiť moment výstrelu a vyhnúť sa predpokladanej trajektórii strely. Napríklad tak, že strele priradíme odpudivý bod (samozrejme len ak náš robot implementuje antigravitačný pohyb:).
Zameriavanie
Ak už vieme niečo o pohybe, je nám jasné, že zameriavanie je s ním tesne spojené. Nemá zmysel strieľať na miesto, kde vidíme nepriateľa, pretože kým strela doletí, on už tam pravdepodobne nebude. Preto sa snažíme odhadnúť, kde bude v tom čase, no na to potrebujeme poznať jeho pohybový vzor. Nesmieme zabúdať, že neúspešná streľba stojí robota energiu. Nie je ťažké predpovedať trajektóriu lineárneho alebo kruhového pohybu. Ale dá sa predpovedať pohyb zdanlivo náhodne pohybujúceho sa tanku? Možno by nám s tým vedeli pomôcť dátové štruktúry.
Dátové štruktúry
Pri programovaní slúžia dátové štruktúry na uchovanie stavu popísaného systému. Konkrétne v Robocode napríklad na uloženie informácií o pohybe ostatných robotov v aréne. Z týchto informácií sa dajú odhadovať vzory ich pohybu alebo úspešnosť v boji. Tak môžeme vytvoriť triedu Enemy
na uchovanie jedného stavu, EnemyLog
na uchovanie viacerých stavov konkrétneho nepriateľa a EnemyManager
na manipuláciu s týmito záznamami.
S informáciami o miestach „pobytu“ robota v čase by sme sa už mohli pokúsiť určiť jeho pohybové návyky, snáď aj predpovedať jeho budúce výskyty. Ale to je už iné rozprávanie.
Nebudem uvádzať implementáciu takéhoto systému, veľmi jednoduchý príklad (ktorým boli inšpirované predchádzajúce riadky a ktorý by mal podať dodatočné vysvetlenie) nájdete tu.
Vstup a výstup
Trieda AdvancedRobot
dovoľuje prácu so súbormi. Ak túto možnosť využívame, vytvorí sa pre robota v jeho balíku adresárMenoRobota.data, do ktorého môže odkladať svoje dáta, najviac však približne 200kB. Súbory aj adresár sú reprezentantami java.io.File
a manipuluje sa s nimi pomocou prúdov. Takto si môže robot napríklad perzistentne ukladať zistené informácie o svojich nepriateľoch medzi dvoma kolami boja.
Naviac má každý robot prístup k jednému PrintStream
-u, ktorý zapisuje na konzolu. Tento prúd je nazvaný out
a príslušná konzola je k dispozícii pod tlačítkom s menom robota na pravej strane arény. Tam si môžeme nechávať zobrazovať hlásenia pri ladení kódu, ale aj bojový pokrik nášho stroja.
Návrh kódu
Roboti robia množstvo opakujúcich sa matematických operácií, takže každého napadne umiestniť ich do metód. Časom metódy pribúdajú a kód sa znovu stáva neprehľadným, takže nie je zle vytvoriť samostatné triedy pre rôznu funkcionalitu. Jednu triedu pre statické matematické funkcie, jednu pre zameriavanie, inú pre algoritmy pohybu. A samozrejme triedy pre vyššie spomínané dátové štruktúry. Ak sú tieto moduly dobre napísané, môžeme ich znovu používať v rôznych robotoch.
Takýmto postupom je navyše jednoduchšie meniť správanie robota. Namiesto prepisovania logiky zameriavania stačí ak v hlavnej triede MyModularRobot
použijeme iné volania z triedy ScanAndAim
(tie názvy som si samozrejme vymyslel ako aj ďalšie:).
Ale dá sa dosiahnuť aj vačšia úroveň abstraktnosti. Stačí ak vytvoríme triedu, ktorá zastreší bežnú funkcionalitu, inicializáciu a pospája volania jednotlivých modulov.
public class MyAbstractRobot extends AdvancedRobot {
...
public Enemy getEnemy(ScannedRobotEvent e) {...}
public void aimAtEnemy(Enemy e) {...}
public void runFromEnemy(Enemy e) {...}
...
}
V hlavnej triede MyRealRobot
sa potom už venujeme len stratégii:
public class MyRealRobot extends MyAbstractRobot {
...
public void onScannedRobot(ScannedRobotEvent event) {
Enemy enemy = getEnemy(event);
if (e.getEnergy() < this.getEnergy()) {
aimAtEnemy(enemy);
fire(1);
} else {
runFromRobot(enemy); // :-)
}
}
}
A náš robot môže byť na svoj dizajn pyšný: logika je rozdelená do znovupoužiteľných modulov a jednotlivé metódy sú krátke, jasne pomenované a čitateľné:).
Tímová práca
Na záver by som rád venoval (skutočne len) pár riadkov možnosti boja tímov v Robocode. Tím sa dá vytvoriť z individuálnych robotov v menu Robot > Team > Create Team, použiť sa dajú akýkoľvek roboti v akomkoľvek počte. Prvý robot v skupine získa postavenie vodcu, bude mať 200 bodov energie, no po jeho zničení sa odpočíta 30 bodov každému radovému členovi. Takúto skupinu potom môžeme zapojiť do boja v aréne rovnako ako jednotlivého robota.
Špecifickosť tímovej práci dáva trieda TeamRobot
, odvodená od AdvancedRobot
. Roboti z tejto triedy si môžu navzájom vymieňať správy – akékoľvek serializovateľné objekty. Odosielať sa dá správa všetkým členom tímu alebo niekomu konkrétnemu, prijatie správy sa prejaví ako vyvolanie udalosti MessageEvent
. Ďalším rozšírením je rozhranie Droid
– robot, ktorý ho implementuje, dostane 20 bodov energie naviac, ale nemá radar a tak je odkázaný na správy od svojich spolubojovníkov.
Popisované pravidlá sú veľmi jednoduché, ale prinášajú dosť zaujímavé možnosti. Je samozrejmé, že úspech boja tímov záleží na vhodnom komunikačnom protokole. Je nutné vybrať medzi centralizovaným a decentralizovaným modelom spolupráce, rozdeľovať úlohy, v prípade „výpadku“ centrálneho stroja usporiadať voľby na nového vodcu, zvážiť používanie časových známok na správy, vyhýbať sa deadlocku… Záleží len na fantázii. Tak ako to pri hrách obvykle býva.
Záver
V tomto krátkom seriáli som sa snažil predstaviť programátorskú hru Robocode. Nešlo ani tak o poskytnutie kompletného tutoriálu ako o naznačenie možností. Možností ako sa zabávať, ako sa učiť a snáď aj ako učiť. Pretože Robocode takýto potenciál obsahuje.
Linky
Veľa inšpirácie pre tento článok pochádza z: