Obsah

Spätná väzba od hráča

Implementácia v Jim hrácovi

Implementované boli dve nové triedy TestFrameworkCommunication a Message. Prvá z týchto tried je spustená hneď pri spustení hráča a jej úlohou je pripojiť sa na TCP server testovacieho frameworku, udržiavať spojenie a posielať správy. Určenie adresy samotného testovacieho frameworku ako aj možnosť zapnutia samotnej spätnej väzby je vykonané prostredníctvom konfiguračného súboru premennými „TestFramework_monitor_enable„“ a „TestFramework_monitor_address“. Trieda Message následne umožňuje vytváranie správ na odoslanie a zabezpečuje správny formát týchto správ. Vytvorenie konkrétnej správy je umožnené rôznymi statickými metódami. Pri spustení triedy s nedostatočnými informáciami sú doplnené údaje z konfiguračného súboru (napríklad tftp port pre vykonávanie príkazov)

Nové správy je možné jednoducho implementovať vytvorení novej triedy dediacej od Message, ktorá vytvára správu v správnom formáte. Následné je nutné implementovanie parsera tejto triedy v testovacom frameworku a to vytvorením triedy dediacej od AgentMonitorMessage.

Implementácia v TestFrameworku

Vytvorená bola nová trieda AgentMonitor, ktorý zohráva úlohu TCP servera pre prichádzajúce nové spojenia. Po príchode nového spojenia je vytvorená nová inštancia triedy AgentMonitorThread, ktorá vykonáva čítanie správ z daného spojenia a následne ich posiela na spracovanie triede AgentMonitorMessage. Trieda AgentMonitorThread vytvára ešte nový typ správy TYPE_DESTROY v prípade zrušenia spojenia s daným hráčom. Po úspešnom spracovaní správy sú notifikované všetky registrované triedy implementujúce rozhranie IAgentMonitorListener na počúvanie (návrhový vzor observer). Pri registrovaní na počúvanie je možné určiť presne pre ktoré typy správy chce byť daná trieda notifikovaná a to určením čísla hráča, jeho tímu alebo typu správy.

Príklad registrovania na typ správy triedou implementujúce rozhranie IAgentMonitorListener:

AgentMonitor.setMessageListener(this, TYPE_INIT |TYPE_DESTROY);

Príklad spracovania správy:

@Override
public void receivedMessage(int uniform, String team, AgentMonitorMessage message) {
   switch (message.type_flags) {
            case TYPE_INIT:
                  Init msgInit = (Init) message;
                  // spracovanie informacie o pripojeni agenta
                  break;
            case TYPE_DESTROY:
                  // spracovanie informacie o odpojeni agenta
                  break;
      }
}

Parsovanie správ

Typická správa nepresahuje dĺžku jedného riadka a obsahuje číslo hráča, meno tímu, typ správy a posielané hodnoty.

Príklad takejto správy je informácia o začatom pohybe, ktorá má nasledovnú formu:

(1 ANDROIDS LEFT) highskill start rollback 0.0

Výnimkou pri posielani správ je odosielanie aktúalneho stavu sveta ako ho vidí hráč (prenos celého objektu WorldModel). Stav sveta je na strane hráča deserializovaný do pola bajtov a následne zakódovaný do textového reťazca pomocou Base64. Okrem štandardných informácií ako pri predošlých správach je odosielaný checksum dát v novom riadku a samotné dáta v ďalších riadkov. Celá jedna správa je ukončená textovým reťazcom „endData“.

Príklad správy je následovný:

(1 ANDROIDS LEFT) worldmodel beginData
6488e0907bc62ad6429963910a7c6c975d44275b
rO0ABXNyACNzay5maWl0LmppbS5hZ2VudC5tb2RlbHMuV29ybGRNb2RlbM8irrx9aZAgAETAAK
8FbJQDWQwJTKvbpzcQB+AAg/QAAAAAA...ADHcIAAAAEAAAAAB4c3EAfgAIP0AAAAAAAAx3CAAA
ABAAAAAAeA==
endData

Správy sú následne dekódované na strane testovacieho frameworku. Správy sú dekodóvané dvoma rôznymi metódami, a to podľa toho či obsahuje dáta alebo nie. V obidvoch prípadoch však funkcie musia parsovať prvý riadok správy, a zistiť čo sa prijíma. Dve funkcie sú následovné:

parse(String input)
parse(String firstLine, Object deserialized)

V druhom prípade, keďže je ojedinelí sa okamžite vytvorí správa typu WorldModel. V prvom prípade sa postupne prechádza slovami prijatej správy, pokiaľ sa text slova nerovná názvu niektorej z tried definovaných v triede „AgentMonitorMessage“. Zvyšky prijatej správy sú poslané do konštruktora tejto triedy v podobe pola textových reťazcov a trieda má spracovať (odobrať) z pola prvky ktoré jej patria. Nespracované časti správy (elementy pola prijatých textových reťazcov) sú neskôr spracované hlavnou triedou „AgentMonitorMessage“, ktorá v tomto poly bude očakávať už len číslo hráča a meno tímu.

Príkladom je spracovanie správy o začatom pohybe:

(1 ANDROIDS LEFT) highskill start rollback 0.0“

Na spracovanie tejto triedy je potrebné definovať následnú novú triedu v triede „AgentMonitorMessage“:

public static class HighSkill extends AgentMonitorMessage {
   // rozne pomocne premenne
      public static class Start extends HighSkill {
            public Start(Stack<String> tokens) {
                  player_time = Double.parseDouble(tokens.pop());
                  move_name = tokens.pop();
                  type_flags |= TYPE_HIGHSKILL;
                  super.init(tokens);
            }
      }
}

Definovaná bola trieda „AgentMonitorMessage.HighSkill.Start“. Pri parsovaní sa úspešne identifikovala časť správy „highskill start“ na túto triedy. Do konštruktora tejto triedy bolo teda vložené následové pole textových reťazcov: {0.0, rollback, Left, Androids, 1}. Prvé dva argumenty musí táto trieda spracovať a o ostatné sa už postará trieda od ktorej dedí (pomocou spustenia metódy „super.init(tokens)“.

Po úspešnom zpracovaní správy je rozoslaná všetkým zaregistrovaným listenerom pre daný typ správy (typ správy je určenú pomocou premennej „type_flags“). Typy správ sú definované ako konštanty v triede „AgentMonitorMessage“. Vykonávajú sa nad nimi logické operácie AND a OR na zisťovanie či daná správa vyhovuje registrovanému listeneru. Možné je teda definovať listener na viacero typov správ naraz. Pre zaregistrovanie a odregistrovanie listenera je umožnené vykonať zavolaním následovných metód:

AgentMonitor.setMessageListener(uniform,team,listener,message_type_flags)<br />
AgentMonitor.removeMessageListener(IAgentMonitorListener listener)