W ramach tego laboratorium poznamy środowisko GVG-AI. Nauczymy się uruchamiać symulacje i przygotujemy podstawowego bota.

Wstęp

Często w grach komputerowych spotykamy się z postaciami sterowanymi przez sztuczną inteligencję. Przeważnie jednak decyzje podejmowane przez takie postacie są wynikiem działania algorytmu dostosowanego do danej gry i roli, jaka jest przypisana sterowanej jednostce.

General Game Playing jest pewnym uogólnieniem tej koncepcji. Są to zawody polegające na tworzeniu systemu sztucznej inteligencji, której zadaniem jest zwycięstwo w grach turowych. General Video Game Playing jest modyfikacją General Game Playing pozwalającą modelować gry czasu rzeczywistego.

W obu przypadkach bot ma za zadanie ukończyć grę z jak najlepszym wynikiem, mimo że w momencie tworzenia programu nie są znane zasady rządzące grą, w której zostanie umieszczony bot.

Przygotowanie

By zacząć zabawę z GVG-AI należy z oficjalnej strony pobrać kod frameworku. http://www.gvgai.net/software.php

Aby niniejsza instrukcja była uniwersalna, uruchomienie kodu opierać będę o narzędzie ANT. Dlatego przyda się ono, jeśli nie chcesz samemu dochodzić, jak uruchomić przykłady.

Ze strony http://ant.apache.org/bindownload.cgi (sekcja Current Rrelease of Ant) pobieramy paczkę z narzędziem i rozpakowujemy na naszym dysku. Po rozpakowaniu paczki musimy ustawić kilka zmiennych środowiskowych:

  • ANT_HOME – folder, gdzie rozpakowano anta
  • JAVA_HOME – katalog domowy Javy, którą będziemy używać do kompilacji i uruchomienia przykładów
  • PATH – tutaj warto dodać ścieżkę $(ANT_HOME)/bin/ant

Zapoznanie się z dostępnymi planszami treningowymi

By zobaczyć framework w działaniu rozpoczniemy uruchamiając przykładową grę, w której my będziemy sterować bohaterem. W konsoli przechodzimy do folderu, w którym umieszczono rozpakowane GVG-AI. Tam wykonujemy komendę ant run. Jeżeli nie zmieniono nic w kodzie źródłowym, po skompilowaniu uruchomiona zostanie prosta gra RPG, którą sterujemy przy użyciu strzałek i spacji. Jeżeli już wygraliście, (lub co bardziej prawdopodobne, dopadły was duchy, lub pająki), zostaje nam wyłączyć grę i w razie ochoty uruchomić ponownie.

Jeśli jednak ta gra już Cię znużyła, możesz przyjrzeć się innym planszom. Aby to zrobić musimy zmodyfikować kod pliku Test.java. Znajduje się on w ścieżce src/Test.java. W pliku tym znajduje się jedynie klasa Test z metodą main. Metoda ta ma jednak pewną strukturę. Znajdziemy tam:

  • nazwy przykładowych botów, które są dostarczone razem z frameworkiem
  • zestawy gier, które należały do kolejnych zawodów GVG-AI
  • kod odpowiedzialny za uruchomienie gry

Teraz najbardziej będzie interesować nas ostatnia sekcja.

//Game and level to play
int gameIdx = 0;
int levelIdx = 0; //level names from 0 to 4 (game_lvlN.txt).
String game = gamesPath + games[gameIdx] + ".txt";
String level1 = gamesPath + games[gameIdx] + "_lvl" + levelIdx +".txt";
 
// 1. This starts a game, in a level, played by a human.
ArcadeMachine.playOneGame(game, level1, recordActionsFile, seed);

Plansze są zdefiniowany przy użyciu języka Video Game Description Language. Pliki z ich definicjami znajdują się w katalogu examples/gridphisics. Kod powyżej nie przypadkowo jest opatrzony komentarzem „Game and level to play”. Jest to przepis na przygotowanie parametrów wskazujących poziom do uruchomienia. Aby zatem uruchomić ulubioną grę, wystarczy nadpisać zmienne game i levelIdx:

game = gamesPath + "pacman" + ".txt";
levelIdx = 4;

Po uruchomieniu polecenia ant run powinna się uruchomić wybrana przez nas gra. Dla każdej planszy są zdefiniowane cztery poziomy. Gier jest 41. Tyle zabawy!

Zapoznanie się z przykładowymi botami

Gdy już zagracie na wszystkich planszach, można zobaczyć, jak radzą sobie na nich boty napisane przez twórców frameworku. Dostępne są kontrolery:

  • controlers.sampleRandom.Agent - symuluje wykonanie losowej akcji i jeśli nie powoduje ona przegranej, to podejmuje ją w grze;
  • controllers.sampleonesteplookahead.Agent - symuluje wykonanie wszystkich ruchów dostępnych w danej turze i dla każdego z nich, na podstawie własnej heurystyki, szacuje o ile zbliża on do zwycięstwa. Podejmuje ten, który daje na to największą szansę;
  • controllers.sampleMCTS.Agent - symuluje wykonanie kolejnych akcji na podstawie algorytmu Monte Carlo Tree Search (o którym dowiecie się na następnych laboratoriach). Podejmuje ruch wskazany przez MCTS za najlepszy;
  • controllers.sampleOLMCTS.Agent - działa podobnie jak poprzedni, z drobną modyfikacją (stan nie jest przechowywany w drzewie, lecz przy symulacji generowany na nowo; zdaniem autora przydaje się w grach z elementem losowości);
  • controllers.sampleGA.Agent - kolejną akcję wybiera przy użyciu algorytmu genetycznego;
  • controllers.Tester.Agent - do wybierania ruchu wykorzystuje MCTS, lecz wcześniej sprawdza, czy gra jest deterministyczna.

