BallFight Készítők: A játékot készítette Róth Gergő és Orosz Ákos Rövid leírás: A játék célja az azonos színű labdák kipukkasztása a SameGame játékhoz hasonlóan. Egy táblán egyszerre két játékos játszik, így egymást tudják segíteni illetve hátráltatni. Szabályrendszer: Cél: A labdák kipukkasztásával több pontot kell szerezni a játék végére, mint amennyit az ellenfél szerez. A játékosok végrehajthatnak egy forgatás és egy lövés műveletet, de kizárólag ebben a sorrendben. A forgatás nem kötelező. A labdákra hat a gravitáció, vagyis lefelé esnek, ha alattuk kilőttünk egy vagy akár több labdát is. A labdákra hat egy jobbról jövő oldalirányú erő is, amely miatt minden oszlop az esés után balra tolódik, ha a tőle balra lévő oszlopban nincs egy labda sem. Természetesen ez addig folytatódik, míg a legalsó sorban a labdák balról sorfolytonosak nem lesznek. A forgatás után a labdák áthelyeződnek a gravitációnak illetve a jobbról jövő erőnek megfelelően (ebben a sorrendben). A lövés során az eltalált labda színének megfelelő egybefüggő labdák pukkannak ki. Két labda egybefüggő, ha élszomszédos pozícióban vannak. Az átlósan szomszédos labdák nem számítanak egybefüggőnek. A játékosok passzolhatnak is. Passzolásnak számít minden olyan lövés, amely során egy labda sem pukkan ki. Minden pukkasztás után a megfelelő játékos pontszámaihoz hozzáadódik a kipukkasztott labdák számából kalkulált pontszám. A pontszám számítása x * x függvény szerint történik, ahol x a kipukkasztott labdák száma. A játék vége: A játék akkor ér véget, ha egy körben mindkét játékos passzol.
Kommunikáció a BallFight programmal
A BallFight program feladata két mesterséges illetve valódi intelligencia kezelése. Egy intelligencia lehet a játékos által megírt program és a játékos is. Ezeket az intelligenciákat a BallFight program váltakozva hívja meg. A kommunikáció a játékosok által megírt programokkal a standard input és a standard
output-on keresztül történik. A standard error használható debug üzenetek írására. A BallFight biztosít a játékos által megírt programnak a standard input-on egy karakterláncot, ami a következőképpen néz ki: columns x rows, ahol colums az oszlopok, rows pedig a sorok száma (pl. 12x11). A sorok és az oszlopok száma maximálisan 20 lehet, a két érték lehet különböző is. Ezután rows számú új sorban következik columns mennyiségű egész szám szóközökkel elválasztva. Ezek a számok reprezentálják a táblát. Az első sorban lévő columns mennyiségű szám az első sorban levő labdákat tartalmazza, a második sorban lévő columns mennyiségű szám a második sorban levő labdákat tartalmazza és így tovább. A számok jelentik a labdák típusát. Értelemszerűen két labda akkor ugyanolyan típusú, ha a két reprezentáló szám azonos. Ha egy szám 0, akkor az adott pozícióban nincs labda. A következő kép a tábla egy állapotát jelzi, amely éppen a felhasználó lépésére vár.
Amennyiben a felhasználó a „Pass” gombra kattint, úgy a második játékos programja ugyanezt a táblát kapja meg. Erre a példára a stdio-n kapott bemenet a következő: 8x6 10000000 20000000 20220000 32330000
33323000 23323330 A játékos által megírt program a standard output-on keresztül biztosít információt a BallFight-nak. Így a standard output-ra tilos bármilyen más szöveget kiírni. A mesterséges intelligenciának először a forgatásra vonatkozó információt kell átadnia. Ez történhet jobbra és balra, vagy akár el is hagyható. A forgatásra vonatkozó információt csupán egy karakter hordozza. A balra forgatást az l ( left ), a jobbra forgatást az r ( right ) karakter jelenti. Minden egyéb nem whitespace karakter azt jelenti, hogy nem történt forgatás. A mesterséges intelligencia ezután adhatja meg, hogy hová kíván lőni. Ez a következőképpen néz ki: printf(“%dx%d”, x_shot, y_shot). A tábla sorainak és oszlopainak az indexelése 0-tól történik. Amennyiben a BallFight nem megfelelő információt kap vagy a lövés után egy labda sem pukkan ki, úgy a lépés passzolásnak számít. Példák a műveletekre: “l12x3”: balra forgat, aztán lő a 12. oszlop 3. sorába “r4x7”: jobbra forgat, aztán lő a 4. oszlop 7. sorába “n0x4”: nem forgat, aztán lő a 0. oszlop 4. sorába “ 1x5”: helytelen információ, passzolás ( szóköz ) “j-1x3”: helytelen információ, passzolás ( negatív indexű szám ) A játékosok debug üzeneteket a standard error-ra írhatnak (pl. fprintf(stderr, “debug information”) ).
Példaprogram
A mellékelt randomshooter.c példaprogram egy olyan forráskódot tartalmaz, ami beolvassa a táblát, majd véletlenszerűen balra forgat, jobbra forgat, vagy egyáltalán nem forgat. Ezután pedig véletlenszerűen választ a táblán belül egy pozíciót ahová lő. Értelemszerűen ha nem megfelelő helyre lő, vagyis nem pukkaszt ki egy labdát sem, akkor passzol. A példaprogram tartalmaz három függvényt. Az allocate_table(int width, int height) visszatér egy width szélességű és height magasságú nullával inicializált integer mátrixszal, amennyiben sikerült helyet foglalni. Hiba esetén NULL pointerrel tér vissza. A függvény a malloc(..) utasítást használja. A deallocate_table(int **table, int width, int height) függvény felszabadítja a lefoglalt tömböt. A függvény a free(..) utasítást használja. A process_table(int **table, int width, int height) függvény generálja az stdout-ra a véletlenszerű kimenetet. A main függvény első utasítása ( srand(time(0)) ) megkeveri a véletlenszám generátort. Az fprintf(..) függvény első paramétere határozza meg, hogy milyen file leíróra kell írnia. A többi paramétere ugyanaz, mint a printf(..) függvénynek. Az fprintf(stdout, ..) hívás
megegyezik a printf(..) hívással. Míg az fprintf(stderr, ..) a standard error csatornára ír. A scanf(”%dx%d”, &width, &height) sor felel a tábla méretének a beolvasásáért. Miután a program beolvasta a tábla méretét, dinamikusan helyet foglal neki a már említett allocate_table(..) függvénnyel. Ezt a címet elmenti a table változóba. A következő if(..) utasítással a program ellenőrzi, hogy sikerült-e helyet foglalnia a táblának. Amennyiben nem sikerült, a program visszatér 1-el, jelezve, hogy a futása helytelen volt. A BallFight csak az stdout-ra írt kimenetet dolgozza fel, így valójában teljesen lényegtelen a visszatérési érték. A tábla beolvasásáért a forráskódban következő egymásba ágyazott ciklus felel. A külső ciklus végigmegy az összes soron, majd minden egyes sor minden oszlopán és beolvassa a tábla megfelelő helyére. A (0, 0) koordináta a táblában a bal alsó saroknak felel meg. Ezután a program átadja a beolvasott táblát a process_table(..) függvénynek. A process_table(..) kiírja az stderr-re a tábla mátrixát, majd generál egy véletlenszerű számot [0, 2] intervallumon. Ez alapján dönt egy switch-case szerkezetben a forgatásról ( balra forgat ( ’l’ ), jobbra forgat ( ’r’ ), vagy egyáltalán nem forgat ( ’n’ ) ). Majd generál két véletlen számot a tábla méretének megfelelően és ezt kiírja az stdout-ra. A program ezzel végzi el a lövést. Amennyiben két randomshooter program futásának kezdete ugyanabban a másodpercben történik, úgy ugyanazokat a véletlenszerű eredményeket adja. Így, ha a két randomshooter versenyzik egymással, akkor ha az egyik passzol, akkor nagy valószínűséggel a másik is passzolni fog. Miután a process_table(..) végrehajtotta a feladatát a program visszatér a main függvénybe és a deallocate_table(..) segítségével felszabadítja a táblát. Majd a program kilép 0 visszatérési értékkel jelezve, hogy a futása helyes volt.
A BallMap ( .bm ) fájltípus
Minden egyes BallMap ( bm kiterjesztésű fájl ) egy előre elkészített pályát tartalmaz. Ez a fájl tartalmazza a tábla szélességét, magasságát, a típusok számát, a típusok színeit és persze a labdákat tartalmazó mátrixot. A bm fájlok 7 bites ASCII kódolású fájlok, melyek egész számokat tartalmaznak. Nem egész számokra a beolvasó helytelenül fog működni. Az első sorban két pozitív egész számnak kell állnia szóközzel elválasztva. Az első jelenti a tábla szélességét, míg a második a magasságát. A második sor a labdák típusainak számát tartalmazza. Majd ezt a sort követi a típusok mennyiségének megfelelő számú sor, melyek mindegyike egy-egy színt jelent. A színek 24 bites RGB kódolásúak, vagyis minden színt tartalmazó sor 3 egymástól szóközzel elválasztott számból áll. Mivel minden egyes színkomponens 8 bites, ezért értéket a [0, 255] intervallumon vehetnek fel. A fájl további része tartalmazza a táblát reprezentáló mátrixot. Ez a magasságnak megfelelő mennyiségű sort és minden egyes sorban a szélességnek megfelelő mennyiségű számot tartalmaz. Ha egy szám az [1, típusszám] intervallumba esik, akkor ott labda van, minden más esetben nincs labda.
A BallFight program használata
Telepítés: a mellékelt könyvtárstruktúrát mentsük el. A BallFight programot a BallFight.exe indítja (Windows alatt).
A következő kép illusztrálja az indításkor fellépő állapotot és a „game” menüpontot. Látható, hogy a program tartalmaz három beviteli mezőt egy-egy „Browse” feliratú gombbal. Minden mezőbe csak létező elérési útvonalat és fájlnevet lehet írni vagy megadni (ez a név lehet relatív is a futtató mappához képest). Az elsőben meg lehet adni egy pályát. Ha a mező üresen marad, akkor a beállításoknak ( „random table options” ) megfelelően generál egy véletlenszerű táblát. A másodikban egy exe kiterjesztésű fájlt lehet megadni, ami az első számú játékos programját tartalmazza. A harmadikba ugyancsak egy programot lehet beírni, de ez már a második játékos programja. Amennyiben valamelyik programhoz a felhasználó nem ír be semmit, úgy amikor az a játékos következik a forgatást és a lövést a felhasználótól várja. A felhasználó csak a „Pass” gombra kattintással tud passzolni. Ha a felhasználó kitöltötte a megfelelő mezőket, akkor a „start game”-re kattintva el is indíthatja a játékot. Bármikor leállítani a „stop game”-mel tudja, vagy egyszerűen bezárja a programot.
A „game” menüpont alatt két beállítási lehetőség közül választhatunk. A „fancy display”-el a textúrázást lehet be illetve kikapcsolni, míg az „animation”-nel az animációkat lehet kapcsolgatni. Az előbbi kényelmes lehet nagyobb foltok szemmel történő megtalálásához, míg a második a játékmenetet gyorsítja fel. Animáció közben nem fut program és a felhasználó sem tudja a programot irányítani. A „show process output”-ra kattintva megnyílik egy ablak, amiben két szöveges kimenet található. A felső a programok stdout, az alsó pedig az stderr kimeneteit tartalmazza.
A „random table options”-szel felnyílik egy előugró ablak, amiben beállítható, hogy mekkora legyen a szélessége és a magassága, valamint, hogy mennyi labda típus legyen a véletlenszerűen generált táblában.
Értékelés A verseny során különböző (előre nem ismert) pályákon zajlik majd a küzdelem körmérkőzések formájában a pályázók programjai között. A programok egymás ellen fognak játszani egy automata segítségével, amelynek szabályai hasonlóak a kiadott egyszerű BallFight programéhoz. A futtatás során egy lépésre maximum 2 másodperc ideje lesz a programoknak, ennél hosszabb gondolkodási időt passzolásnak értelmezünk. Az egyes fordulókban szerzett pontszámok összeadódnak, a legtöbb pontot szerzett program lesz a győztes.