Algorytmy dla gier dwuosobowych Wojciech Dudek Seminarium Nowości Komputerowe 5 czerwca 2008
Plan prezentacji Pojęcia wstępne (gry dwuosobowe, stan gry, drzewo gry) Algorytm MiniMax Funkcje oceniające Algorytm α, β cięć Tablice transpozycji
Rodzaje gier Rodzaje gier deterministyczne niedeterministyczne pełna szachy, go monopol informacja warcaby, otello niepełna.. poker, brydż informacja scrabble
Model gry W grze uczestniczy dwóch graczy. Gracze wykonują ruchy naprzemiennie. W każdym momencie jest skończona liczba możliwych do wykonania ruchów. (skończoność) Sytuacja na planszy i wykonany ruch jednoznacznie wyznaczają następną sytuację na planszy. (determinizm) Sytuacja na planszy może być jednoznacznie zaklasyfikowana jako: wygrana pierwszego gracza, wygrana drugiego gracza, remis, sytuacja nierozstrzygnięta (rozgrywka może jeszcze trwać)
Gra dwuosobowa Cel Interesują nas dwuosobowe gry deterministyczne z pełną informacją Szukamy najlepszej strategii (sekwencji ruchów) dla każdej odpowiedzi przeciwnika.
Stan gry Sytuacja na planszy Kto się rusza Rysunek: Plansza
Drzewo gry Partia może być w pełni opisana przez ciąg naprzemiennych ruchów obu graczy od stanu początkowego do rozstrzygnięcia (wygranej/przegranej/remisu). Rozważamy wszystkie możliwe scenariusze rozwoju gry. Naturalna reprezentacja, to drzewo.
Drzewo gry Rysunek: Drzewo gry, Kółko i krzyżyk
Przeszukiwanie ruchów Wygrana M, Przegrana -M, Remis 0 Jesteśmy graczem Max Przeciwnik nam przeszkadza, czyli my dążymy do 1 a on do -1 Przeciwnik to Min Nie wiemy jak zagra Min, zakładamy że zagra jak najkorzystniej dla siebie
Zasada MiniMax Stany rozstrzygnięte w drzewie gry mają swoją ocenę {M,-M,0} Poziomy należą na przemian do Min i do Max Stany nierozstrzygnięte otrzymują ocenę wg. zasady: Zasada poziom Max a: maximum ocen z jego węzłów potomnych poziom Min a: minimum ocenę z jego węzłów potomnych
MiniMax Rysunek: MiniMax
Uwagi o MiniMax Nie musimy budować całego drzewa Przechodzimy drzewo w głąb (DFS) Czasami drzewo jest za duże. Obcięcie, i heurystyczna ocena stanu
Funkcje oceniające Chcemy przybliżyć ocene sytuacji na planszy Typowe dla szchów Rank(s) = w 1 f 1 (s) + w 2 f 2 (s) +... f 3 (s) = (ilosc h etmanow b ialych) (ilosc h etmanow c zarnych) Dla kółka i krzyżyk np. ilośc gróźb
Głębokość Dla szchów ilość możliwych ruchów w każdym kroku, ok b=35 ; długość partii m=100. (35 100 ) Dla minimaxa ok b=4 (nowicjusz) 8 - przeciętny PC, mistrz ; 12 - Kasparow, DeepBlue Można grać ze zmienną głębokością przeszukiwania.
Algorytm MiniMax function minimax(node, depth) if node is a terminal node return value of node if depth = CutoffDepth return the heuristic value of node else let a := -inf foreach child of node let a := max(a, -minimax(child, depth+1)) return a
Algorytm α, β cięć Rysunek: MiniMax
AlfaBeta function minimax(node, depth) return alfabeta(node, depth, -inf, +inf) function alfabeta(node, depth, alfa, beta) if node is a terminal node or depth = 0 return the heuristic value of node else foreach child of node beta := min(beta, alfabeta(child, depth-1, alfa, beta)) if alfa >= beta return alfa return beta else {my mamy zagrac w wezle} foreach child of node alfa := max(alfa, alfabeta(child, depth-1, alfa, beta)) if alfa >= beta return beta return alfa
Negamax function negamax(node, depth, alfa, beta) if node is a terminal node or depth = 0 return the heuristic value of node else foreach child of node alfa := max(a, -negamax(child, depth-1, -beta, -alfa)) {the following if statement constitutes alpha-beta pruning} if alfa >= beta return beta return alfa
Tablice transpozycji Zapamiętujemy ocenione stany, żeby nie sprawdzać kilka razy tego samego. Do uszeregowania ruchów, dla iteracyjnego pogłebiania Jako strukturę zapamiętującą używamy tablic haszujących.
Zorbrist hashing zorbrist[typ figury][kolor][pozycja] wypełnimy liczbami losowymi 64 bitowymi hash = xor(zorbrist[t i ][k i ][p i ]) dla każdej figury i łatwo/szybko się liczy
Kilka faktów Komputery grają dobrze w szachy (DeepBlue - Kasparow), warcaby, otello W Go komputery grają słabo (b=300)