Automat stanów w General Game Playing. Gajusz Chmiel



Podobne dokumenty
Heurystyki. Strategie poszukiwań

Wyznaczanie strategii w grach

Działanie algorytmu oparte jest na minimalizacji funkcji celu jako suma funkcji kosztu ( ) oraz funkcji heurystycznej ( ).

Marcel Stankowski Wrocław, 23 czerwca 2009 INFORMATYKA SYSTEMÓW AUTONOMICZNYCH

Uniwersytet Zielonogórski Wydział Elektrotechniki, Informatyki i Telekomunikacji Instytut Sterowania i Systemów Informatycznych

Badania operacyjne: Wykład Zastosowanie kolorowania grafów w planowaniu produkcji typu no-idle

MAGICIAN. czyli General Game Playing w praktyce. General Game Playing

3. MINIMAX. Rysunek 1: Drzewo obrazujące przebieg gry.

Metody przeszukiwania

Algorytmy sztucznej inteligencji

Partition Search i gry z niezupełną informacją

Zajęcia nr. 3 notatki

Metody teorii gier. ALP520 - Wykład z Algorytmów Probabilistycznych p.2

Maciej Piotr Jankowski

O badaniach nad SZTUCZNĄ INTELIGENCJĄ

Aproksymacja funkcji a regresja symboliczna

Nierówność Krafta-McMillana, Kodowanie Huffmana

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Tworzenie gier na urządzenia mobilne

10. Wstęp do Teorii Gier

Metoda tabel semantycznych. Dedukcja drogi Watsonie, dedukcja... Definicja logicznej konsekwencji. Logika obliczeniowa.

AiSD zadanie trzecie

Metoda Tablic Semantycznych

O badaniach nad SZTUCZNĄ INTELIGENCJĄ

w analizie wyników badań eksperymentalnych, w problemach modelowania zjawisk fizycznych, w analizie obserwacji statystycznych.

Języki programowania zasady ich tworzenia

operacje porównania, a jeśli jest to konieczne ze względu na złe uporządkowanie porównywanych liczb zmieniamy ich kolejność, czyli przestawiamy je.

Wykład 11a. Składnia języka Klasycznego Rachunku Predykatów. Języki pierwszego rzędu.

Programowanie w języku C++ Grażyna Koba

Luty 2001 Algorytmy (4) 2000/2001

Algorytmy dla gier dwuosobowych

Układy VLSI Bramki 1.0

7. Pętle for. Przykłady

0 + 0 = 0, = 1, = 1, = 0.

Metody numeryczne w przykładach

Algorytmy i str ruktury danych. Metody algorytmiczne. Bartman Jacek

Spacery losowe generowanie realizacji procesu losowego

Złożoność obliczeniowa zadania, zestaw 2

Definicje. Algorytm to:

Metody Kompilacji Wykład 3

METODY DOWODZENIA TWIERDZEŃ I AUTOMATYZACJA ROZUMOWAŃ

Rozwiązywanie problemów metodą przeszukiwania

Heurystyczne metody przeszukiwania

Skalowalność obliczeń równoległych. Krzysztof Banaś Obliczenia Wysokiej Wydajności 1

Programowanie celowe #1

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat

Wyszukiwanie binarne

XQTav - reprezentacja diagramów przepływu prac w formacie SCUFL przy pomocy XQuery

Reprezentacje grafów nieskierowanych Reprezentacje grafów skierowanych. Wykład 2. Reprezentacja komputerowa grafów

Znajdowanie wyjścia z labiryntu

Zapisywanie algorytmów w języku programowania

Instrukcje dla zawodników

1. Algorytmy przeszukiwania. Przeszukiwanie wszerz i w głąb.

Obliczenia iteracyjne

Materiały dla finalistów

Scenariusz zajęć. Moduł VI. Projekt Gra logiczna zgadywanie liczby

Metody numeryczne Technika obliczeniowa i symulacyjna Sem. 2, EiT, 2014/2015

Algorytmy i struktury danych. Drzewa: BST, kopce. Letnie Warsztaty Matematyczno-Informatyczne

Wstęp do Sztucznej Inteligencji

SZTUCZNA INTELIGENCJA

ALGORYTMY I STRUKTURY DANYCH

Przeszukiwanie z nawrotami. Wykład 8. Przeszukiwanie z nawrotami. J. Cichoń, P. Kobylański Wstęp do Informatyki i Programowania 238 / 279

Złożoność informacyjna Kołmogorowa. Paweł Parys

Temat 1: Pojęcie gry, gry macierzowe: dominacje i punkty siodłowe

Planowanie drogi robota, algorytm A*

OSTASZEWSKI Paweł (55566) PAWLICKI Piotr (55567) Algorytmy i Struktury Danych PIŁA

Ekonometria - ćwiczenia 10

Programowanie i techniki algorytmiczne

Zbiory, relacje i funkcje

Andrzej Wiśniewski Logika I Materiały do wykładu dla studentów kognitywistyki. Wykład 9. Koniunkcyjne postacie normalne i rezolucja w KRZ

Optimizing Programs with Intended Semantics

Algorytmy ewolucyjne (3)

166 Wstęp do statystyki matematycznej

Wykład 4. Określimy teraz pewną ważną klasę pierścieni.

Logika Stosowana. Wykład 1 - Logika zdaniowa. Marcin Szczuka. Instytut Informatyki UW. Wykład monograficzny, semestr letni 2016/2017

Wykład 2. Drzewa zbalansowane AVL i 2-3-4

Programowanie w Logice Struktury danych (Lista 2)

Paradygmaty programowania

Algorytm poprawny jednoznaczny szczegółowy uniwersalny skończoność efektywność (sprawność) zmiennych liniowy warunkowy iteracyjny

9.9 Algorytmy przeglądu

Maszyna Turinga języki

Metoda Karnaugh. B A BC A

Ćwiczenie 1 Planowanie trasy robota mobilnego w siatce kwadratów pól - Algorytm A

Modele i narzędzia optymalizacji w systemach informatycznych zarządzania

< K (2) = ( Adams, John ), P (2) = adres bloku 2 > < K (1) = ( Aaron, Ed ), P (1) = adres bloku 1 >

Analiza wielokryterialna wstęp do zagadnienia

METODY ROZWIĄZYWANIA RÓWNAŃ NIELINIOWYCH

Optymalizacja systemów

Temat: Algorytm kompresji plików metodą Huffmana

lekcja 8a Gry komputerowe MasterMind

Klasa 2 INFORMATYKA. dla szkół ponadgimnazjalnych zakres rozszerzony. Założone osiągnięcia ucznia wymagania edukacyjne na. poszczególne oceny

M T E O T D O ZI Z E E A LG L O G R O Y R TM

OPTYMALIZACJA HARMONOGRAMOWANIA MONTAŻU SAMOCHODÓW Z ZASTOSOWANIEM PROGRAMOWANIA W LOGICE Z OGRANICZENIAMI

