Szakdolgozat Miskolci Egyetem Logikai játékok nyerő stratégiáinak keresése Készítette: Dorgai Attila Programtervező informatikus szak Témavezető: Dr. Körei Attila, egyetemi docens Miskolc, 2017
Miskolci Egyetem Gépészmérnöki és Informatikai Kar Alkalmazott Matematikai Tanszék Szám: Szakdolgozat Feladat Dorgai Attila (FEDI1K) programtervező informatikus jelölt részére. A szakdolgozat tárgyköre: Mesterséges intelligencia A szakdolgozat címe: Logikai játékok nyerő stratégiáinak keresése A feladat részletezése: Kétszemélyes, teljes információjú játékok vizsgálata. A játékfa bejárására, elemzésére, levágására alkalmas módszerek bemutatása (minimax tétel, alfabéta algoritmus). A nyerő stratégia létezésének kérdése. Egy konkrét logikai játékot játszó program elkészítése, tesztelése. Témavezető: Dr. Körei Attila, egyetemi docens. A feladat kiadásának ideje: 2016. szeptember 12.................................. szakfelelős 2
Eredetiségi Nyilatkozat Alulírott Dorgai Attila; Neptun-kód: FEDI1K a Miskolci Egyetem Gépészmérnöki és Informatikai Karának végzős Programtervező informatikus szakos hallgatója ezennel büntetőjogi és fegyelmi felelősségem tudatában nyilatkozom és aláírásommal igazolom, hogy Logikai játékok nyerő stratégiáinak keresése című szakdolgozatom/diplomatervem saját, önálló munkám; az abban hivatkozott szakirodalom felhasználása a forráskezelés szabályai szerint történt. Tudomásul veszem, hogy szakdolgozat esetén plágiumnak számít: szószerinti idézet közlése idézőjel és hivatkozás megjelölése nélkül; tartalmi idézet hivatkozás megjelölése nélkül; más publikált gondolatainak saját gondolatként való feltüntetése. Alulírott kijelentem, hogy a plágium fogalmát megismertem, és tudomásul veszem, hogy plágium esetén szakdolgozatom visszautasításra kerül. Miskolc,............év............hó............nap................................. Hallgató 3
1. A szakdolgozat feladat módosítása szükséges (módosítás külön lapon) nem szükséges................................................. dátum témavezető(k) 2. A feladat kidolgozását ellenőriztem: témavezető (dátum, aláírás): konzulens (dátum, aláírás):................................................................................. 3. A szakdolgozat beadható:................................................. dátum témavezető(k) 4. A szakdolgozat................... szövegoldalt................... program protokollt (listát, felhasználói leírást)................... elektronikus adathordozót (részletezve)...................................... egyéb mellékletet (részletezve)................... tartalmaz.................................................. dátum témavezető(k) 5. bocsátható A szakdolgozat bírálatra nem bocsátható A bíráló neve:............................................................................................. dátum szakfelelős 6. A szakdolgozat osztályzata a témavezető javaslata:................ a bíráló javaslata:................ a szakdolgozat végleges eredménye:................ Miskolc,......................................................... a Záróvizsga Bizottság Elnöke 4
Tartalomjegyzék 1. Bevezetés 7 2. Logikai játékok 8 2.1. Kétszemélyes játékok............................ 8 2.2. Nyerő stratégiák............................... 8 2.3. A játékfa................................... 9 2.4. Minimax algoritmus............................. 10 2.5. Kiértékelő függvények............................ 11 2.6. Alfa-béta nyesés............................... 12 2.7. A Deep Blue és az AlphaGo programok összehasonlítása........ 14 2.7.1. A sakk és a go összehasonlítása.................. 14 2.7.2. A Deep Blue működése....................... 16 2.7.3. Az AlphaGo működése....................... 17 2.7.4. A Deep Blue és AlphaGo működésének összehasnolítása..... 20 2.7.5. Jövőbeli lehetőségek az AlphaGo megközelítésének alapján... 20 2.8. Az amőba története............................. 21 2.8.1. Az amőba szabályai......................... 21 3. Fejlesztői dokumentáció 22 3.1. Használt programozási eszközök...................... 22 3.1.1. A választott eszközök........................ 22 3.1.2. A programok egyesítése....................... 22 3.2. A játéktér felépítése............................. 23 3.3. A gép lépésének kiválasztása........................ 23 3.3.1. A getvalue()............................ 23 3.3.2. A calcbestmoves()......................... 23 3.3.3. A compmovesmm()......................... 24 3.3.4. A gép játékstílusa.......................... 24 3.4. A játék vége................................. 25 3.5. Játék a fal közelében............................ 25 3.5.1. A probléma a fal melletti játékkal................. 25 3.5.2. A megoldása............................. 25 3.6. A heurisztika................................ 26 3.6.1. A heurisztika megvalósítása.................... 26 3.6.2. Első példa a heurisztikára..................... 26 3.6.3. Második példa a heurisztikára................... 28 3.7. A játékmódok................................ 29 3.7.1. Nehézségi fokozatok sorrendisége................. 29 5
3.8. A grafikai működés............................. 30 3.8.1. A tábla megvalósítása....................... 30 3.8.2. Kattintás a táblán......................... 30 3.8.3. Kattintás a menüben........................ 30 3.8.4. Az indikátor működése....................... 30 3.8.5. A menü............................... 30 3.8.6. A játékos elleni mód........................ 31 3.9. Kísérletezések, jövőbeli tervek....................... 32 4. Összefoglalás 33 Irodalomjegyzék 34 Adathordozó használati útmutató 35 6
1. fejezet Bevezetés A szakdolgozatom témájának azért választottam a logikai játékok nyerő stratégiáinak vizsgálatát, mert nagy hatással voltak rám a közelmúltban elért sikerek ezen a területen, különösen, hogy a go is beállt a számítógép által meghódított játékok sorába, amikor 2016 márciusában 4:1-re legyőzte a google AlphaGo programja a játék világbajnokát. Az eredmény azért is volt kimagasló, mivel a játék sokkal komplexebb a sakknál, ezért csak jóval későbbre merték volna megjósolni a kutatók a számítógép sikerét. Mivel a minimaxos alfa-béta nyeséses megvalósításból már sok amőba program született, ezért úgy gondoltam, hogy sajátosabb úton közelítem majd meg a feladatot. Mindig is érdekelt, hogy ha teljesen koncentrálva hiba nélkül tudok játszani a meglévő tudásommal, akkor mennyire vagyok jó játékos. Ezen a szálon elindulva jutottam arra az elhatározásra, hogy az én gondolkodásmódom szeretném átadni a programomnak. A súlyokat saját játékokból meghatározva, kikövetkeztetve határoztam meg, ami leginkább illik a játékstílusomhoz. Korábban, egyetemi tanulmányaim alatt már készítettem egy hasonló programot, ami sudoku rejtvényeket oldott meg heurisztikával, szintén saját tudásom felhasználásával. Már akkor is meglepett az eredmény, hogy hiába tartottam magam jó sudoku fejtőnek, mégis voltak olyan táblák ahol elakadt. Vissza kellett nyúlnom a gépi megközelítéshez és betippelni, egy számot, lehetőleg olyat amire 50-50 % esély van, és azokkal végig haladni tovább megnézni, hogy a tábla helyes marad-e. A legtöbb újságban található példákban nem volt szükség tippelésre, a nehezebb feladatoknál pedig egy-két tipp elég volt. 7
2. fejezet Logikai játékok 2.1. Kétszemélyes játékok A mesterséges intelligencia eléggé szétágazó tudományág még a logikai játékokon belül is, ám a váltott lépésű determinisztikus zérusösszegű kétszemélyes teljes információjú játékokra a tudományos MI is figyelmet szentel. Ide tartoznak azok a játékok, amelyek megfelelnek a következő feltételeknek: A két játékos felváltva lép (néhány esetben van kivétel amikor az ellenfél nem tud lépni, pl.: Reversi) Véges számú lépés létezik Nincs szerepe a véletlennek a játékban Mindkét játékos birtokában van minden információnak a játékkal kapcsolatban, azaz a szabályoknak, az összes lehetséges lépésnek az adott helyzetben, és az eddigi lépéseknek, ugyanis néhány játéknál fontosak az előző lépések a szabályok szempontjából (pl.: A sakkban az en passant csak az ellenfél egy bizonyos lépése után léphető.) Zérusösszegű Tehát ha a győztesként kikerülő játékos értéke +1, akkor a vesztesnek -1-nek kell lennie. Fontossága abban rejlik, hogy a többszemélyes játékoknál, megjelenhetnek szövetségek, és abban az esetben nem a saját értékünk maximalizására törekszünk feltétlenül. (Pl.: Rizikó) [1] 2.2. Nyerő stratégiák Amikor azzal foglalkozunk, hogy létezik-e egyes játékokhoz biztos stratégia, akkor azt vizsgáljuk, hogy van-e olyan kényszerítőág a játék kezdetétől fogva, amiből az ellenfél nem tud fordítani az álláson és győztesként kijönni, bármit is lép. Ilyen stratégia minden kétszemélyes teljes információjú logikai játéknál létezik az egyik fél számára, amennyiben a játék nem végződhet döntetlennel. Abban az esetben ha mégis, akkor nem-vesztő stratégiáról beszélünk. Ezt mondja ki Zermelo-tétele. 8
2.3. A játékfa Ha Zermelo tételét alkalmazzuk a sakkra vagy az amőbára, akkor azt a következtetést vonhatjuk le, hogy: Vagy fehérnek létezik nyerő stratégiája. Vagy feketének létezik nyerő stratégiája. Vagy mindkettőnek létezik nem-vesztő stratégiája. Amennyiben nincs lehetőség döntetlenre egy játékban, akkor ha az egyik játékosnak nincs nyerő stratégiája, a másik játékos nem-vesztő stratégiája egy nyerő stratégia lesz. 2.3. A játékfa A játékfa úgy épül fel, hogy a csúcsok egy-egy játékállást tartalmaznak, az élek pedig a szabályos lépéseket jelképezik, amelyek a következő játékálláshoz vezetnek. Tehát a gyökérben a kezdő állapot (többnyire az üres tábla) fog szerepelni, míg a levelekben a játék végét tartalmazó állás lesz. Biztosan csak akkor tudjuk megállapítani egy állásról, hogy létezik-e hozzá nyerő stratégia, ha az álláshoz tartozó játékfának az alatta levő részfájában az ellenfél nem tudja elkerülni semmilyen esetben sem, hogy az ellenfele olyan levélre vezesse amiben az ő győzelmével ér véget a játék. A fentiek miatt az ilyen fajta feladatokat visszavezethetjük egy játékfán alkalmazott keresési problémára. 9
2.4. Minimax algoritmus 2.1. ábra. A Tic-Tac-Toe játékfája Néhány játéknál ez a fa teljes egészében felírható, (ilyen például a Tic-Tac-Toe játék), azonban a legtöbb esetben (azaz a bonyolultabb játékoknál) a fa robbanásszerűen, exponenciálisan növekszik a lehetséges lépesek, és a játék megnyeréséhez szükséges lépések számának a függvényében. Ezekben az esetekben már nem tudunk valós időben biztos stratégiát mondani, habár azt meg tudjuk állapítani, hogy nyerő vagy nem vesztő stratégia létezik-e egy játékhoz. A kezelhető méretű játékfával rendelkező játékokra nagyon jó megoldás lehet a minimax algoritmus használata. 2.4. Minimax algoritmus Az algoritmus a játékállásokhoz rendel 1, 0 vagy -1 értéket attól függően, hogy melyik játékosnak létezik nyerő stratégiája abban az állásban. 1, ha MAX-nak van nyerő stratégiája. 0, ha MAX-nak csak döntetlent elérő stratégiája van. -1, ha MAX vesztes ágon van, és az ellenfelének létezik nyerő stratégiája az adott helyzetből. Az algoritmus azonban jóval több, mint egy egyszerű keresési feladat, ugyanis feltételeznünk kell, hogy az ellenfél (MIN) minden esetben minimalizálni próbálja nekünk ezeket az értékeket a saját győzelmének érdekében. Ezért MAX-nak szükséges lesz egy 10
2.5. Kiértékelő függvények stratégia, ami figyelembe veszi MIN-nek a lehetséges lépéseit is, majd újra a sajátjait, egészen addig amíg a helyzetnek megfelelő végállapotba nem érünk. Tehát a stratégiának feltételeznie kell, hogy az ellenfél minden helyzetben optimálisan dönt. 2.2. ábra. A van MAX szerepében, és B MIN szerepében. Az algoritmus működését láthatjuk egy egyszerűsített esetben, a játék végéhez közelítve. Azokban az esetekben, ahol a túl nagy számítási igény miatt nincs lehetőségünk egészen a levelekig vizsgálni a teljes játékfát, megjelentek az igények a koncepció továbbfejlesztésére. Ennek egyik lehetséges módja a kiértékelő függvények alkalmazása. 2.5. Kiértékelő függvények A kiértékelő függvények bevezetésével lehetővé vált, hogy ne kelljen a teljes játékfát vizsgálni. Ezt úgy oldják meg, hogy egy bizonyos mélységben (ahogy a számítási kapacitás engedi) elvágják a fát, és heurisztikákra támaszkodva, egy jósági vagy hasznossági értéket rendelnek az adott álláshoz. Ehhez általában az adott játék alapos ismerete szükséges. Az a célja a kiértékelő függvénynek, hogy értékeket rendeljen a csúcsokhoz, attól függően, hogy ki áll éppen nyerésre. Minél nagyobb ez az érték, annál esélyesebb, hogy MAX fog nyerni, viszont a kisebb értékek MIN-nek kedveznek. Így már nem csak 1,0 vagy -1 értékeink lesznek, és már nem a biztos győzelmet, vagy a hiányát fogják jelenteni, hanem csak becsült értékek arra, hogy ki áll jobban az adott helyzetben. 11
2.6. Alfa-béta nyesés 2.3. ábra. Az ábra a minimax algoritmus működésére a kiértékelő függvényekkel kombinálva. Az algoritmus a lehető legjobb lépéshez tartozó operátort adja vissza, vagyis ahhoz a lépéshez tartozó operátort, amelyik a legnagyobb hasznossági értékkel rendelkező eredményre vezet, feltételezve, hogy az ellenfél úgy játszik, hogy minimalizálja a hasznossági értéket. A MAX-ÉRTÉK és MIN-ÉRTÉK függvények végigmennek a teljes játékfán, le egészen a levélcsomópontokig, hogy meghatározzák a csomópont felfelé terjesztett értékét. [2] (2.3.) 2.6. Alfa-béta nyesés A minimax algoritmuson még ezen felül is lehet javítani, és szükség is van erre a lehetőségre, mivel a lépések száma exponenciálisan növekszik ahogy haladunk egyre mélyebben a fában. A lehetséges lépések miatt a fa egyre jobban szerteágazódik. Viszont az elágazások között vannak olyan esetek is, amelyekről már korábbi szinteken kiderülhetett, hogy nem fogunk azon a részfán tovább haladni, mégis vizsgáljuk őket. Az ilyen esetek elhagyására alkalmazható az alfa-béta nyesés. 12
2.6. Alfa-béta nyesés 2.4. ábra. Ábra az alfa-béta nyesés működéséről egy példában. Ugyanarra a részfára alkalmazva nyeséssel és nyesés nélkül is ugyanazt a levelet fogja visszaadni a minimax algoritmus, azonban nyesve jóval kevesebb területet kell bejárnunk és tovább vizsgálnunk. Abban az esetben, hagyhatunk el részfákat, ha azon a szinten, vagy korábbi szinteken, amelyek nem ehhez a lépéshez vezetnek, már találtunk az adott lépésnél jobbat. Ebben az esetben megállapíthatjuk, hogy ezt a lépést nem fogjuk választani, így az ezt követő részfát se, tehát nyugodtan lenyeshetjük ezt az ágat. Az ilyen ágak vizsgálata felesleges, mivel nem befolyásolják érdemben a minimax algoritmussal hozott döntést. 13
2.7. A Deep Blue és az AlphaGo programok összehasonlítása 2.5. ábra. Ábra az alfa-béta nyeséssel kiegészített kiértékelő függvényes minimax algoritmus megvalósításának a módjáról. 2.7. A Deep Blue és az AlphaGo programok összehasonlítása 2.7.1. A sakk és a go összehasonlítása A címben szereplő programok a sakkot és a go játékot játszó programoknak az első olyan változatai, amelyek győzedelmeskedni tudtak a saját játékaikban a világbajnokok felett, versenykeretek között. A sakkban 1997-ben győzte le Garry Kaszparovot az IBM által tervezett Deep Blue nevű program, viszont ekkor a go-ban még csak erős amatőr szinten játszó programok léteztek, és csak 2016-ban sikerült eljutni arra a szintre, hogy a világbajnokok szintjén tudjon játszani a játékban egy program. Ettől a ponttól kezdve a fejezet hátralevő részét a Christopher Burger munkája alapján dolgoztam fel. [3] 14
2.7. A Deep Blue és az AlphaGo programok összehasonlítása 2.6. ábra. Az esemény ahol győzedelmeskedett az AlphaGo. A játékok komplexitásának összehasonlítása A közel 20 évnyi időeltérés oka a számítási igényekben és a játék komplexitásában rejlik. Hiába egyszerűbbek a go szabályai a sakktól, ez teret hagy több lépésnek, míg a sakkban átlagosan 35 lehetséges lépés létezik az éppen következő játékos számára, addig a go-ban 250 körül mozog ez az érték. A go-játszmák általában hosszabb ideig is tartanak, átlagosan 150 lépésből áll egy játék, a sakk esetében pedig csak 80 lépés a partik átlagos hossza. A játékfák A számítási és tárolási igények kiszámításakor és összehasonlításakor tehát azt kell figyelembe vennünk, hogy a go-ban 10 761, míg a sakkban 10 120 darab lehetséges játék létezik. A teljes játékfa ismerete lehetővé tenné, hogy mindig a legjobb lépést válasszuk egy helyzetben. A játékfa bejárásának egyik eszköze a minimax algoritmus, melynek az a feladata, hogy minimalizálja a legrosszabb esetet, tehát az ellenfél ideális lépéseivel is számol. Ehhez szüksége van a teljes játékfára egészen a játékot megnyerő lépésekig. Így ez az algoritmus tökéletes eszköz a Tic-tac-toe-hoz és más feldolgozható méretű játékfával rendelkező játékokhoz, azonban a sakkhoz és a go-hoz a játékfa mérete miatt többre van szükség. 15
2.7. A Deep Blue és az AlphaGo programok összehasonlítása 2.7.2. A Deep Blue működése A minimax A Deep Blue működése a minimax algoritmuson és a kiértékelő függvényeken alapul. Az alapvető koncepció az volt, hogy előre megvizsgál annyi lehetséges lépést amennyit tud, (ez általában legalább 6 lépés volt a Deep Blue esetében), majd az állásra alkalmazta a kiértékelő függvényt, mely egy jósági értéket rendelt az álláshoz, ezzel helyettesítve a lépések alatt lévő részfákat. Ezen értékek felhasználásával a minimax algoritmust már lehetett alkalmazni a teljes gráf ismerete nélkül is. A kiértékelő függvény A kiértékelő függvény valamilyen formájú heurisztikára támaszkodik. Minél közelebb kerülünk a játék végéhez, annál könnyebb jó kiértékelő függvényeket gyártani, ugyanis ha belegondolunk, könnyebben meg tudjuk állapítani egy állásról, hogy ki áll nyerésre, ha már közeledik a befejező lépés, azonban a játék elején még nagyon nehéz megmondani, hogy ki fog nyerni. Valószínűleg közel lehetetlen tökéletes kiértékelő függvényt tervezni, azonban egy jobb függvény egy erősebb játékost eredményez. Viszont amíg egy másikhoz képest fele olyan jó kereső függvény kétszer annyi idő alatt járja be a fát, addig egy fele olyan jó kiértékelő függvény klasszisokkal gyengébben teljesít. Két meghatározó tényezője van a mesterséges intelligencia erősségének: A számítási erő. Ha több számítást tud elvégezni adott idő alatt, akkor az mélyebb keresésnek nyit teret a fában, ami végül jobb becslésekhez vezet a kiértékelő függvényt alkalmazva. A Deep Blue szuperszámítógépen futott, ezért nagy számítási kapacitás állt a rendelkezésére. A kiértékelő függvény minősége. Az IBM óriási figyelmet fordított a kiértékelő függvény tervezésére. A függvény több mint 8000 darab alfüggvényből állt, rengeteg speciális eset kezelésére felkészítve. Több mint 4000 nyitási pozíciót dolgozott fel, 700.000 nagymesteri játékot vizsgálva. A program sakktudásának finomhangolását nagymesterek végezték el. Összességében a Deep Blue nagymértékben támaszkodott a nyers erőre, és a hosszas, nagy erőfeszítések árán megírt heurisztikára. A go-ra viszont ugyanezt a megközelítést nem lehetett alkalmazni a játékfa hatványozott szétágazása miatt, valamint amiatt, mivel a végjátékban a játék sokkal bonyolultabbá válik, így nehezebb jó kiértékelő függvényeket írni rá. 16
2.7. A Deep Blue és az AlphaGo programok összehasonlítása 2.7.3. Az AlphaGo működése A Monte Carlo Tree Search Ennek tudatában egy új megközelítéssel próbálkoztak, és ez a Monte Carlo (MCTS) keresési módszer. Az elképzelés mögött az áll, hogy a játék aktuális állásából szimulációkat indítanak, amíg el nem érnek egy végpontot valamelyik játékos győzelmével. Először a szimulációkban teljesen véletlenek a lépések mindkét fél részéről. Azonban minden szimulációban letárolnak néhány adatot, például, hogy melyik állást hányszor választották, és ezek hányszor vezettek győzelemhez. Ezek az adatok fogják később befolyásolni a választásokat, és egyre kevésbé lesznek véletlenszerűek a lépések. Minél több szimulációt futtatunk le az algoritmus annál jobban ki tudja választani a győzelemhez vezető lépéseket. Érzékelhető, hogy a szimulációk gyarapodásával az algoritmus egyre jobban közelít az optimális játékhoz. 2.7. ábra. Ábra a bejárandó fáról. A felfedezés és kihasználás Az MCTS egyik fontos tényezője a felfedezés és kihasználás (exploration/exploitation) egyensúlya. Ez azt jelenti, hogy az MCTS hajlamos túl kevés szimuláció után következtetéseket levonni arra vonatkozóan, hogy az adott lépés tényleg nyerő álláshoz vezet-e, ezért érdemesebb egy új komponens behozatala, amely hatására a jól bevált lépések helyett esetleg újakkal is próbálkozhat, hátha talál jobb megoldást. Az eddigi megközelítések Az MCTS érdekessége az, hogy kezdetben nem szükséges megadnunk semmilyen taktikát a játékra vonatkozóan. A Deep Blue bonyolult kiértékelő függvényeket használt, ezzel ellentétben az MCTS-nek csak néhány számot kell követnie, és a szimulációkat. Ennek ellenére meglehetősen sok szimuláció lefuttatására van szükség ahhoz, hogy az algoritmusunk pontos legyen. 17
2.7. A Deep Blue és az AlphaGo programok összehasonlítása Az AlphaGo előtti legerősebb go programok (Fuego, Pachi, Zen és Crazy Stone) mind MCTS-t használtak, azonban kézzel írott szabályokat is írtak a jobb lépésválasztás érdekében. Ezek mind egy erős amatőr szintjén játszottak. Az AlphaGo újszerű megközelítése viszont kiaknázta a gépi tanulás által nyújtott eszközöket, hogy ne legyen szükség kézzel írt szabályok használatára. A program három különböző neurális hálót használ egy fa kereséssel összekötve. Működésének megismerése érdekében azonban néhány fogalmat tisztáznunk kell. Gépi tanulás A gépi tanulás egy adaptív eljárás, amely a rendszerben olyan változásokat hoz létre, hogy a következő ciklusban megjelenő azonos problémát a rendszer már helyesebben oldja meg. A tanulási folyamat paraméterek beállítását, illetve csoportosítást, osztályozást, statisztikailag szignifikáns szabályszerűségek feltárását teszi lehetővé a rendszer számára. [4] Neurális hálózatok A mesterséges neurális hálózatokat gyakran használják gépi tanulásban a nagy adatmennyiséget feldolgozó képességük miatt. A neurális hálók több réteget tartalmaznak, és ezek több paramétert, melyeknek értékeit a tanuló adatokra kell hangolni. A neurális hálók rétegei neuronokat tartalmaznak, ezeknek a bementi értékük az előző réteg kimeneti értéke, majd ezeket az értékeket együtt figyelik. Ez a fajta viselkedés tényleges biológiai neuronok viselkedése alapján lett tervezve, ahonnan a nevük is ered. Konvolúciós neurális hálózatok A neurális hálók egyik típusa a konvolúciós neurális hálózat, amely kifejezetten jól használható képfeldolgozási feladatokban, például az arc, vagy rendszámtábla felismerésnél. A konvolúciós hálózatok jól használhatóak az emberek által könnyen, ösztönösen megoldható feladatokra, ami a go-nál is kifejezetten hasznos. Az AlphaGo megvalósítása Az AlphaGo működése két fő komponensre bontható fel. Egy fakeresési eljárásra, és a konvolúciós hálózatokra, amely a fa keresést irányítja. A konvolúciós hálózatok lényegében nagyon hasonlóak a Deep Blue kiértékelő függvényeihez, abban viszont eltérnek, hogy ezeket nem tervezték, hanem maguktól tanulták meg a játékot, egyfajta ösztönösséget biztosítva így a működéshez. Összesen három konvolúciós hálózatot tanít be a rendszer, két különböző típusból. Két irányválasztó hálózat, és egy értékhálózat. Mindkét fajta hálózatnak a bemeneti értékei képek a jelenlegi játékállásról. Az érték hálózat Az értékhálózat megbecsüli a játék állásának az értékét. Az input a teljes játék tábla, az output egyetlen szám, amely a nyerési esélyt takarja. 18
2.7. A Deep Blue és az AlphaGo programok összehasonlítása Az irány hálózat Az irányhálózatok útmutatást adnak arra nézve, hogy milyen lépést válasszon a program az adott tábla alapján. Az output egy valószínűségi érték, hozzárendelve az összes lehetséges lépéshez. A nagyobb valószínűségi értékekkel rendelkező lépések nagyobb eséllyel vezetnek győzelemhez. Az irány hálózatok pontossága Az irányító hálózat 30 millió pozícióból lett betanítva profi go játékosok meccsei alapján, melyek elérhetőek voltak egy nyílt go szerveren. Az AlphaGo csapata végzett egy tesztet ennek a hálózatnak az alkalmazásával, amely során 57% pontossággal meg tudták jósolni, hogy a két játékos közül ki fogja megnyerni a játszmát. Egy kisebb, de gyorsabb irányító hálózatot is létrehoztak. Ennek pontossága csak 24% volt, azonban a döntéshozatal 3 milliszekundum helyett 2 mikromásodperc alatt zajlott le. Ez egy 1500-szoros gyorsításnak felel meg. Az irány hálózatok további tanítása Mindeddig az irányító hálózatokat csak az ember által játszott játszmák kimenetelének megjóslására használták, azonban a fő célja nem ez, hanem hogy optimális döntéseket hozzon, amelyek segítenek megnyerni a játékot. Innentől az irányító hálózatokat már úgy fejlesztették tovább, hogy egymás ellen játszatták őket, ezeket a meccseket pedig felhasználták a további tanuláshoz. Ez a fajta megközelítés nem tekinthető teljesen újnak, ugyanis már használták az 1992-es TD-Gammon-ban. Ez egy ostábla játékot játszó program, amit szintén az IBM fejlesztett, akárcsak a Deep Blue-t, és abban az időben elérte a korában legjobban teljesítő emberi játékos szintjét. Az irány hálózat teljesítménye Az AlphaGo csapata kipróbálta, hogy egyedül ezekre az irányító hálózatokra támaszkodva, mindig a legnagyobb eséllyel rendelkező lépést választva- ami így csak 3 ezredmásodpercet vett igénybe- milyen eredményeket érhet el. A legjobban teljesítő irányító hálózatukat játszatták, az akkori legjobb nyílt forráskódú go program, a Pachi ellen, mely 100.000 MCTS szimulációval számolt minden körben. Az eredmény 85%-ban az AlphaGo irányító hálózatának a javára dőlt el. Ez azért is kiemelkedő, mert egy gyors, előrecsatolt rendszer képes volt túlteljesíteni egy erősen keresésre épülő rendszert. Ez is mutatja, hogy a go-ban mennyire szükséges is az ösztönösség. Az érték hálózat szintén 30 millió játék pozíció alapján lett betanítva, de ezeket az alatt szerezte, amíg az irányító hálózat saját maga ellen játszott. Emlékeztetőül, az érték hálózat a jelenlegi álláshoz rendeli hozzá a nyerési esélyt, amely nagy mértékben hasonlít a kiértékelő függvényekhez, annyi kivétellel, hogy ezek tanultak, nem pedig terveztek. Azonban a tendencia, hogy a játék vége felé könnyebb pontosabb értékeket mondani itt is észrevehető. 19
2.7. A Deep Blue és az AlphaGo programok összehasonlítása A technikák összeállása Ha összerakjuk az eddig megismert technikákat akkor megkapjuk, hogy hogyan is játszik az AlphaGo. A keresési eljárása hasonló az MCTS-hez, azonban itt az eddig megismert három hálózat alapján hozza a döntéseket. A Deep Blue-hoz hasonlóan az AlphaGo is kiértékeli az állást, viszont ez az eredmény a keveréke az érték hálózatnak és a gyors irányító hálózat által lejátszott, saját maga elleni szimulációnak. A csapat tesztelte külön-külön is ezeket, azonban mégis a kombinációjuk adta ki a legjobb eredményt, tehát mindkettő ugyanannyira fontos. A lassú irányító hálózat is hozzájárult a fában való kereséshez. Ez a rész felelős többnyire a felfedezés és kihasználás egyensúlyáért. A hálózat visszaad egy értéket minden egyes lehetséges lépéshez, majd leosztja ezeket annak a számával, hogy hányszor lépte már ezt a lépést. Ezzel hátrányba helyezi egy kicsit a túl gyakran választott lépéseket, teret hagyva az új lépések kipróbálásának. 2.7.4. A Deep Blue és AlphaGo működésének összehasnolítása Összegezve a legnagyobb különbségeket a Deep Blue és az AlphaGo között, arra a következtetésre juthatunk, hogy a sakkban elég volt egyedül a kézzel írott heurisztikára, és egy egyszerű keresésre támaszkodni, és a sakk esetén a játékfa, még hatalmas mérete ellenére is kezelhető volt. A go-nál nem lehetett ugyanezt a megközelítést alkalmazni, hiába jelentett azonban nagy előrelépést az MCTS megoldás, egyedül erre támaszkodva még nem lehetett volna áttörést elérni. Az AlphaGo sajátosságai Ami az AlphaGo-t rendkívülivé teszi az a tanulási komponens, ami kiváltja a kézzel írt heurisztikákat. Azzal, hogy saját maga ellen játszatják egyre csak erősebb és erősebb lesz, ami reményt nyújt, hogy talán más mesterséges intelligenciabeli problémákra is használható lehet ez a módszer. Ami még szintén említésre méltó, hogy a Deep Blue által vizsgált pozíciók mennyiségének csak a töredéke is elég az AlphaGo-nak, azonban ezek minőségükben sokkal precízebbek, és összességében így jobb játéktudást eredményeznek. 2.7.5. Jövőbeli lehetőségek az AlphaGo megközelítésének alapján Az AlphaGo-nak szüksége volt egy hatalmas mennyiségű minta játékra először, ami szerencsére ebben az esetben adott volt, azonban más problémák esetén nem biztos, hogy mindig alkalmunk lesz hozzáférni ilyenekhez. Abból kifolyólag, hogy kezdetben emberi játékokból indult ki, a program gondolkozása túlzottan hasonlíthat az emberi gondolkozáshoz, így kiszorítva a lehetőséget, hogyha csak saját maga ellen játszana, akkor új megközelítéssel, stratégiákkal próbálna meg nekikezdeni a játéknak. A TD-Gammon esetében ez merült fel, ugyanis az csak saját maga elleni játékból merítette az adatait, és így felfedezett olyan stratégiákat amelyeket az emberek azelőtt nem használtak, így fejlesztve az ostábla játék elméletét. 20
2.8. Az amőba története A tény, hogy egymástól függetlenül tanult a neurális hálózat és a fa keresés, lehetséges, hogy létezik egy, a jelenleginél jobb kombinációja a két komponens összekapcsolásának. A konvolúciós hálózatok egy speciális fajtái a neurális hálóknak, ezért nem feltétlenül használhatóak más játékokhoz, problémákhoz. 2.8. Az amőba története Az amőba egy körülbelül ezeréves játék, amit Japánban játszottak először. Amőbaként csak Magyarországon ismert, eredeti elnevezése a gomoku, de 5 in-a-row néven is szokták emlegetni. A játékot eredetileg a 19x19-es go táblán játszották és a rácsvonalakra tették le a játékosok a jeleket, de később ezt lecsökkentették 15x15-ösre. A hétköznapokban nyugodtan lehet tollal és papírral játszani az amőbát, hiszen a lerakott jeleket nem mozdíthatjuk már el miután letettük őket, bár eredetileg a játékban 100-100 kő lerakása után a játék átváltott a lerakott jelek szabad mezőkre való mozgatására felváltva. Mivel 1994-ben L. Victor Allis bebizonyította algoritmusával, hogy létezik nyerő stratégia 15x15-ös pályára, ezért bevezettek megkötéseket a kezdésekre, mint pl.: a Renju, Pente és a Swap. [5] 2.8.1. Az amőba szabályai 2009 óta elkezdték újra megrendezni két évente az amőba világbajnokságot, ezeken a kezdő megkötésre a swap2 -t használják. A swap2 nyitás úgy korlátozza a játékosokat, hogy a kezdő játékos 3 követ rak le, 2 feketét, és 1 fehéret, ezután az ellenfele választhat, hogy folytatja, vagy a fehérrel vagy a feketével, vagy dönthet úgy is, hogy lehelyez még 1-1 követ, viszont ekkor az ellenfél köteles színt választani már. Még fontos megkötés az is, hogy az ötnél hosszabb azonos alakzatok nem számítanak győzelemnek. Ezek a megkötések kiegyenlítetté teszik a kezdést, és a kezdő játékosnak már nem ad leküzdhetetlen előnyt a másik játékossal szemben. A magyar játékosok kiemelkedően jól szerepelnek, hiszen a 2009 óta megrendezett négy világbajnokságból hármat magyarok nyertek, Demján Attila és Dupszki Rudolf. A programomban nem tettem megkötéseket a nyitásra, ugyanis nem nyer minden esetben nyitó játékosként a program, szóval a körülmények a mezei játékosoknak sokkal hétköznapibbak, ezért közelebbi, élvezhetőbb lehet számukra a játék. 21
3. fejezet Fejlesztői dokumentáció 3.1. Használt programozási eszközök 3.1.1. A választott eszközök A programkód elkészítéséhez a C nyelvet, a grafikus ábrázoláshoz pedig az OpenGL-t választottam. A grafikai rész alatt néhány helyen C++ is alkalmazásra került a kód során. A programkód implementálása Először a C program került leimplementálásra egy konzolos verzióval a könnyebb debuggolás és fejlesztés érdekében, ebben látszik a gondolkodása, hogy miért azokat a lépéseket választotta, és mely lehetőségekből. A grafika implementálása Miután a kód az általam eltervezettként működött, hozzáláttam a grafika elkészítéséhez. Itt a Számítógépi grafika tárgyon megismert Glut, Soil és glfw könyvtárakat használtam. Tábla feletti mozgást és forgatást is megvalósítottam, hogy jobb élményt nyújthasson. Ennek érdekében viszont az egér kattintását és mozgását le kellett képeznem, hogy átszámolja a táblán való pozíciókra. Így nem közvetlenül a táblán kell kattintani, hanem az ablakon, viszont ezzel nyerünk az ablak reszponzivitását illetően, hisz így átméretezhetjük ahogy szeretnénk, valamint mozoghatunk és forgathatjuk, hogy más szögből lássuk, ami sokkal emberközelibb mintha csak a teljes statikus tábla foglalná el az ablak egészét. A látvány és élménybeli löket pedig úgy gondoltam, hogy megéri azt az áldozatot, hogy rövid idő alatt meg kell szokni a leképzéssel való korrigálást. 3.1.2. A programok egyesítése A grafika és a C program összeollózásával nem volt probléma, kihasználva a C++ visszafelé kompatibilitását. Kisebb átalakításokra szükség volt a GlutMainLoop() szükségessége miatt, így a display() függvényben került elhelyezésre a kód érdemleges része a következő lépést illetően. 22
3.2. A játéktér felépítése 3.3. A gép lépésének kiválasztása A játéktér egy const Size hosszúságú négyzet. Ezek értéke alapból inicializálódik 0 - ra. A teljes játékteret körbeveszi egy 4-es vastagságú fal minden irányból, melyek az inicializáció során 3 -as értékkel kerülnek feltöltésre, később a fal menti számolásoknál lesz majd jelentősége ennek a fajta megoldásnak. A falak értékeit a játékosok nem írhatják át, és csak a súlyokat kiosztó algoritmus veszi figyelembe azokban a speciális esetekben, amikor a játék a fal közelébe kerül már. A játéktéren a cellák tartalma 0;1;2 értéket vehet fel, reprezentálva az üres, a O és az X állapotokat rendre. 3.3. A gép lépésének kiválasztása A gép először végighalad az összes mezőn, és a 0 -t tartalmazó mezőkre meghívja a getvalue() függvényt. A függvény a mezőkhöz egy értéket rendel, mely megadja, hogy a lépés mennyire lenne hasznos a számára. 3.3.1. A getvalue() A függvényen belül más függvényhívások történnek, melyek megvizsgálják a mezőhöz tartozó szomszédos mezőket minden irányból, ezek a calcvaluerow() és calcvaluedial() és a tábla elforgatásával, és tükrözésével történnek. A két előbbi függvényt egybe is vonhattam volna, azonban úgy véltem, hogy ez az érthetőség rovására menne. Ezek a függvények tartalmazzák ugyanis a súlyokat, és ezek fognak lefutni a legtöbbször a program során, így szerettem volna elkerülni a felesleges indexléptetéseket és számolást. Folyamatosan tárolásra kerül a három legmagasabb mező értéke, és indexe. 3.1. ábra. Az ábrán az algoritmus kódja, és hozzárendelt súlyok működése látható, valamint, hogy melyik helyzetben hívódna meg a hozzájuk tartozó kódrészlet. 3.3.2. A calcbestmoves() A táblán végighaladva a kapott értékeket folyamatosan vizsgáljuk, ha olyan értéket kapunk ami nagyobb az eddigi harmadik legnagyobbtól, akkor annak a helyére letárolja. 23
3.3. A gép lépésének kiválasztása 3.2. ábra. Diagram a lépéshozatalról. A sorthighestvalues() Amikor talál ilyet, meghívja a sorthighestvalues() függvényt, ami a legnagyobb értékeket összehasonlítja, és egy tömbbe rendezi, és cseréli a hozzájuk tartozó értéket és indexeket. 3.3.3. A compmovesmm() Miután megkaptuk a teljes iteráció után a három legnagyobb értéket ezeket összehasonlítva eldöntjük, hogy érdemes-e foglalkozni a második és harmadik legjobb lépéssel. Amennyiben legalább fele olyan jónak ítéljük meg a lépéseket mint az elsőt, akkor számolunk velük is. A használhatónak vélt helyekre megnézzük, hogy a saját algoritmusunk szerint az ellenfélnek mennyire lenne jó lépése, és ezekből választjuk ki a legkisebbet. Kivételként kezelendő az az eset, amikor az ellenfél az utolsó lépését helyezné le, mert akkor alapvetően azt akadályozza meg. Ez alól természetesen kivétel, ha nekünk lenne esélyünk megnyerni a játékot, de azt az esetet nem szükséges leimplementálnunk, mert az összehasonlítós előszűrés kiküszöböli. 3.3.4. A gép játékstílusa A legjobb mezőkre való szűrés miatt az algoritmusunk továbbra is agresszív stílusban játszik, de a minimalizáció miatt, mégis a védekezőbb lépéseket választja közülük, egy 24
3.5. Játék a fal közelében rugalmas játékost szimulálva. Az ellenfél lépésének meghatározása is ugyanazzal a kóddal történik, mint a gép lépésének a meghatározása, csak a táblát invertáljuk, hogy a kódot egészében alkalmazhassuk rá, majd ha végeztünk ezzel visszavesszük mindkét lépést és visszainvertáljuk a táblát a következő iteráció előtt. 3.4. A játék vége A játék végéért az isover() függvény felelős. Megvizsgálja, hogy van-e öt darab egyes vagy kettes, és attól függően, hogy melyik játékoshoz tartozik leállítja a játékot. Ez minden lépésváltás közben lefut. A tábla megvizsgálása a lépéshez hasonlóan elforgatással, és tükrözéssel történik. 3.5. Játék a fal közelében 3.5.1. A probléma a fal melletti játékkal Az előbbiekben, mint már említésre került, a játékteret egy a játékosok számára láthatatlan négyes vastagságú fal veszi körbe. A kiértékelő algoritmus jól kezeli a falak és üres mezők közötti különbséget, azonban önmagában ez nem elég ahhoz, hogy teljesen elkerülje a fal felé való terjeszkedést. 3.5.2. A megoldása A fal menti értékeket a kiértékelés közben leosztja hárommal vagy kettővel attól függően, hogy közvetlenül a fal mellett vagy annak közvetlen szomszédjában. Ez az apró korrigálás elég ahhoz, hogy eltántorítsa a falhoz közel eső lépések választásától, viszont, ha nyerő pozíció alakul ki (mint a két oldalt nyitott négyesre lehetőség, vagy a tényleges győzelem a fal mentén), az osztott értékek még mindig jóval jobb lépésnek bizonyuljanak. Fontossága abban is rejlik, hogy ne legyen túl szigorú az értékek osztása, hiszen az ellenfél nyerő helyzeteit is le kell tudni zárni. 25
3.6. A heurisztika 3.6. A heurisztika A jó kiértékelő függvény nagyban befolyásolja mesterséges intelligenciánk teljesítményét a mesterséges intelligenciánknak ahogy azt a Deep Blue és AlphaGo esetében is láthattuk. Ezért döntöttem úgy, hogy erre nagyobb figyelmet szeretnék szentelni, és konkrét állásokat lekezelni, egy egyszerűbb környezetében lévő jelek számolásán alapuló algoritmus helyett. 3.6.1. A heurisztika megvalósítása A lehetséges játékállásokat letároltam, majd összehasonlítás alapján megnézem melyikre illeszkedik, és egy általam tapasztalati úton meghatározott súlyt rendelek hozzá. Folyamatosan a tábla i és j indexszel rendelkező eleméhez képest viszonyítva nézzük a játékállásokat, erre már nem kell kikötést tennünk, hiszen, csak akkor jut el ide az algoritmus, ha az a mező üres, hiszen egyébként nem érdemes vele foglalkoznunk. Ebben az esetben csak a sorban nézi a lehetőségeket, tehát még háromszor meg kell majd hívnunk a függvényt a forgatások és tükrözések után, és a currentvalue változót, azaz a mezőhöz tartozó értéket ennek a négy hívásnak az összegéből kapjuk meg, miután minden irányból megkaptuk a helyzet hasznosságát. 3.3. ábra. Az első kielemzett mintalépés. 3.6.2. Első példa a heurisztikára Az ábrán az algoritmus lépésválasztási döntése látható, ehhez készítettem egy illusztrációt, mely segíthet megérteni a működését. A barna bekeretezett lépésére, a program 26
3.6. A heurisztika a bekeretezett kék csillaghoz tartozó mezőt vélte jobbnak. Ránézésre a fekete csillag se lenne rossz lépés, azonban az algoritmus mégis eldobja, hiszen fele olyan jónak se ítéli meg. A fekete csillag értéke A fekete csillaghoz tartozó mező értéke a forráskód segítségével megállapítható. Ez az érték pedig 15. A kettes számmal ellátott fekete kerethez tartozó mintázatot a zárt hármasok csoportjába soroltam be, hiszen ha a másik oldalról zárjuk le, akkor abból az ellenfél már nem tud több lehetőséget kihozni, hiába mégis egy nyitott hármasra emlékeztet az alakja, de a nem közvetlen távolabbi környezete miatt, mégis lekorlátozható és zártnak tekinthető. A súlya így jóval kevesebbet ér, mint egy nyitott hármas, hiszen azokat már nem lehet túlzottan figyelmen kívül hagyni. Mindezek függvényében tehát általánosságban véve nem éri meg azokat a lépéseket választani, hiszen az alakzat teljes lezárása később még egy lépést igénybe fog venni, amit megelőzhetnénk. A kék csillag értéke A kék keretbe foglalt lépés tehát azért kedvezőbb, mert az előbbi indokok alapján a súlya így jóval nagyobb mértékű a nyitott hármas lezárása miatt. Ennek eléréséhez a környezetében tartózkodó cellák értékét kellett vizsgálni, beleértve azokat is, amelyek nem feltétlenül az alakzat két végén szerepelnek. A döntés Tehát a program a három legkedvezőbb lépés helyett csak a legjobbat veszi figyelembe, mivel a többi meg se közelíti az értékét, így nincs más, amiből minimalizálni lehetne. Ezért lépte meg a kék csillagot a lépésének anélkül, hogy más lépésen komolyabban gondolkozott volna. 27
3.6. A heurisztika 3.6.3. Második példa a heurisztikára Ebben az esetben látható, hogy a két lépés közül a kedvezőtlenebbet választja ki, mivel az ellenfélnek a lépése (enemyvalue) kisebb eredményhez vezetne. A saját értékeit látható, ahogyan több irányból összeadódó kisebb értékekből teszi össze. 3.4. ábra. A második kielemzett mintalépés. A csillagok értékei A kék csillagnál három irányból 6+2+2 értékek teszik ki a tízet. A fekete csillagnál a nyitott hármas értéke, mivel még könnyű lenne megállítani, ezért csak tíz. Azért ajánlja fel az alakzat azon oldalát második legjobb lépésnek, mert ahhoz az oldalhoz tartozik már egy nyitott kettes, így plusz kettővel megdobja az értékét. A döntés Látható, hogy szándékosan a rosszabb lépést választja, hiszen a jobb lépés az ellenfélnek kedvezőbb alakzat lezárására kényszerítené rá. Mivel a legjobb lépésekből történik a szűrés, ezért előbb-utóbb az algoritmus meg fogja lépni az itt kedvezőbb lépést is. Előbb azonban megvárja, amíg több hasonló fenyegetéssel kecsegtető más lépésre is esély tárul, így azokat láncba szedve fogja meglépni őket. Ennek következtében nagyobb kényszerítőlépés-láncot tud majd végrehajtani, ami nagyobb eséllyel vezet győzelemhez. 28
3.7. A játékmódok 3.7. A játékmódok A nehézségi fokozatok a következőképpen alakulnak: Könnyű Az eddig ismertetett döntéshozatal, azaz a három legjobb lépésből választja ki azt, amelyik az ellenfélnek a legkevésbé kedvező lépéshez vezet. Közepes Pusztán a heurisztikára alapul, azért lehet jobb ez, mint a könnyű nehézségi szint, mivel a játéknak ez volt az első verziója, így a súlyok optimalizálása ennek az algoritmusnak az elvére történt. Nehéz Az eddig ismertetett algoritmus kódja, annyi eltéréssel, hogy csak a legjobb két lépésre van korlátozva a három helyett, kevesebb teret hagyva így a hibázásnak, jelentősen növelve az agresszivitást. Játékos a játékos ellen A játék teljes élvezhetőségért, és az alkalmazás multifunkcióssága kedvéért, két játékos egymás elleni játékára is adtam lehetőséget. 3.5. ábra. A menü, ahol a játékmódokat lehet választani. 3.7.1. Nehézségi fokozatok sorrendisége A játékmódok egymás elleni játékából egyik se került ki abszolút győztesként, tehát túl nagy nehézségbeli eltérés nincs a fokozatok között, ezt a sorrendet véltem a legjobbnak. Az az eset se állt fenn, hogy mindig a kezdő játékos nyert, és mivel az algoritmus nem tartalmaz véletleneket, ezért a meccsek eredményéből nem tudtam volna reális statisztikát készíteni a módok nehézségét illetően. 29
3.8. A grafikai működés 3.8.1. A tábla megvalósítása 3.8. A grafikai működés A grafikában a leginkább feladat specifikus tényező a csillag modellek jó helyre történő lerakása volt. A csillag modelljét és textúráját a hagyományos módszerrel töltöttem be, amelyekhez a már meglévő függvényeket használtam fel. A tábla 100 100 intervallumon van kifeszítve, és erre történik a képernyőn való kattintás leképezése. Ezt a táblát, akárcsak a képernyőt 20x20 részre osztottam fel, és ezeket feleltettem meg egymásnak. A display() függvény folyamatosan frissíti a grafikus megjelenést a GlutMainLoop() miatt, így a megjelenítéshez elég volt csak a tábla tömbjét kirajzolni. Annak függvényében, hogy egyes vagy kettes (azaz saját vagy gép lépése) az értéke a cellának, választja ki a modellt, csak másfajta textúrával. 3.8.2. Kattintás a táblán A MouseClick() függvény visszaadja az egér pozícióját kattintás esetén, ez felel a mezőre való lerakásért. Amennyiben a tábla felosztott részei közül valamelyikre kattint, és az a mező még nem foglalt, akkor annak a cellának az értékét átírja, amelyet a display így megjelenít, és átadja a lépést a következő játékosnak. 3.8.3. Kattintás a menüben A MouseClick() függvényt használtam még a menü megvalósításához is, itt csak az új játék nehézségi szintjének a meghatározása a feladata. Ha valamelyik gombra eső tartományba esik a kattintás, akkor inicializálja a táblát, kezdőállapotba állítja a változókat, és a megfelelő játékmódot hívja meg. 3.8.4. Az indikátor működése Az indikátor-csillag folyamatos reprezentálásért a glutpassivemotionfunc() felelős. Ez mindig az adott pillanatban visszaadja a képernyőhöz tartozó x és y koordinátát. A működési elve hasonló a MouseClick()-hez, azonban mivel itt csak egy mezőt kell megjeleníteni, ezért nem egyezik meg teljesen, hiszen a MouseClick()-nél, ha egy mezőre leraktunk egy lépést, akkor onnantól a játék végéig azt már nem kellett módosítanunk. Ennek a függvénynek a működése azon az elven alapul, hogy ha táblához tartozó üres cella felé ér, akkor először egy, az előzőtől eltérő tömböt kinulláz, hogy eltüntesse az előző indikátort, ha volt, és aztán növeli a cella értékét. A display() ezt a tömböt kapja meg kirajzolásra, és a működése miatt így mindig csak egy csillagot fog mutatni. 3.8.5. A menü A menü felépítése egy help változóhoz van kötve, melynek értéke igaz vagy hamis lehet. Alapvetően ez a változó igazra van állítva, hiszen a menü képernyő fogad minket. A menü még az isover() függvénnyel is össze van kötve, mely annak a vizsgálatért felelős, hogy véget ért-e a játék valamelyik játékos győzelmével, és ha igen akkor melyikével. Ha egy játékos nyert már, akkor attól függően hívja meg a textúrát, hogy ki nyert. Mivel nem csak a játékok végén ugorhat fel a menü, hanem az alkalmazás indításakor is, ahol még egy játékos se nyert, vagy egy játék közepén az F1 gomb segítségével, 30
3.8. A grafikai működés így három menü textúrát is el kellett készítenem annyi különbséggel, hogy a győzelem feliratokhoz más tartozik, vagy egyáltalán nincs ott. 3.8.6. A játékos elleni mód A három gép elleni mód mögött nem különböznek a grafikai hívások, azonban a játékos elleni mód létrehozásához változtatások voltak szükségesek. A MouseClick() függvénynek azt is vizsgálnia kell, hogy épp melyik játékos következik, és ahhoz mérten állítani a cella értékét, valamint a glutpassvemotionfunc()-nál is ugyanez a módosítás volt szükséges. Ennyi módosítás elég volt, hiszen a display() függvény a gép csillagait a tábla értékei alapján rajzolta ki, amit a gép kódja állított be, ezt helyettesíti a másik játékos kattintása. 31
3.9. Kísérletezések, jövőbeli tervek 3.9. Kísérletezések, jövőbeli tervek A döntés meghozatalakor a próbálgatások alapján felmerült egy, a minimaxra hasonlító koncepció, miszerint a gép az ellenfél legjobb lépése után a saját legjobb lépését válassza. Azonban, mivel a heurisztika a lépéseket értékelte és nem a játék állását, ezért a gép hajlamos volt az ellenfélnek engedni, hogy kiforrottabb alakzatai legyenek, (hiszen ezek lezárása több pontot ér) így sokszor engedte az ellenfelet nyerés közeli helyzetbe. Egy jobb játékosoknak ez elég a játék befejezéséhez, azonban amikor a gép diktálta a tempót, és ő volt az agresszor, akkor jobb eredményeket produkált. Lehetséges megvalósításként két ötletem támadt a probléma orvoslására: Az egyik a súlyok teljes átalakítása, hogy a támadó lépések jobban domináljanak, azonban nem szerettem volna a stabilan működő heurisztikát elrontani, így úgy véltem ez nem járható út. A másik megoldásnak a lépéskiértékelések táblakiértékeléssé konvertálása tűnt, méghozzá úgy, hogy az összes lépés értékét összeadnám, majd leinvertálva a táblát az ellenfélnek is megismételném, és azt kivonnám a saját értékemből. Azonban a lépéselőnnyel járó bizonytalansággal és módszer javításának/működésének garanciája nélkül, valamint hogy a program már így is elfogadható szinten játszik, azt a közvetkeztetést vontam le, hogy ennek implementálását célszerűbb a jövőre bízni, és más területeken érdemesebb csiszolgatni a projektet. 32
4. fejezet Összefoglalás A szakdolgozatom elméleti részében kifejtettem az általános megoldásokat a logikai játékokat játszó mesterséges intelligencia megvalósítására. Ezeket a Deep Blue és AlphaGo programok alapján mutattam be. Ezek a módszerek már bebizonyították, hogy van létjogosultságuk a mesterséges intelligencia területén. A Deep Blue mintáján bemutattam a minimax, alfa-béta nyesés, valamint a kézzel írott heurisztikák fontosságát. Az AlphaGo játék bemutatásán keresztül pedig az új megközelítést a logikai játékokhoz, a Monte Carlo fakeresést, a gépi tanulást, valamint a neurális hálózatokat, azon belül kiemelten a konvolúciós hálózatokat. Az általam választott játékhoz, az amőbához készítettem programot. Ebben törekedtem a jó heurisztika megvalósítására. Igyekeztem a saját játékstílusomat implementálni. Ehhez a lépések döntésének a meghozatalához megpróbáltam lekezelni a legtöbb játékállást, ami a mező közvetlen közelében van a sorban, és így súlyokat rendelni az adott mezőhöz. Mivel törekedtem az emberi játék imitálására, hogy minél jobban hasonlítson az én játékomhoz, ezért nem a megszokott minimax módszerrel valósítottam meg, hanem annak egy egyszerűbb változatával, ami nem tekint annyi lépéssel előrébb. Mivel minimax-szal megvalósított amőba programból már számos található, ami megvalósítja a nyerő stratégiát, így inkább a mellett döntöttem, hogy egy élvezetes emberközelibb mesterséges intelligenciát hozzak létre. 33
Irodalomjegyzék [1] Fekete István, Gregorics Tibor, Nagy Sára: Bevezetés a mesterséges intelligenciába, LSI Oktatóközpont oktatási segédlet, 1999. [2] Stuart J. Russell-Peter Norving: Mesterséges Intelligencia modern megközelítésben, Panem-Prentice Hall, 2000. [3] Tastehit, Christopher Burger, 2016. URL https://www.tastehit.com/blog/googledeepmind-alphago-how-it-works. [4] Intelligens számítási módszerek alkalmazása logikai játékokban, URL http://miau.gau.hu/miau/160/machine_learning.pdf. [5] Daniel Ford, Gomoku AI player, 2016 május 6. URL https://www.cs.cf.ac.uk/pats2/@archive_file?c=&p=file&p=526&n=final&f=1-1224795-final-report.pdf. 34