Aby uruchomić grę sterowaną przez jednego z powyższych botów, musimy:

  • zakomentować linię uruchamiającą grę sterowaną przez nas:
//ArcadeMachine.playOneGame(game, level1, recordActionsFile, seed);
  • odkomentować znadującą się poniżej linię:
// 2. This plays a game in a level by the controller.
ArcadeMachine.runOneGame(game, level1, visuals, sampleMCTSController, recordActionsFile, seed);
  • sposób wyboru planszy pozostaje niezmieniony;
  • czwarty argument odkomentowanego wywołania odpowiada za wybór bota, który będzie sterował rozgrywką i podaje się go poprzez String wskazujący klasę bota (możemy tu posłużyć się stałymi definiowanymi w pierwszej sekcji funkcji main);
  • ponownie wywołać polecenie ant run.

Przykładowe boty nie należą do najlepszych w swojej klasie. Z grami radzą sobie słabo, a niektóre z nich nie wyrabiają się w oczekiwanym czasie dla gier z większym stanem (stąd ich bezruch, lub natychmiastowa przegrana; proszę zajrzeć w logi konsoli) Mają one służyć za przykład, jak takiego bota można napisać i co oferuje framework, a nie być czarnymi końmi w zawodach GVG-AI.

Tworzenie własnego bota

Aby poznać możliwości jakie daje nam framework stworzymy prostego bota, który zachowuje się podobnie jak controlers.sampleRandom.Agent.

Proszę stworzyć plik Agent.java w ścieżce src/myRandom i wkleić poniższy kod, a następnie spróbować uzupełnić kod metody act na podstawie komentarzy i wskazówek pod szablonem kodu:

Agent.java
package myRandom;
 
import core.game.StateObservation;
import core.player.AbstractPlayer;
import ontology.Types;
import tools.ElapsedCpuTimer;
 
import java.util.Random;
 
/**
 * Created by Marek on 08.06.2016.
 */
public class Agent extends AbstractPlayer {
 
    private Random random;
 
    public Agent(StateObservation observation, ElapsedCpuTimer timer)
    {
 
    }
 
    @Override
    public Types.ACTIONS act(StateObservation observation, ElapsedCpuTimer timer) {
        // pobierz dostępne akcje
        // powtarzaj:
            // wylosuje jedną akcję z dostępnych
            // stwórz kopię stanu
            // na kopii zaaplikuj wylosowaną akcję
            // jeżeli pozostało mało czasu, lub wylosowano ruch nie powodujący przegranej, to zakończ pętlę
        // zwróć wylosowaną akcję
    }
}

Uwagi i wskazówki dotyczące powyższego kodu:

  1. aby stworzyć własnego bota, musimy go zdefiniować w klasie Agent, która dziedziczy po klasie AbstractPlayer.
  2. w naszej klasie musimy zaimplementować dwie metody:
    • konstruktor public Agent(StateObservation observation, ElapsedCpuTimer timer) - inicjalizacja bota
    • metodę public Types.ACTIONS act(StateObservation observation, ElapsedCpuTimer timer) - przez tą metodę framework odpytuje naszego bota, na jaki ruch ma ochotę
  3. argumenty metody act pozwalają botowi na obserwację środowiska, w jakim został umieszczony. Metody, które przydadzą nam się do uzupełnienia kodu:
    1. ArrayList<Types.ACTIONS> StateObservation.getAvailableActions() – zwraca listę akcji dostępnych w danym kroku w grze.
    2. StateObservation StateObservation.copy() – standardowa, głęboka kopia obiektu.
    3. void advance(Types.ACTIONS) – przeprowadzenie symulacji na stanie. Modyfikuje stan tak, jakby funkcja act zwróciła akcję podaną w argumencie. Dla zdarzeń losowych (ruchy przeciwników itp.) jest dobierana losowa akcja, dlatego nowy stan nie musi się w pełni pokrywać z tym, jaki dostaniemy w grze. Ważne jest, że wywołanie tej metody trwale modyfikuje stan, dlatego, jeśli nie chcemy tracić referencji do stanu otrzymanego od frameworku, musimy ją wywoływać na kopii.
    4. long EclapsedCpuTimer.remainingTimeMillis() – zwraca informację, ile dostępnego czasu pozostało na obliczenia.
    5. boolean StateObservation.isGameOver() – zwraca informację, czy gra została ukończona
    6. Types.WINNER StateObservation.getGameWinner() – zwraca informację, czy gracz wygrał daną rozgrywkę.

Gdy zaimplementujemy już naszego bota, uruchomimy go podobnie jak robiliśmy to dla przykładowych botów dostępnych w frameworku. W punkcie, gdzie była mowa o wyborze bota, za czwarty argument podajemy „myRandom.Agent”. Powstały bot powinien być nieco bardziej ruchliwy niż prezentowane w przykładach.

pl/dydaktyka/wshop/prv/2016/gvgai/start.txt · ostatnio zmienione: 2019/06/27 15:50 (edycja zewnętrzna)
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0