Szukanie rozwiązań funkcji uwikłanych (równań nieliniowych)

6. Pętle while. Przykłady

D. Miszczyńska, M.Miszczyński KBO UŁ 1 GRY KONFLIKTOWE GRY 2-OSOBOWE O SUMIE WYPŁAT ZERO

========================= Zapisujemy naszą funkcję kwadratową w postaci kanonicznej: 2

1 Metody rozwiązywania równań nieliniowych. Postawienie problemu

Zaawansowane algorytmy i struktury danych

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Transkrypt:

Automat stanów w General Game Playing Gajusz Chmiel 14 marca 2012

Streszczenie General Game Playing (GGP) jest dziedziną, której celem jest zbudowanie systemów zdolnych grać na zaawansowanym poziomie we wcześniej nieznane gry. Pierwszą częścią pracy jest wprowadzenie do zagadnienia. Zawiera ono omówienie powstania dziedziny oraz przedstawione i podsumowane dotychczasowe osiągnięcia. Postęp w dziedzinie GGP można zaobserwować na co rocznych konkursach, w których najlepsze systemy rywalizują o zwycięztwo, mierząć się w wielu różnych grach. W pierwszej części pracy największy nacisk kładę na omówienie tych technik, które były stosowane w kolejnych latach przez zwycięzców konkursu. W drugiej części znajduje się szczegółowe omówienie implementacji maszyny wnioskującej opartej na Propositional Nets. Maszyna wnioskująca, a w szczególności jej wydajność odgrywała w minionych konkursach kluczową rolę. Implementacja w języku C# zawiera szereg optymalizacji w strukturze sieci, co stanowi pewne rozwinięcie orginalnego pomysłu opracowanego na Uniwersytecie Stanforda. Całość domknięta jest podsumowaniem testów wydajnościowych, w których wyniki porównane są ze standardowa implementacją w Prologu.

Spis treści I Wprowadzenie do General Game Playing 3 1 Gra w ujęciu formalnym 5 1.1 Game Description Language...................... 7 1.2 Syntaktyka GDL............................ 8 1.3 KIF................................... 9 1.4 Zdefiniowane relacje w GDL...................... 10 1.5 Protokół rozgrywki........................... 14 2 Techniki stosowane w GGP 16 2.1 Automat gry w praktyce........................ 17 2.1.1 Prolog.............................. 17 2.1.2 Kompilacja........................... 18 2.1.3 Dekompozycja gier....................... 20 2.1.4 Wykrywanie symetrii...................... 21 2.2 Algorytmy przeszukiwania....................... 22 2.2.1 MiniMax............................. 22 2.2.2 Iterative Deepening A*..................... 27 2.2.3 UCT............................... 28 2.3 Konstrukcja funkcji ewaluacyjnej................... 32 2.3.1 Cluneplayer........................... 33 2.3.2 Fluxplayer............................ 34 2.4 Analiza zwycięskich graczy....................... 35 2.4.1 Cluneplayer........................... 35 2.4.2 Fluxplayer............................ 36 2.4.3 Cadiaplayer........................... 37 2.4.4 Ary................................ 37 2.4.5 TurboTurtle........................... 38 2.4.6 Podsumowanie......................... 38 1

II Automat stanów 40 3 Propositional Net 42 3.1 Konwersja z GDL do Propositional Net................ 43 3.1.1 Obliczenie dziedzin predykatów................ 44 3.1.2 Generowanie przełączników sieci................ 45 3.1.3 Generowanie bramek logicznych i połączeń.......... 45 3.1.4 Optymalizacja struktury sieci................. 46 3.1.5 Wyznaczenie porządku topologicznego sieci.......... 46 4 Implementacja i testy 47 4.1 Prologowy automat stanów....................... 47 4.2 Wyniki testów.............................. 48 5 Usprawnienia 51 2

Część I Wprowadzenie do General Game Playing 3

General Game Playing jest częścią dziedziny sztucznej inteligencji, koncentrującą się wokół budowania programów, zdolnych do rozwiązywania problemów, których treść jest zmienną programu. Ujmując to innymi słowami - opis problemu, który potrafiłby rozwiązać program jest podawany jako dane wejściowe, a wynikiem jest ciąg zgodnych z zasadami operacji, który prowadzi do możliwie najlepszego wyniku. Pewne klasy problemów uwzględniają uczestnictwo innych, niezależnych programów zmieniając sens rozwiązywania problemu w rywalizację lub kooperację. W tym miejscu chciałbym podkreślić, że nazwa General Game Playing (dosłownie: ogólne granie w gry) może być myląca, gdyż zakres możliwych do zdefiniowania gier obejmuje również problemy grafowe, czy problem pokrycia zbioru. W dalszej części pracy będę jednak używać określeń gra i problem zamiennie, idąc w ten sposób zgodnie z terminologią używaną w pracach na ten temat. [1]Za oficjalny początek tej młodej dziedziny można uznać rok 2005 i ogłoszenie przez Uniwersytet Stanford a otwartych mistrzostwo świata w General Game Playing. Towarzyszyło temu ograniczenie możliwych gier do konkretnego modelu, formalizacja języka opisu oraz protokół rozgrywki. W momencie pisania tej pracy odbyło się siedem edycji konkursu, co świadczy z jednej strony o zainteresowaniu dziedziną, jak i o tym, że wciąż istnieją duże możliwości rozwoju. W części I pracy rozpocznę od umotywowania dziedziny, kontrastując GGP z klasycznym podejściem do Game Playing, a w szczególności z najbardziej znanym przedstawicielem dziedziny - Deep Blue. Następnie wprowadzony zostanie w sposób formalny model gier, którymi zajmuje się GGP, wraz z omówieniem języka opisu oraz przybliżony zostanie protokół rozgrywki. Są to elementy, które mają fundamentalne znaczenie dla zrozumienia dalszych rozdziałów, a w szczególności zrozumienia technik stosowanych w GGP. 4

Rozdział 1 Gra w ujęciu formalnym Gry w General Game Playing składają się ze skończonej liczby stanów z wyróżnionym stanem początkowym oraz pewnymi stanami końcowymi, z których każdy ma przypisaną indywidualną nagrodę dla każdego z graczy.w każdej rozgrywce bierze udział skończona i stała liczba graczy, którzy w każdej turze, jednocześnie dokonują wyboru wykonywanej akcji ze skończonego zbioru działań zgodnych z zasadami. Każdy z graczy jest informowany o wybranych przez pozostałych akcjach. Stan gry zmienia się tylko pod wpływem akcji wykonywanych przez graczy. Tak opisany model można sformalizować w następujący sposób: S r 1,..., r n I 1,..., I n l 1,..., l n, l i I i S f : I 1... I n S S s 1 S T S g 1,..., g n, g i : r i T [0,..., 100] - skończony zbiór stanów gry. - gracze biorący udział w grze. - zbiory wszytkich akcji dla poszczególnych graczy. - zbiory legalnych akcji w danym stanie. - funkcja przejścia między stanami. - wyróżniony stan początkowy. - podzbiór stanów końcowych. - funkcja wypłaty dla stanów końcowych i poszczególnych graczy. Gra rozpoczyna się w stanie s 1. W każdej turze wszyscy gracze r i wybiera swoją akcję a i I i, dla której istnieje l i (m i, s numer tury ). Następnie stan gry zmienia się zgodnie z funkcją przejścia f(a 1,..., a n, s numer tury ). Gra kończy się w momencie, w którym stan gry s T. Zanim przejdziemy do omówienia sposobu na przekazanie zasad gry programowi, chciałbym rozważyć możliwości przedstawionego modelu. Weźmy akcję null 5

