Algorytmy z powrotami. Algorytm minimax Algorytmy i struktury danych. Wykład 7. Rok akademicki: 2010/2011 Algorytm z powrotami rozwiązanie problemu budowane jest w kolejnych krokach, po stwierdzeniu (w trakcie realizacji i-tego kroku), że rozwiązanie problemu nie jest możliwe do osiągnięcia następuje powrót do kroku wcześniejszego i badana jest możliwośd wykonania innego kroku zapoczątkowującego inną ścieżkę poszukiwao; sposób wyznaczania rozwiązania można przedstawid jako wędrówkę po drzewie. Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 2 1
Algorytm z powrotami schemat działania Stan początkowy Poziom 1 Wariant 1 Poziom 1 Wariant 3 Poziom 2 Wariant 1.1 Poziom 2 Wariant 1.2 Poziom 2 Wariant 3.1 Poziom 2 Wariant 3.2 Poziom 2 Wariant 3.3 Poziom 3 Wariant 1.2.1. Poziom 3 Wariant 1.2.2. Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 3 Problem ośmiu hetmanów Ułożyd na szachownicy osiem hetmanów tak, aby się wzajemnie nie szachowały. Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 4 2
Opis algorytmu problem ośmiu hetmanów Figury ustawiane są w kolejnych kolumnach (począwszy od pierwszej od lewe strony), Jeśli ustawienie hetmana w danej kolumnie nie jest możliwe, to następuje powrót do kolumny wcześniejszej i dokonywana jest próba zmiany położenia znajdującego się tam hetmana; po jej dokonaniu poszukiwania są kontynuowane. Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 5 Problem ośmiu hetmanów class PierwszeUstawienie boolean [][] szachownica = new boolean[8][8]; int ileustawiono = 0; void usunwszystko() for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) szachownica[i][j] = false; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 6 3
Problem ośmiu hetmanów void drukujszachownice() for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) if (szachownica[i][j] == true) System.out.print('*'); else System.out.print('.'); System.out.println(); Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 7 Problem ośmiu hetmanów boolean czypoprawne(int x, int y) int i, j; //czy jest w tym samym wierszu? for (j = 0; j < 8; j++) if (szachownica[x][j] == true) return false; //czy jest w tej samej kolumnie? for (i = 0; i < 8; i++) if (szachownica[i][y] == true) return false; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 8 4
Problem ośmiu hetmanów //czy jest na przekatnej prawo-gora? for (i = x, j = y; (i >= 0) && (j < 8); i --, j++) if ((i!= x) && (j!= y) && (szachownica[i][j] == true)) return false; //czy jest na przekatnej prawo-dol? for (i = x, j = y; (i < 8) && (j < 8); i++, j++) if ((i!= x) && (j!= y) && (szachownica[i][j] == true)) return false; //czy jest na przekatnej lewo-gora? for (i = x, j = y; (i >= 0) && (j >= 0); i--, j--) if ((i!= x) && (j!= y) && (szachownica[i][j] == true)) return false; //czy jest na przekatnej lewo-dol? for (i = x, j = y; (i < 8) && (j >= 0); i++, j--) if ((i!= x) && (j!= y) && (szachownica[i][j] == true)) return false; return true; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 9 Problem ośmiu hetmanów boolean ustaw(int kolumna) int wiersz = 0; do if (czypoprawne(wiersz,kolumna)) szachownica[wiersz][kolumna] = true; ileustawiono++; if (kolumna + 1 < 8) if (ustaw(kolumna + 1)) return true; else szachownica[wiersz][kolumna] = false; ileustawiono--; wiersz++; while ((ileustawiono < 8) && (wiersz < 8)); if (ileustawiono == 8) return true; else return false; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 10 5
Problem ośmiu hetmanów void rozwiazzadanie() usunwszystko(); if (ustaw(0)) drukujszachownice(); else System.out.println("Brak rozwiazaia!!!"); public class OsiemHetmanow01 public static void main(string [] args) PierwszeUstawienie u = new PierwszeUstawienie(); u.rozwiazzadanie(); Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 11 Problem ośmiu hetmanów Rezultat uruchomienia programu: *......*....*......*.*......*......*....*... Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 12 6
Algorytm minimax Algorytm minimax jest podstawowym algorytmem wykorzystywanym przy tworzeniu gier dwuosobowych rozgrywanych w układzie: człowiek - komputer. Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 13 Kółko i krzyżyk jako przykład gry dwuosobowej Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 14 7
class KK01 static final int NIKT = 0; static final int KOMPUTER = 1; static final int CZLOWIEK = 2; int n; int [][] plansza; KK01(int n) this.n = n; plansza = new int[n][n]; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 15 char symbolgracza(int zawodnik) switch(zawodnik) case CZLOWIEK: return 'X'; case KOMPUTER: return 'O'; case NIKT: return '.'; return '?'; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 16 8
void wyswietl() for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) System.out.print(symbolGracza(plansza[i][j])); System.out.println(); Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 17 void ruchgracza() int wiersz = 0, kolumna = 0; System.out.println("RUCH GRACZA:\n"); wyswietl(); System.out.println(); Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 18 9
try BufferedReader klawiatura = new BufferedReader(new InputStreamReader(System.in)); do System.out.print("Podaj numer wiersza (1," + (n) + "): "); wiersz = Integer.parseInt(klawiatura.readLine()); System.out.print("Podaj numer kolumny (1," + (n) + "): "); kolumna = Integer.parseInt(klawiatura.readLine()); while (plansza[wiersz-1][kolumna-1]!= NIKT); plansza[wiersz-1][kolumna-1] = CZLOWIEK; System.out.println(); catch (Exception e) System.out.println(e.getMessage()); Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 19 boolean czywygral(int zawodnik) int suma; //czy jest wiersz for (int i = 0; i < n; i++) suma = 0; for (int j = 0; j < n; j++) if (plansza[i][j] == zawodnik) suma++; if (suma == n) return true; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 20 10
//czy jest kolumna for (int j = 0; j < n; j++) suma = 0; for (int i = 0; i < n; i++) if (plansza[i][j] == zawodnik) suma++; if (suma == n) return true; //pierwsza przekatna suma = 0; for (int i = 0; i < n; i++) if (plansza[i][i] == zawodnik) suma++; if (suma == n) return true; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 21 //druga przekatna suma = 0; for (int i = 0; i < n; i++) if (plansza[i][n-1-i] == zawodnik) suma++; if (suma == n) return true; return false; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 22 11
int ocenasytuacji(int ktowykonalruch) return czywygral(ktowykonalruch)? 1000 : 0; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 23 int wybierznajlepszyruch() int sytuacja = -9999; int ruch = -1; int ocena; for (int i = 0; i < n * n; i++) if (plansza[i/n][i%n] == NIKT) plansza[i/n][i%n] = KOMPUTER; if ((ocena = ocenasytuacji(komputer)) > sytuacja) sytuacja = ocena; ruch = i; plansza[i/n][i%n] = NIKT; return ruch; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 24 12
void ruchkomputera() System.out.println("RUCH KOMPUTERA...\n"); int pozycja = wybierznajlepszyruch(); plansza[pozycja/n][pozycja%n] = KOMPUTER; wyswietl(); System.out.println(); Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 25 boolean czysapuste() int suma = 0; for (int i = 0; i < n * n; i++) if (plansza[i/n][i%n] == NIKT) suma++; return (suma > 0? true: false); int nastepny(int zawodnik) return 3 - zawodnik; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 26 13
void rozgrywka() int nastepnyzawodnik = CZLOWIEK, zawodnik; do zawodnik = nastepnyzawodnik; switch (zawodnik) case CZLOWIEK: ruchgracza(); break; case KOMPUTER: ruchkomputera(); break; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 27 nastepnyzawodnik = nastepny(zawodnik); while (!czywygral(zawodnik) && czysapuste()); System.out.println("\n\nKoniec gry!!!\n"); wyswietl(); System.out.println("\n"); if (czywygral(czlowiek)) System.out.println("Wygrales z komputerem!!!"); else if (czywygral(komputer)) System.out.println("Wygral KOMPUTER!!!"); else System.out.println("REMIS!!!"); Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 28 14
class KolkoKrzyzyk02 public static void main(string [] args) KK01 kk = new KK01(3); kk.rozgrywka(); Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 29 RUCH GRACZA:......... Podaj numer wiersza (1,3): 1 Podaj numer kolumny (1,3): 1 RUCH KOMPUTERA... XO....... RUCH GRACZA: XO....... Podaj numer wiersza (1,3): 2 Podaj numer kolumny (1,3): 1 Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 30 15
RUCH KOMPUTERA... XOO X..... RUCH GRACZA: XOO X..... Podaj numer wiersza (1,3): 3 Podaj numer kolumny (1,3): 1 Koniec gry!!! XOO X.. X.. Wygrales z komputerem!!! Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 31 Wniosek Zastosowany sposób gry nie jest prawidłowy - gdyż realizuje ruch tylko na podstawie oceny bieżącej sytuacji. Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 32 16
Algorytm minimax Algorytm minimax służy do tworzenia gier dwuosobowych. Wybiera optymalny ruch na podstawie analizy drzewa gry (opisującego wszystkie możliwe do zrealizowania ruchy). Do oceny sytuacji stosowana jest funkcja płatności oceniająca sytuację z punktu widzenia komputera - im wyższa jest jej wartośd, tym lepsza jest pozycja komputera. Podstawowa zasada algorytmu: przy wyborze ruchu komputer maksymalizuje wartośd funkcji płatności, zaś człowiek wykonuje ruch minimalizujący jej wartośd. Drzewo gry analizowane jest od dołu. Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 33 Schemat działania algorytmu minimax Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 34 17
I class KK02 extends KK01 KK02(int n) super(n); Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 35 I int ocenasytuacji(int ktowykonalruch) int wartoscprogowa = 0; switch(ktowykonalruch) case KOMPUTER: if (czywygral(komputer)) return 1000; if (czysapuste()) wartoscprogowa = 9999; for (int i = 0; i < n * n; i++) if (plansza[i/n][i%n] == NIKT) plansza[i/n][i%n] = CZLOWIEK; wartoscprogowa = Math.min(wartoscProgowa, ocenasytuacji(czlowiek)); plansza[i/n][i%n] = NIKT; else return 0; break; Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 36 18
I case CZLOWIEK: if (czywygral(czlowiek)) return -1000; if (czysapuste()) wartoscprogowa = -9999; for (int i = 0; i < n * n; i++) if (plansza[i/n][i%n] == NIKT) plansza[i/n][i%n] = KOMPUTER; wartoscprogowa = Math.max(wartoscProgowa, ocenasytuacji(komputer)); plansza[i/n][i%n] = NIKT; else return 0; // koniec switch return wartoscprogowa; // koniec ocenasytuacji // koniec definicji klasy Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 37 19