Játékos fejlesztése Verzió 1.01 Utolsó módosítás: 2012. május 16.
1. Alapfogalmak Architekturális szempontból a StratOnAut rendszernek két szereplője van: •
A játékvezérlő: olyan egység, amely koordinálja a játékok lebonyolítását. Nyilvántartja a játékvilág állapotát, fogadja és feldolgozza a játékosok lépéseit, és tájékoztatja őket a játékvilág állapotában bekövetkező változásokról.
•
A játékos: olyan egység (a mesterséges intelligencia fogalmaival élve ágens), amely a játékban aktív szereplőként vesz részt: fogadja és feldolgozza a játékvilág állapotának változásait, és ezekre olyan válaszlépéseket igyekszik adni, amellyel elérheti a játékszabályban kitűzött győzelmi kondíciókat.
A játék a résztvevő játékosok lépéseinek sorozatából álló folyamat, ami addig tart, amíg valamelyik játékos nem győz, vagy a játékra szánt időkeret le nem telik. Egy játékban egy játékvezérlő és kettő vagy több játékos vesz részt.
2. Áttekintés Egy játékos fejlesztése alapvetően két feladatból áll: 1. Meg kell valósítani a játékvezérlővel való kommunikációt. A rendszer elosztott architektúrájú: a játékosok és a játékvezérlő fizikailag is különálló egységet alkotnak, a kommunikáció köztük HTTP üzenetek formájában, meghatározott protokoll szerint zajlik. A játékos ebből a nézőpontból tehát egy HTTP szerver, amely fogadja a játékvezérlő (mint HTTP kliens) üzeneteit, és válaszol rájuk. A játékvezérlővel való kommunikáció részleteit a kommunikációs protokoll specifikációja tárgyalja. 2. Meg kell alkotni a játékos mesterséges intelligenciáját. Ki kell fejleszteni azt az algoritmust, ami a játékvilág ismert állapotának elemzésével olyan lépések megtételére törekszik, amelyek elvezetnek a játék megnyeréséhez. Ez a StratOnAut verseny tulajdonképpeni célja. A HTTP protokoll feletti kommunikáció tetszőleges (a HTTP figyelést támogató) technológia alkalmazását lehetővé teszi. Jelenleg .NET platformon létezik egy keretrendszer, amely az első feladat megoldásának terhét leveszi a játékosfejlesztők válláról. (Bővebben l. a Játékos fejlesztése .NET platformon című fejezetet.) A fejlesztés, hibakeresés segítése érdekében a verseny szervezői egy tesztkörnyezetet üzemeltetnek, amely itt érhető el. Ennek használatával az élessel megegyező környezetben tesztelhető a játékos viselkedése.
3. Technikai segítség a kommunikáció hálózati beállításához A játékvezérlővel való sikeres kommunikáció előfeltétele a megfelelő hálózati beállítások alkalmazása. Ennek kapcsán két gyakori probléma szokott felmerülni: •
A játékost futtató számítógép nem közvetlenül csatlakozik az internetre, hanem helyi hálózaton, hálózati útválasztó (router) mögött van. Ekkor az internetről (a játékvezérlőtől) érkező adatcsomagok a routerhez fognak megérkezni, ezért konfigurálnunk kell, hogy ezeket a csomagokat továbbítsa a játékost futtató géphez. Ez általában a router adminisztrációs felületén állítható be, a (port) forwarding vagy virtual server nevű menüben. 1. Válasszunk egy nem „jól ismert”, 1024-nél nagyobb X portszámot. 2. Regisztráljuk a játékosunkat az X portra.
Szerző Dávid Zoltán – Simon Ádám
Verzió 1.01
Oldal 2/7
3. Amikor a játékvezérlőnek megadjuk a játékosunk címét (http://{ip}:{port}/), akkor használjuk az internet-szolgáltatónktól kapott IP címünket (ezt megnézhetjük a routerben vagy pl. itt) és az X portszámot. 4. Állítsuk be a routeren, hogy az X portra érkező TCP csomagok a játékost futtató gép helyi hálózatbeli IP címére és annak X portjára legyenek továbbítva. 5. A játékost futtató gépnek célszerű statikus IP címet adni, vagy a router DHCP szerverén fix MAC cím – IP cím hozzárendelést (address reservation) megadni, hogy a port forwarding beállítást ne kelljen újra és újra módosítani, amikor a gépünk más IP címet kap a DHCP szervertől. •
A játékost futtató számítógép tűzfal mögött van. Ez lehet pl. a router beépített vagy a futtató gép szoftveres tűzfala, stb. A tűzfalakat úgy kell konfigurálni, hogy átengedjék az X portra érkező csomagokat.
A beállítások helyességéről pl. a következő módon győződhetünk meg: 1. Elindítjuk a játékosunkat. 2. Ellenőrizzük itt, hogy az X port nyitva van-e.
4. Játékos fejlesztése .NET platformon Rendelkezésre áll egy .NET 4.0 platformra készült keretrendszer, amely elfedi a játékvezérlővel való kommunikáció részleteit, így megkönnyíti a .NET platformra készülő játékosok fejlesztését. A keretrendszer beépítetten támogatja több, párhuzamosan folyó játék kezelését. Rendezett objektumstruktúrában ad hozzáférést a játékvilág állapotához, amelyet automatikusan frissít. Eseményvezérelten teszi lehetővé a lépések megtételét. A keretrendszert a StratOnAut.Common és StratOnAut.Agent.Common osztálykönyvtárak tartalmazzák. Használatára a StratOnAut.Agent.PassPlayer és a StratOnAut.Agent.RandomPlayer projektek mutatnak példát.
4.1. Első lépések Két osztályt kell leszármaztatnunk: •
AgentGameState. Egy példánya egy játékhoz kapcsolódik, és annak állapotát tárolja. Az ősosztály gondoskodik a játékvezérlőtől kapott és az azokból származtatott alapvető állapotinformációk kezeléséről, a leszármaztatott osztályban további állapotinformációk nyilvántartására van lehetőségünk.
•
Agent
. Egy példánya egy játékost (ágenst) reprezentál. Ennek az osztálynak a felelőssége a lépések meghatározása az aktuális állapot alapján. (Bővebben l. A lépések megtétele című alfejezetet.) Az osztály TState típusparamétere határozza meg, hogy milyen típusú AgentGameState leszármazottban tároljuk a játékállapotot. (Ez az AgentGameStateből származtatott osztályunk lesz.)
4.2. A játékok kezelése A kívánt ponton (praktikusan a program indulásakor) létrehozzuk a játékos (Agent leszármazott) példányt, és meghívjuk annak Register() függvényét. Ennek hatására a háttérben elindul a HTTP üzenetek figyelése. Innentől kezdve – amíg az Unregister() függvényt meg nem hívjuk - a játékosunk minden induló játékba automatikusan bekapcsolódik. A játékvezérlőtől érkező világállapot üzenetek Szerző Dávid Zoltán – Simon Ádám
Verzió 1.01
Oldal 3/7
alapvető feldolgozását, a játékhoz kapcsolódó játékállapot objektum frissítését a keretrendszer automatikusan elvégzi.
4.3. A játékállapot A játékok állapotát az AgentGameState osztály leszármazottjának példányai tárolják.
4.3.1. A világállapot objektumstruktúrája A játékvezérlőtől kapott világállapot információk alapján a keretrendszer a következő objektumstruktúrát tartja karban.
Az osztályok leírása: •
GameState osztály: az AgentGameState osztály őse. o
RoundNumber tulajdonság: az aktuális kör sorszáma.
o
Map asszociáció: a térkép.
o
Upgrades asszociáció: az összes elérhető fejlesztés.
o
UnitTypes asszociáció: az összes elérhető egységtípus.
Szerző Dávid Zoltán – Simon Ádám
Verzió 1.01
Oldal 4/7
•
o
OwnPlayer asszociáció: a saját játékos.
o
Players asszociáció: a jelenleg játékban lévő játékosok.
GameMap osztály: a térképet reprezentáló osztály. o
•
GameSector osztály: a térkép egy területét reprezentáló osztály. o
•
•
•
•
•
Sectors asszociáció: az összes terület.
Neighbours asszociáció: a terület szomszédjai (az egy lépéssel elérhető területek).
Upgrade osztály: egy fejlesztést reprezentáló osztály. o
Name tulajdonság: a fejlesztés neve.
o
Price tulajdonság: a fejlesztés ára.
o
ProductivityBonus tulajdonság: a termelékenységi bónusz (százalékpontban).
o
DefenseBonus tulajdonság: a városvédelmi bónusz (százalékpontban).
o
Dependency asszociáció: a fejlesztés közvetlen előkövetelménye.
UnitType osztály: egy egységtípust reprezentáló osztály. o
Name tulajdonság: az egységtípus neve.
o
Price tulajdonság: az egységtípus ára.
o
AttackPower tulajdonság: az egységtípus támadási erőssége.
o
DefenseLevel tulajdonság: az egységtípus védekezési szintje.
o
Speed tulajdonság: az egységtípus által egy körben megtehető lépések száma.
o
Dependency asszociáció: az egységtípus fejlesztési előkövetelménye.
Player osztály: egy játékost reprezentáló osztály. o
Money tulajdonság: a jelenleg rendelkezésre álló pénzösszeg.
o
Upgrades asszociáció: a játékos által jelenleg birtokolt fejlesztések.
o
Units asszociáció: a játékos által jelenleg birtokolt egységek.
o
Territories asszociáció: a játékos által jelenleg birtokolt területek.
Unit osztály: egy egységet reprezentáló osztály. o
Type asszociáció: az egység típusa.
o
Player asszociáció: az egységet jelenleg birtokló játékos.
o
Sector asszociáció: az a terület, ahol az egység jelenleg tartózkodik.
Territory osztály: egy birtokolt területet reprezentáló osztály. o
HasTown tulajdonság: meghatározza, hogy jelenleg van-e város a területen.
o
Player asszociáció: a területet jelenleg birtokló játékos.
o
Sector asszociáció: a kapcsolódó térképterület.
A felsorolt osztályok (leszámítva a GameState és GameMap osztályokat) rendelkeznek egy Id tulajdonsággal, amely egyértelműen azonosítja a példányokat az adott osztályon belül. (Az azonosítóval rendelkező objektumok összehasonlítása felüldefiniált, és az azonosítók egyezőségére van visszavezetve.) Szerző Dávid Zoltán – Simon Ádám
Verzió 1.01
Oldal 5/7
A kollekció típusú asszociációk szótár típussal vannak megvalósítva, ahol a kulcs az objektum azonosítója. Így azonosító alapján hatékonyan kereshető vissza egy objektum. (Érdemes még megjegyezni, hogy a játékvezérlő jelenleg minden alkalommal közli a teljes világállapotot a round_info üzenetekben, ennek ellenére a korábban már létező objektumok nem példányosodnak újra, hanem csak az állapotuk frissül. Az eltűnt objektumok törlésre, a korábban nem létezők pedig létrehozásra kerülnek. Azaz a keretrendszer az azonosítók alapján „összefésüli” a régi állapotot az újjal.)
4.3.2. További, származtatott állapotok Az AgentGameState osztály a játékszabályok figyelembevételével nyilvántart néhány alapvető állapotinformációt. •
RoundAvailableUnitMoves szótár: tárolja, hogy az aktuális körben melyik egység hányszor léphet még. Csak azokat az egységeket tartalmazza, amelyek mozoghatnak még.
•
RoundAvailableUpgrades halmaz: tárolja, hogy az aktuális körben melyik fejlesztéseket lehet megvásárolni. Csak azokat a fejlesztéseket tartalmazza, amelyekre van elég pénz, és megvan az előkövetelményük.
•
RoundAvailableTownSectors halmaz: tárolja, hogy az aktuális körben melyik területeken lehet még várost alapítani.
•
RoundAvailableUnitPurchaseTowns halmaz: tárolja, hogy az aktuális körben melyik városokban lehet még egységet vásárolni.
•
RoundAvailableUnitTypes halmaz: tárolja, hogy az aktuális körben milyen típusú egységeket lehet vásárolni. Csak azokat az egységtípusokat tartalmazza, amelyekre van elég pénz, és megvan a fejlesztési előkövetelményük.
4.3.3. Események Az AgentGameState osztály két hasznos eseményt* definiál. () •
UpdateOnNewRound esemény: egy új kör indulásakor meghívódó függvény. Itt pl. lehetőség van valamilyen saját állapotinformáció inicializálására.
•
UpdateOnActionResponse esemény: egy lépésre kapott válasz megérkezésekor meghívódó függvény. A függvény paraméterei meghatározzák, hogy mi volt az utolsó lépés, és hogy az sikeres volt-e, vagy ha nem, akkor mi volt a sikertelenség oka.
4.4. A lépések megtétele A játékos az Agent osztály eseményeit* felhasználva határozhatja meg lépéseit. Mindegyik lépéstípushoz van egy esemény definiálva. Az események a kapcsolódó lépéstípusok játékszabályban rögzített sorrendjében hívódnak meg. (Pl. először az egységmozgatás, majd a fejlesztésvásárlás, stb.) Egy esemény csak akkor hívódik meg, ha van egyáltalán lehetőség a kapcsolódó típusú lépés megtételére. (Pl. egységvásárlás esemény egy körben csak akkor hívódik meg, ha van legalább egy
*
Nem valódi C# eseményekről van szó: ezek virtuális függvények, amelyekre a leszármazott osztályban való felüldefiniálással lehet „feliratkozni”. Szerző Dávid Zoltán – Simon Ádám
Verzió 1.01
Oldal 6/7
olyan egységtípus, amire van pénz, és aminek megvan az előkövetelménye, valamint van legalább egy város, ahol lehet egységet vásárolni.) Az események a következők: •
MoveUnit esemény: akkor hívódik meg, ha egység mozgatására van lehetőség. (Egy körben nullaszor vagy többször hívódhat meg.)
•
BuyUpgradeAction esemény: akkor hívódik meg, ha fejlesztés vásárlására van lehetőség. (Egy körben nullaszor vagy egyszer hívódhat meg.)
•
BuyTownAction esemény: akkor hívódik meg, ha város alapítására van lehetőség. (Egy körben nullaszor vagy többször hívódhat meg.)
•
BuyUnitAction esemény: akkor hívódik meg, ha egység vásárlására van lehetőség. (Egy körben nullaszor vagy többször hívódhat meg.)
Ha egy lépéstípusból már nem akarunk többet végrehajtani, azt null érték visszaadásával kell jeleznünk. A kört lezáró passzolás lépés automatikusan küldésre kerül a lépéssorozat végén. (Megjegyzendő, hogy a keretrendszer jelenleg semmilyen ellenőrzést nem végez a lépésen annak elküldése előtt, tehát egy lépés sikertelenségéről leghamarabb a játékvezérlő válaszakor értesülhetünk.)
4.5. Hibafelderítés, tesztelés A fejlesztés során érdemes a keretrendszer által használt TraceSource forrásokat naplózni, mivel megkönnyítik az esetleges hibák felderítését és a tesztelést. Jelenleg kettő ilyen van: •
StratOnAut.General: az általános naplóbejegyzések forrása. Ha egy lépés meghatározásakor vagy az állapot frissítésekor nem kezelt kivétel történik, az ide kerül rögzítésre.
•
StratOnAut.Communication: a kommunikációval kapcsolatos naplóbejegyzések forrása. Ide a kommunikációval kapcsolatos hibák naplózódnak, illetve verbose szinten minden beérkező és kiküldött üzenet ide íródik.
Szerző Dávid Zoltán – Simon Ádám
Verzió 1.01
Oldal 7/7