I i, dla każdego gracza i taką, że null wykonany na dowolnym stanie s S nie zmienia tego stanu. Konceptualnie jest to równoważne nie wykonaniu żadnej akcji. Mając do dyspozycji null możemy zasymulować w dowolnej grze naprzemienność wykonywania akcji w następujący sposób: w dowolnym stanie s S, wszyscy gracze poza jednym, magą wykonać tylko akcję null. Dzięki temu możemy wpasować do przedstawionego modelu takie gry jak szachy, warcaby, czy kółko i krzyżyk. Zgodne z modelem są zarówny gry wielo- jak i jednoosobowe. Do tych drugich możemy zaliczyć klasyczne łamigłowki takie jak: 8-queens, 15-puzzle czy wieże Hanoi, ale również pewne problemy optymalizacyjne jak: najkrótsza scieżka między parą wierzchołków w grafie, czy problem sumy podzbioru. Wsród możliwych do skonstruowania gier wieloosobowych, możemy wyróźnić gry sumy zerowej, ale również takie, które wymagają kooperacji. Funkcja wypłaty dla stanów terminalnych może być kształtowana w dowolny sposób. Przedstawienie wyżej wymienionych gier w praktyczny sposób nie zawsze jest łatwe, a więcej szczegółów dotyczących języka opisu gier znajduje się w najstępnej sekcji. Warto jednak odnotować, że w tak sformalizowanym modelu, możemy wyrazić cały szereg bardzo różniących się od siebie gier. Aplikacja potrafiąca radzić sobie z tak szerokim wachlarzem problemów jest zdecydowanie bliższa duchem początkom sztucznej inteligencji i [2]próbie budowy sztucznego umysłu niż ścieżka, w którą zabrneły wyspecjalizowane programy grające w jedną konkretną grę. Deep Blue Szachy byłyb obiektem badań sztucznej inteligencji w zasadzie od samego początku dziedziny. Gra, która od gracza na przyzwoitym poziomie wymaga stosowania rozmaitych strategii, planowania i przewidywania na wiele ruchów do przodu, mogłaby być wskaźnikiem tego jak blisko jest nam to stworzenia sztucznej inteligencji.[3] Pierwsze programy komputerowe zdolne grać w szachy powstały już w latach 50 XX wieku osiągając poziom nowicjusza. W latach 60 w oparciu o algorytm Alpha-beta powstały programy zdolne grać porównywalnie z dobrym graczem ze szkoły średniej. w kolejnej dekadzie nastąpił dalszy postęp w tej dziedzinie. Dzięki zwiększeniu mocy obliczeniowej komputerów, programy działające na bardzo podobnych zasadach jak ich poprzednicy, osiągnęły poziom eksperta, choć wciąż nie było pewne, czy kiedykolwiek komputer będzie zdolny do ogrania najlepszych ludzkich graczy. Dopiero pod koniec lat 80 wyspecjalizowany komputer Deep Thought w regularnym turnieju szachowym wyprzedził kilku arcymistrzów zajmując ex aequo pierwsze miejsce. Za najważniejsze - a z pewnością najsłynniejsze - osiągnięcie programów szachowych uznaje się komputer Deep Blue i jego zwycięstwo w 1997 roku nad Garry m Kasparov em, ówczesnym mistrzem świata 6

w szachach. Deep Blue bez wątpienia można uznać za technologiczne dzieło sztuki. [5] Zbudowano go z 30 procesorów ogólnego przeznaczenia IBM RS/6000, z czego dwadzieścia osiem działało z częstotliwościa 120M hz, a pozostałe dwa z częstotliwością 135M hz. Każdy procesor miał do dyspozycji 16 wyspecjalizowanych jednostek przeszukiwania stanów szachowych (łącznie 480), 1GB pamięci RAM (łącznie 30GB) oraz 4GB miejsca na dysku (łącznie 120GB). Każda z wyspecjalizowanych jednostek potrafiła przeanalizować od 2 do 2.5 miliona stanów gry.w czasie meczu z Kasparov em Deep Blue analizował średnio 126 milionów stanów gry na sekundę, a momentami ta liczba dochodziła do 330 milionów na sekundę. Funkcja ewulacyjna złożona była z około 8000 charakterystyk opisujących planszę, których wagi ustalane były programowo. Sama wartość w celu zwiększenia wydajności obliczana była sprzętowo, tz. wszystkie charakterystyki były wbudowane w sprzęt! Sam algorytm przeszukiwania opierał się na klasycznym algorytmie Alpha-beta ze znanymi już wcześniej szachowymi optymalizacjami. Podsumowując opis działania Deep Blue chciałbym zacytować Noam a Chomsky ego[4] : Program komputerowy wygrywający z arcymistrzem w szachy, to tak jakby buldożer wygrał zawody w podnoszeniu ciężarów. Deep Blue został tutaj przywołany nie bez przyczyny. Rozwiązania w nim zastosowane bardzo mocno oddaliły się od pierwotnego celu, którym jest zbudowanie sztucznego umysłu. Próby zrozumienia fenomenu inteligencji zastąpiono zapisywaniem na sztywno w kodzie źródłowym wiedzy programisty o konkretnym problemie uzupełnioną ogromem mocy obliczeniowej. Tworzenie wysoce wyspecjalizowanych aplikacji to na dzisiaj jedyna szansa, żeby móc konkurować - przy rozwiązywaniu konkretnych problemów - z człowiekiem. Model gry w General Game Playing jest zaprzeczeniem takiego podejścią. Program musi być gotowy do gry w potencjalnie nieskończenie wiele gier, każdą z nich analizując bez aktywnego wsparcia ze strony programistów. 1.1 Game Description Language Problemy spełniające założenia wprowadzonego w poprzedniej sekcji modelu, można postrzegać jako automaty skończone. Każda gra zawiera skończony zbiór stanów S. Funkcja f definiuje jak zmienić stan gry po wykonaniu akcji przez graczy. Stan s 1 określa stan początkowy, a zbiór T S określa stany końcowe automatu. Niestety poza bardzo wąskim gronem gier, przekazywanie automatu wprost jest niepraktyczne. Wspomine już wcześniej szachy zawierają ponad 10 28 stanów[6], więc 7

zakodowanie ich wprost przekracza możliwości jakiegokolwiek istniejącego obecnie nośnika danych. Rozwiązaniem tego problemu było zaproponowanie języka programowania logicznego Game Description Language (GDL). Pozwala on opisywać stan gry za pomocą zbioru prawdziwych faktów. Przejście między stanami definiują reguły, które pozwalają wywnioskować zbiór faktów prawdziwych po wykonaniu danych akcji graczy. To czy stan, jest stanem końcowym, określają pewne reguły - spełnione lub nie - przy danym zbiorze prawdziwych faktów. Specyfikację języka można znaleść w bibliografii [6]. Znajdują się w niej szczególowe wyjaśnienia dotyczące wprowadzonych na syntaktykę ograniczeń. Przedstawione poniżej wprowadzenie do GDL mają umożliwić śledzenie następnych rozdziałów bez konieczności analizowania oficjalnej specyfikacji języka. 1.2 Syntaktyka GDL Definicja 1 (Symbole GDL) Symbole w GDL składają się z: Zbioru zmiennych np. X, Y. Zbioru stałych obiektowych np. a, b, c. Zbioru symboli relacyjnych o ustalonej arności np. adjacent, on. Zbioru symboli funkcyjnych z ustaloną arnością np. f, g, h. Definicja 2 (Termy GDL) Termem w GDL jest: Zmienna. Stała obiektowa. N-argumentowy symbol funkcyjny zastosowana do n termów np. f(a, X, g(h(c, Y), e)). Definicja 3 (Zdanie atomowe GDL) Zdaniem atomowym w GDL jest n-argumentowy symbol relacyjny zastosowany do n termów. Definicja 4 (Literał GDL) Literałem w GDL jest zdanie atomowe lub jego zaprzeczenie. Definicja 5 (Term stały GDL) Termem stałym w GDL term bez zmiennych. 8

Definicja 6 (Reguły GDL) Regułami w GDL nazywami implikację o następującej formie: h b 1... b n h jest zdaniem atomowym. Każde b i jest literałem. Bezpieczeństwo: jeśli zmienna występuje w h lub w literale negatywnym, to występuje też w literale pozytywnym w poprzedniku aplikacji. Powyższe definicje można uzupełnić zasadą Ograniczenia Rekursji. Ma ona charakter techniczny - zapobiegający rozrostowi termów- i jest omówiona szerzej w specyfikacji GDL [6]. Ma ona jednak znaczenie głównie w przypadku samodzielnego przygotowywania reguł do gier, co nie jest moim celem - przy testowaniu będę korzystał z bogatej oferty dostępnych gier [8] [9]. Tak zdefiniowany Game Description Language jest teoretycznym modelem posiadającym przydatne w General Game Playing własności. Można za pomocą tego modelu - poprzez odpowiedni zbiór symboli i reguł - opisać w zwięzły sposób wiele gier. Dodatkowo każdy stan jest zbiorem zdań prawdziwych, dzięki czemu istnieje możliwość poszukiwania jakiegoś głębszego podobieństwa między poszczególnymi stanami. Warto zaznaczyć, że model nie zawiera wbudowanej artmetyki, ani też nie zakłada żadnych faktów prawdziwych, poza tymi które można wywnioskować ze zbioru faktów zasadniczych i reguł. 1.3 KIF Przejście od tego teoretycznego modelu do praktycznego zastosowania wymaga pośredniego języka. Wybór padł na Knowledge Interchange Format (KIF ), który pozwala w sposób niezależny od maszyny i języka programowania wymieniać komunikaty między komputerami. Zdecydowane się na niego ponieważ składnia nie wymaga dużych zmian w stosunku do modelu GDL. Jest to język o notacji prefiksowej. Wszystkie zmienne rozpoczynają sie od znaku?. Arność i typ stałych ustalany jest z kontekstu. Oto kilka przykładów: X jest zapisane jako?x f(a, X, g(h(c, Y ), e)) jest zapisane jako (f a?x (g (h c?y) e)) true(cell(1, 1, X)) jest zapisane jako (true (cell 1 1?x)) true(cell(1, 1, X)) jest zapisane jako (not (true (cell 1 1?x))) p(x) q(x) r(x) jest zapisane jako ( (p?x) (q?x) (not (r?x))) 9

1.4 Zdefiniowane relacje w GDL Game Description Language definiuje kilka podstawowych predykatów. Dzięki nim w każdej grze można określić role graczy, stan początkowy, funkcję przejścia czy też funkcję wypłaty dla stanów końcowych. Poniższe omówienie tych predykatów oparte jest na zasadach gry kólko i krzyżyk. Grę rozpoczyna się na planszy o rozmiarach 3x3 wypełnionej symbolami b, które symbolizuja pole puste (ang. blank). W grze uczestniczy dwóch graczy: x i o. W każdym kroku, naprzemiennie każdy z graczy może postawić w dowolnym pustym polu odpowiednio znak krzyżyka lub kólka, podczas gdy drugi gracz w danej turze wykonuje akcję noop (w wolnym tłumaczeniu nic ). Celem gry jest ustawienie trzech własnych symboli w rzędzie: pionowo, poziomu lub na przekątnych. Gra kończy się jeśli, którys z graczy osiąga ten cel lub kiedy nie ma już pól pustych. W przypadku osiągniecia celu zwycięzca dostaje 100pkt, podczas gdy przegrany dostaje tych punktów 0. W przypadku remisu obaj gracze dostają po 50pkt. Gracze: relacja role W każdym opisie gry znajduje sie przynajmniej jedna rola opisana przez predykat role. W grze kólko i krzyżyk role wygladają następująco: (role o) (role x) Oznacza to, że w całej grze występuje dwóch graczy określonych przez stałe obiekty - x oraz o. Zbiór graczy jest stały podczas całej rozgrywki dlatego użycie predykatu role ograniczone jest tylko do termów stałych, w szczególności nie można w trakcie gry wywnioskować istnienia nowej roli. Stan gry: relacja true Stan gry jest jednoznacznie wyznaczony przez zbiór termów stałych postaci true(f akt). Jest to symboliczny zapis tego, że dany fakt jest prawdziwy. Każda gra zawiera zbiór faktów prawdziwych na początku gry, oraz zawiera zbiór reguł pozwalających wywnioskować fakty prawdziwe w następnym stanie. Przykładem faktu w grze kółko i krzyżyk jest: (controle x) oznaczający, że gracz x ma możliwość wykonania niepustej akcji. Za pomocą tego i podobnych faktów, złożonych z symboli funkcyjnych, czy też - ogólniej rzecz ujmując - termów, można zbudować zdania atomowe prawdziwe w danym stanie: 10

(true (control x)) (true (cell 2 2 b)) Powyższy zbiór faktów oznacza dokładnie tyle, że gracz x posiada możliwość wykonania niepustej akcji oraz, że pole oznaczone stałymi 2, 2 jest puste. Stan początkowy: relacja init Znaczenie predykatu init jest analogiczne do znaczenia predykatu true poza tym, że jego pomocą przekazuje się zbiór predykatów prawdziwych w stanie początkowym gry. W grze kółko i krzyżyk ten zbiór wyglada w następujący sposób: (init (cell 1 1 b)) (init (cell 1 2 b)) (init (cell 1 3 b)) (init (cell 2 1 b)) (init (cell 2 2 b)) (init (cell 2 3 b)) (init (cell 3 1 b)) (init (cell 3 2 b)) (init (cell 3 3 b)) (init (control x)) Funkcja przejścia: relacja next Kolejnym predykatem o znaczeniu analogicznym do predykatu true jest predykat next określający te fakty, które są prawdą w następnym stanie gry: (<= (next (control x)) (true (control o)) (<= (next (control o)) (true (control x)) Legalne akcje: relacja legal W każdym stanie gry - poza być może stanami końcowymi - każdy z graczy może wywnioskować zbiór możliwych do wykonania akcji. W tym celu istnieje zdefiniowany predykat przybierający formę legal(gracz, akcja), który jest prawdziwy jeśli gracz może wykonać daną akcj. W grze kółko i krzyżyk gracz, dla którego prawdą jest, że posiada kontrolę może zaznaczyć dowolne puste pole, podczas gdy drugi gracz może wykonać jedynie akcję noop. 11

(<= (legal?player (mark?x?y)) (true (control?player))) (<= (legal x noop) (true (control o))) (<= (legal o noop) (true (control x))) Wykonywanie akcji: relacja does Predykat ten przybiera analogiczną formę do poprzedniego predykatu: does(gracz, akcja). W najogólniejszym sensie słuzy on do zmiany stanu gry w odpowiedzi na akcje graczy: (<= (next (cell?x?y?player)) (does?player (mark?x?y))) Dodatkową rolę predykat ten może odgrywać w przenoszeniu faktów prawdziwych do następnego stanu: (<= (next (cell?x?y b)) (does?player (mark?m?n)) (true (cell?x?y b)) (distinctcell?x?y?m?n)) (<= (distinctcell?x?y?m?n) (distinct?x?m) (<= (distinctcell?x?y?m?n) (distinct?y?n) Podczas rozgrywki gracze są informowani o akcjach przeciwników. Dokładnie w momencie otrzymania tej informacji następuje zmiana stanu, czyli w praktyce oznacza to wywnioskowanie pełnej relacji next. Komunikat z akcjami może wyglądać następująco: (does x (mark 2 2)) (does o noop) Taki zbiór oznacza, że gracz x zaznaczył środek planszy,a gracz o nie zaznaczył nic. 12

Cel gry: relacja goal Każda gra musi mieć zdefiniowany cel. W GDL istnieje w tym celu relacja o formie: goal(gracz, nagroda), gdzie nagroda [0,..., 100]. Nie ma żadnych ograniczeń w kwestii doboru wartości nagród, gry mogą mieć zarówno sprzeczne, jak i wspólne cele. Warto zaznaczyć, że gracze starają się zmaksymalizować wypłatę. W grze kółko i krzyżyk przykładem użycia relacji goal może byc następująca reguła: (<= goal(?player 100) (line?player)) gdzie predykat line oznacza zdefinowaną w innym miejscu relację ułożenia trzech znaków w linii. Stany końcowe: relacja terminal Omawiana relacja terminal nie zawiera żadnych argumentów, więc jest wyróżnioną stałą obiektową, która pojawia się w zbiorze faktów prawdziwych, kiedy osiągnięto stan końcowy. Pierwsze osiągnięcie przez grę stanu końcowego oznacza koniec rozgrywki. (<= terminal (role?player) (line?player) (<= terminal (not open)) Pozostałe relacje i ograniczenia W GDL domyślnie istnieją również relacje służące do budowania formuł logicznych - unarny not oraz binarny or. Badanie tego czy dwa termy są różne odbywa się za pomocą binarnego predykatu distinct, który jest spełniony wtedy i tylko wtedy, gdy oba termy są różne w sensie syntaktycznym. Na użycie domyślnych predykatów są nałożone pewne ograniczenia omówione szerzej w specyfikacji [6]. Można tam również znaleźć definicje pewnych własności gier, które muszą być spełnione, żeby nadawała się ona do rozegrania partii. W przypadku samodzielnego tworzenia gier jest to niezbędna lektura. 13

1.5 Protokół rozgrywki GDL stanowi język zwięzłego opisu zasad szerokiej klasy gier. Do rozegrania rzeczywistej partii między programami potrzebny jest jeszcze mechanizm komunikacji. W związku z brakiem ograniczeń wyboru języka programowania czy systemu operacyjnego naturalnym wyborem był powszechnie stosowany protokół sieciowy TCP/IP. W tym ujęciu każdy gracz jest serwerem, który ma swój adres sieciowy i port na którym odbiera komunikaty. Zadaniem każdego gracza jest umiejętność odpowiadania na te komunikaty. Potencjalnie każdy program potrafi jednocześnie prowadzić wiele jednoznacznie identyfikowalnych gier. Każda rozgrywka musi być jednak rozpoczęta, a następnie nadzorowana przez specjalny program w specyfikacji[6] nazywany Manager em Gry (GM ). Nadzorowanie gry przez GM polega na sprawdzaniu legalności wykonywanych przez graczy akcji, sprawdzaniu czy są one przesyłane w odpowiednim czasie oraz propagowaniu ruchów do wszystkich graczy (gracze nie komunikują się ze sobą bezpośrednio, lecz za pośrednictwem GM ). W przypadku kiedy akcja gracza nie jest legalna lub kiedy gracz nie zdąży odpowiedzieć przez upłynięciem limitu czasu,w jego imieniu losowana jest akcja ze zbioru tych legalnych. Komunikacja między GM a graczami odbywa się poprzez wymianę komunikatów w protokole HTTP. Każda wiadomość zawiera standardowy nagłówek wraz z typem ciała wiadomości - text/acl. Treść komunikatu to - odpowiednia dla danego etapu rozgrywki - formuła KIF, opakowana w jedną z dostępnych komend. Komenda START Komenda START służy do rozpoczynania rozgrywki i ma następującą formę: (START <MATCHID> <ROLE> <DESCRIPTION> <STARTCLOCK> <PLAYCLOCK>) MATCHID jest unikalnym identyfiaktorem przypisanym danej rozgrywce, który pozwala na prowadzenie wielu gier jednocześnie. Wszystkie komendy należące do tej samej rozgrywki mają jednakowy identyfikator. ROLE jest pojedyńczym elementem określającym rolę danego gracza w rozgrywce np. o lub x w grze kółko i krzyżyk. DESCRIPTION jest wyrażeniem w języku KIF, zamkniętym w parę zewnętrznych nawiasów. STARTCLOCK / PLAYCLOCK są liczbami naturalnymi określającymi kolejno czas do pierwszej tury oraz czas na przesłanie odpowiedzi w każdej turze w sekundach. 14

W odpowiedzi każdy z graczy przed upłynięciem czasu na zainicjalizowanie gry powienien odpowiedzieć: READY Jeśli któryś z graczy nie zdąży odpowiedzieć w wyznaczonym czasie nie ma to żadnych konsekwencji - kolejne komendy będą wysyłane bez zakłóceń i spóźniony gracz wciąż może brać udział w rozgrywce. Komenda PLAY Komenda PLAY rozpoczyna każdą turę. Zawiera ona dwa argumenty: pierwszym jest identyfikator rozgrywki, drugim jest lista akcji wykonanych przez graczy w poprzedniej rundzie. (PLAY <MATCHID> (<A1>... <An>)) Specjalnym przypadkiem tej komendy jest pierwsze jej wystąpienie - lista akcji wykonanych w poprzedniej turze jest pusta i oznaczona symbolem NIL. W odpowiedzi w każdej turze, przed upływem wyznaczonego czasu gracz zobowiązany jest wysłać akcję, którą chciałby wykonać. (MARK 2 2) W przypadku kiedy podana akcja jest nielagalna lub nie została dostarczona przed upływem czasu, GM losuje z równym prawdopodobieństwem akcje ze zbioru legalnych. Gracz jest o tym fakcie informowany przy następnej komendzie PLAY, która jest pewnym potwierdzeniem (lub zaprzeczeniem) wyboru gracza. Komenda STOP Komenda ta ma strukturę i znaczenie analogiczne do komendy PLAY z tą różnicą, że oznacza koniec rozgrywki. (STOP <MATCHID> (<A1>... <An>)) W odpowiedzi każdy z graczy wysyła krótką wiadmość: DONE 15

Rozdział 2 Techniki stosowane w GGP Gracze w General Game Playing często nazywani są systemami GGP. Wynika to wprost z poziomu skomplikowania takiej aplikacji. W najbardziej zewnętrznej warstwie musi znajdować się serwer HTTP, bez którego nie ma możliwości komunikacji niezbędnej do prowadzenia rozgrywek. Granie w daną grę w najogólniejszym sensie wymaga jakieś formy przeszukiwania automatu zadanego przez opis w GDL. W tym celu potrzebny jest algorytm przeszukiwania oraz mechanizm generowania następników danego stanu, legalnych ruchów, czy też określania ilości punktów za stany końcowe. W niektórych podejściach potrzebny jest też mechanizm oceny stanów pośrednich, czyli kod odpowiedzialny za generowanie heurystycznych funkcji ewaluacyjnych, które w GGP nie mogą być znane z góry. Poszczególne elementy systemu mogą być realizowane na różne sposoby i najważniejsze z nich są przedstawione w następnych podrozdziałach. Część z wymienionych technik jest w pewnym odwrocie, gdyż znaleziono - wydaje się - lepsze alternatywy. GGP jest jednak dziedziną bardzo młodą, więc warto dla porządku wspomnieć pierwsze podejścia szczególnie, że gracze z nich korzystający wygrywali mistrzostwa świata. Ponadto można zaobserwować pewną ewolucję i odejście od technik klasycznego Game Playing na rzecz rozwiązań bardziej ogólnych i uniwersalnych. Celem tej sekcji jest przybliżenie idei rozwiązań zastosowanych w GGP, naszkicowanie zasad działania poszczególnych technik z wyraźnym zaznaczeniem pomysłów i intuicji z nimi związanych. Przy każdej z nich znajduje się odwołanie do pracy właściwej, opisującej dane zagadnienie w sposób bardziej formalny. Niestety na dzień dzisiejszy GGP nie doczekała się jako dziedzina pełniejszego opracowania, w większości prac powtarza sie element wprowadzenia do dziedziny, a opis pomysłow choć bardziej formalny niż w tej pracy, wciąż żadko kiedy zawiera jakiś dowód poprawności. 16

2.1 Automat gry w praktyce Zupełnie fundamentalną częścią systemu GGP jest automat gry. Mówiąc precyzyjniej jest to podsystem, który potrafi obliczyć odpowiedzi na co najmniej cztery podstawowe zapytania: Wszystkie legalne akcje dla danego gracza i stanu. Nastepny stan na podstawie danego stanu i wykonanych przez graczy akcji. Sprawdzić, czy dany stan jest stanem końcowym. Dla danego stanu końcowego i gracza podać liczbę zdobytych punktów. Właściwie w każdym systemie GGP jest to elemenet intensywnie wykorzystywany przez algorytm przeszukiwania. W związku z tym kluczową cechą automaty gry powinna być wydajność. Biorąc pod uwagę cele GGP i nauczkę ze ścieżki jaką obrali twórcy Deep Blue nie należy uważać elementu wydajności za bezwzględnie najważniejszy. Nie można też jednak zignorować ten element - jeśli maszyna kiedyś będzie zachowywać sie inteligentnie z dużym prawdopodobieństwem będzie też niezwykle wydajna. Mimo postępu w tej dziedzinie w stosunku do pierwszych prac dochodzącego do nawet 20x szybszych automatów gry wciaż jest wiele do zrobienia. [12] Dzięki jednemu z najszybszych obecnie rozwiązań potrafimy w szachach wygenerować - bez analizowania - około 1000 sytuacji na sekundę przy użyciu jednego rdzenia, co odpowiada zejściu w drzewie przeszukiwania na dwa, trzy ruchy do przodu. Dla przypomnienia Deep Blue średnio analizował około 420 000 stanów na sekundę przy użyciu jednej wyspecjalizowanej jednostki (miał ich w sumie 480). Przy obecnej technologii konstrukcji procesora postęp wydajności osiąga się dzięki zrównolegleniu obliczeń i bez wątpienia od automatu gry wymagana jest skalowalności. Tą cechę można uzyskać poprzez utrzymywanie niezależnej kopii automatu dla każdego wątku zadającego zapytania. 2.1.1 Prolog Pierwsze systemy GGP implementowały automat gry w Prologu. Reguły podane w GDL można konwertować w jedną i drugą stronę w prosty, mechaniczny sposób. Drugim powodem tego wyboru jest fakt, że Prolog jest dojrzałym językiem z wieloma implementacjami silnika wnioskującego oraz z wieloma bibliotekami umożliwiającymi integrację z popularnymi językami programowania takimi jak Java, C++ czy C#. Zanim inne podsystemy będą mogły korzystać z automatu gry, należy go zainicjować wpisaniem do bazy wiedzy Prologa reguł wnioskowania zawartych w grze. 17

Następnie obliczanie odpowidzi na zapytanie np. o następników stanu s wymaga wgrania do bazy faktów prawdziwych w s. Za każdym razem jednak trzeba te fakty wymieniać tj. jeśli pytaliśmy o stan s 1, a chcemy zapytać o stan s 2 musimy usunać z bazy fakty prawdziwe w s 1, a następnie wgrać fakty prawdziwe w stanie s 2. Można uniknąć dodawania i usuwania faktów dodając dodatkowy argument oznaczający stan [7], co poprawia szybkość działąnia, ale zużywa też dużo więcej pamięci. Przykładem reguły GDL przekonwertowanej do postaci Prologowej jest: goal(player, 100, State) :- line(player, State) Poza mechaniczną zmianą wyrażeń potrzebne jest jeszcze zdefiniowanie kilku dodatkowych predykatów. GDL uwzględnia sprawdzenie czy dwa termy są różne, dlatego: distinct(x, Y) :- X \== Y Relacja true w GDL wyznacza zbiór faktów prawdziwych w danym stanie. Fakty te są zdefiniowane jako wyrażenia należące do opisu danego stanu: true(x, State) :- member(x, State) Ponad istnieje potrzeba zdefiniowania predykatów odpowiedzialnych za relacje odpowiedające spójnikom logicznym: not(x) :- \+ X or(a, B) :- A ; B Zaletą użycia Prologa z pewnością jest prostota implementacji i możliwość skorzystania z istniejących, przetestowanych elementów. Podejście to ma jednak przede wszystkim wady. Silniki wnioskowania Prologa są przystosowane do dowolnego zbioru predykatów, czyli w pewnym sensie są interpreterem przeszukującym zbiory stałych i reguł. W grze napisanej w GDL reguły są stałe, zmienia się tylko zbiór faktów. Zadajemy również tylko kilka rodzajów zapytań. Podsumowując: jest to sytuacja, w której do bardzo wyspecjalizowanych wnioskowań używamy bardzo ogólnego mechanizmu. 2.1.2 Kompilacja Na przeciw problemom wymienionym w poprzednim paragrafie wyszedł Kevin Waugh [12]. Idea jego rozwiązania jest następująca: reguły z opisu gry podane w GDL zamienić na kod źródłowy w C++, skompilować go, a następnie podająć zbiór faktów prawdziwych jako parametr metody dokonywać obliczeń. W zasadzie poza 18

mechaniczną generacją kodu i użyciem transpositions table do zapamiętywania pośrednich obliczeń praca nie przedstawia żadnych optymalizacji, wskazując poszukiwania takowych jako kierunek rozwoju. Wśród propozycji potencjalnych ulepszeń znajduję sie znalezienie heurystyki ulepszającej uszeregowanie poprzedników implikacji. Można znaleźć jeszcze jedną pracę w podobnym duchu [13], ale autorzy postanowili kompilować GDL do OCaml a co poskutkowało znacznie skromniejszym przyśpieszeniem. Kompilowanie GDL do kodu wykonywalnego oparte jest na spostrzeżeniu, że reguły wnioskowania są stałe i można algorytm rezolucji - dla danej gry - zapisać na stałe w kodzie maszynowym. Omawiany kompilator został przez twórcę nazwany gdlcc. Sam algorytm składa się z następujących faz: 1. Analiza leksykograficzna: usunięcie komentarzy, podział na tokeny. 2. Analiza syntaktyczna: z tokenów budowane są fakty i reguły. Każdy token ma przypisany identyfikator, dzięki czemu można operować na identyfikatorach zamiast napisów. 3. Odkrywanie zależności między regułami: przeszukiwanie grafu wszerz od podstawowych zapytań (np. o legalne ruchy ze stanu) w celu ustalenia zapytań pośrednich. 4. Generowanie kodu: na podstawie poprzedniego kroku generowany jest kod źródłowy z ustalonymi zapytaniami pośrednimi. Poniżej znajduje się przykładowy fragment wyniku działania algorytmu przepisany na język C#. Przetwarzane jest w nim zapytanie pośrednie z gry kółko i krzyżyk: (row?x a) W zasadach gry znajduje się tylko jedna reguła zawierająca predykat row w następniku implikacji: (<= (row?m?x) (true (cell?m 1?x)) (true (cell (?m 2?x)) (true (cell?m 3?x))) Dla każdego zapytania generowana jest metoda o odpowiedniej sygnaturze. Nazwa metody tworzona jest ze wględu na obliczany predykat oraz wektor bitowy odpowiadający ukonkretyzowaniu zmiennych. W powyższym przykładzie drugi argument jest ustalony jako a stąd odpowiadający mu wektor to 01. Wygenerowany kod wygląda następująco: 19

IList< Tuple<int> > EvaluateRow01(int a) { var results = new List<Tuple<int>>(); var b = EvaluateCell011(2,a); foreach(var argb in b) { var d = EvaluateCell111(argB[0], 4, a); foreach(var argd in d) { var f = EvaluateCell111(argB[0], 5, a); foreach(var argf in f) { results.add(new Tuple<int>(argF[0]); } } } return results.distinct(); } Kompilowanie gier pozwoliło uzyskać wyraźną poprawę wydajności w stosunku do rozwiązań opartych na Prologu. Testy przeprowadzone przez Kevina Waugh[12] polegały na przeprowadzaniu losowych przeszukiwań drzewa gry. Pierwszy z graczy korzystał z implementacji YAP Prolog, podczas gdy drugi gracz korzystał z kompilowanego źródła GDL. Oba programy były uruchamiane na jednym rdzeniu procesora o częstotliwości 2.4GHz. Poniżej znajduje się tabelka z uśrednionymi ilościami przejrzanych ruchów w czasie jednej sekundy. Różnica w wydajności jest Kółko i krzyżyk Szachy YAP 10519 640 gdlcc 181169 1118 gdlcc tt 263224 1070 Tabela 2.1: Ilość rozważanych ruchów w 1s czasu wyraźna, szczególnie w grze, której stan jest opisywany niewielką ilościa faktów. Rozmiar stanu gry ma też wpływ na przydatność transpositions table, w grze kółko i krzyżyk przyśpieszenie jest wyraźne, w szachach otrzymujemy wręcz zwolnienie. 2.1.3 Dekompozycja gier Rozważmy następującą sytuację: na stole znajdują się dwie plansze, każda do grania w niezależną grę. Dla uproszczenia przyjmijmy, że branching factor obu można 20

oszacować przez O(b), gdzie b jest pewną stałą. Rozpatrując dwie plansze jako całość otrzymujemy grę z branching factor równym O(b 2 ). Oznacza to, że mogąc rozpatrzyć w jednostce czasu dokładnie k stanów gry w istocie rozpatrujemy tylko O( k) niezależnych stanów każdej z podgier. Ponadto gdyby rozpatrywać każdą podgrę niezależnie, moglibyśmy rozpatrzyć O( k ) sytuacji dla każdej z nich. 2 Co w przypadku kiedy liczba niezależnych podgier równa się n? Branching factor całości w tym przypadku równy jest O(b n ) co oznacza, że sam poziom rozgałęzienia drzewa gry ulega kombinatorycznej eksplozji, chociaż rozpatrując podgry w sposób niezależny moglibyśmy rozpatrzyć dla każdej O( k ) sytuacji. Dokładnie n tak zachowałby się człowiek widząc, że sytuacja na jednej planszy nie ma wpływu na sytuację na drugiej. Podana tutaj sytuacja w grze napisanej w GDL zdażyła się podczas konkursu w roku 2008 roku, kiedy gracze walczyli w grze odpowiadającej dwóm jednoczesnym partiom w kółko i krzyżyk oraz w grze jednoosobowej składającej się z dwóch łamigłówek. Próbę rozwiązania tego problemu można znaleść w dwóch pracach: w opisie rozszerzenia do gracza Fluxplayer[23] oraz jako pracę teoretyczną grupy osób z Uniwersytetu Stanforda[26]. W drugiej części mojej pracy będzie szczegółowo omówione rozwiązanie zaproponowane na Stanfordzie - ma ono większy potencjał do optymalizacji. 2.1.4 Wykrywanie symetrii W wielu grach ważnym elementem służącym optymalizacji jest wykrywanie symetrii stanów gry. Stephan Schiffel w swojej pracy [15] zaproponował sposób na wygrywanie symetrii stanów w grach napisanych w GDL. Pierwszym problemem, który należało rozwiązać była sama definicja symetrii. W grze kółko i krzyżyk można dość łatwo zaobserwować, że stany gry mogą być symetryczne z dokładnością do odbić i obrotów. W grach definiowanych przez GDL Schiffel definiuje symetrię w następujący sposób (ujmując rzecz nieformalnie): Definicja 7 (Symetria w grze) Symetrią gry G nazywamy bijekcję σ działającą na obiektach opisu G w GDL w ten sposób, że zachowuje strukturę gry. Dwa stany s 1 i s 2 są symetryczne jeśli akcje możliwe w stanie s 1 mają swoje symetryczne odpowiedniki wśród akcji legalnych w stanie s 2. Dwie akcje są są symetryczne jeśli zaaplikowane prowadzą w jednym kroku do symetrycznego stanu. Powyższa definicja jest intuicyjnie łatwa do zrozumienia, chociaż do zastosowania jej potrzeba pewnych uściśleń i ograniczeń zawartych w pracy Schiffel a 21

[15]. Pierwszym problemem, który należy zauwazyć jest rekurencyjność definicji. Sprawdzając ją wprost, można teoretycznie sprawdzić czy funkcja σ jest symetrią, ale jest to zupełnie niepraktyczne. Istotą pracy Schiffel a jest wskazanie stosunkowo niewielkiego grafu, którego automorfizmy są równoważne symetriom. Budowę grafu można w szerszym spojrzeniu opisać następująco: zmienne w opisie gry przemianujemy tak, żeby się nie powtarzały w formułach. Następnie dla każdej zmiennej, stałej, predykatu, reguły wnioskowania czy termu występującego w opisie gry bez relacji init, ale z relacją true (graf jest różny dla poszczególnych stanów gry). Każdy z tych wierzchołków jest kolorowany w ten sposób, że możliwy jest tylko automorfizm przekształcający zmienne na zmienne, stałe na stałe etc. Krawędzie w grafie odzwierciedlają zależności między wierzchołkami i dodaje się je w 7 przypadkach opisanych dokładniej w pracy. Symetrię można wykorzystać przy odcinaniu pewnych gałęzi gry w przypadku, kiedy odwiedziliśmy już stan symetryczny, lub kiedy rozważamy wykonanie jednej akcji ze zbioru, w którym część akcji jest symetrycznych (wtedy warto sprawdzić tylko reprezentantów klas równoważności). Testy pokazały ze zaproponowana metoda potrafi w prostych grach taki jak kółko i krzyżyk odrzucić nawet 7 8 możliwych stanów, ale są też gry, w której zysk jest minimalny, lub też nawet występuje strata. Ostatni przypadek ma miejsce, kiedy zbiór faktów potrzebnych do opisu stanu jest spory, a symetrie występują rzadko. 2.2 Algorytmy przeszukiwania Drugim istotnym podsystemem jest jakaś forma przeszukiwania automatu,nawet jeśli miało to polegać tylko na przejrzeniu możliwych do wykonania ruchów z aktualnego stanu gry. W pierwszych systemach GGP stosowano rozwiązania z klasycznego Game Playing, takie jak algorytm MiniMax z istniejącymi usprawnieniami. Metody te zostały szybko wyparte przez nowsze, oparte na statystyce. Warto jednak omówić je wszystkie, zwracając szczególną uwagę na wady i zalety w kontekście grania w bardzo zróżnicowane gry szczególnie, że niezależnie od wybranego algorytmu zawsze pozostaje do rozwiązania problem modelowania zachowań przeciwników. 2.2.1 MiniMax MiniMax jest algorytmem, a właściwie teorią, która mówi o tym, że w skończonych grach dwuosowych sumy zerowej z naprzemiennymi ruchami możemy mechanicznie obliczyć gwarantowaną wypłatę dla gracza rozpoczynającego grę. W 22

grze bierze udział dwóch graczy: min i max. Pierwszy stara się zminimalizować wartość funkcji celu, drugi zachowuje się dokładnie odwrotnie. Grę rozpoczyna gracz max, który może wykonać jeden ze skończonego zbioru ruchów legalnych. Z każdym wyborem wiążą się pewne konsekwencje, w szczególności dla każdego wyboru gracza max gracz min może prowadzić dalej grę tak, żeby zagwarantować sobie jak najmniejszą wartość funkcji celu. Konsekwencją takiego rozumowania jest strategia optymalna dla gracza max, a mianowicie wykonanie takiego ruchu, który maksymalizuje minimalizowaną przez gracza min gwarantowaną wypłatę. Analogiczne rozumowanie można przeprowadzić z perspektywny gracza min. W konsekwencji możemy na problem spojrzeć, jak na drzewo drzewo gry, w którym wierzchołki mają przypisaną gwarantowaną wypłatę. Zaczynając od funkcji celu w liściach na parzystych poziomach drzewa, gracz max wybiera największą wartość wypłaty ze wszystkich wartości w bezpośrednich potomkach. Analogicznie gracz min na nieparzystych poziomach drzewa wybiera najmniejszą gwarantowaną wypłatę ze wszystkich wartości w bezpośrednich potomkach. Przykładowe drzewo gry znajduje się na Rysunku 2.1: liczby symbolizują gwarantowane wypłaty, czerwone strzałki oznaczają dokonane na poszczególnych poziomach drzewa wybory, a niebieska strzałka oznacza ruch wybrany przez gracza max po przeanalizowaniu całego drzewa. Rysunek 2.1: Przykładowe drzewo gry. Źródło: http://www.wikipedia.com W przedstawionym rozumowanie istotnymi własnościami gry jest naprzemienność wykonywania ruchów oraz fakt, że funkcja wypłaty ma sumę zerową( w każdym stanie funkcje wypłaty dla gracza min i max sumują się do zera). W grach 23