Projekt Poker Bot Engine
Transkrypt
Projekt Poker Bot Engine
Wydział Elektrotechniki, Automatyki, Informatyki i Elektroniki Kierunek: Informatyka Laboratorium Computer Games Projekt Poker Bot Engine Opracowali: Maciej Bożętka Piotr Siatka 1. Cel projektu Celem projektu, który mieliśmy zrealizować w ramach laboratorium z przedmiotu Computer Games była implementacja silnika gry pokerowej Texas Holdem, który mógłby umożliwić twórcom pokerowych botów ich testowanie, oraz rywalizowanie między sobą. Należało zrealizować proste narzędzie umożliwiające użytkownikom testy lokalne, jak i w połączeniu z grupą realizującą mechanizm komunikacji grę online, pozwalającą na implementację botów w dowolnym języku programowania. Sama platforma powstała z wykorzystaniem języka Java. 2. Implementacja Implementację można podzielić na trzy zasadnicze części – kontener przechowujący wszystkie informacje wykorzystywane w grze, mechanizm przeprowadzający rozgrywkę, oraz część sprawdzającą na końcu rozgrywki, który z użytkowników ma najsilniejsze karty. Logicznie, projekt składa się z dwóch części: PokerTableCommons i PokerTableEngine, podział taki został wytworzony z racji wykorzystywania zarówno przez projekt komunikacji jak i nasz pewnych wspólnych klas. Sercem naszego projektu jest klasa Game. To ona przechowuje informacje o graczach siedzących przy stole, uczestniczących dalej w grze, kartach leżących na stole, rundach które są do rozegrania, aktualną rundę i indeks zawodnika, który jest aktualnie dealerem. Gracza reprezentuje klasa interfejs IPlayerBasic, którą w momencie kiedy czas na ruch danego zawodnika odpytujemy o jego decyzję (wywołując na nim jego funkcję getDecision()). Po naszej stronie gracza reprezentujemy również za pomocą klasy PlayerGame, w której przechowujemy pieniądze, które położył na stole, jego karty, ostatnią decyzję oraz to, czy zagrał allIn. Rozgrywka przebiega zgodnie z zasadami pokera Texas Holdem. Przy tworzeniu gry dostajemy listę użytkowników, którzy w niej uczestniczą. Następnie inicjalizowane są wszystkie rundy. Każda z rund (preflop, flop, turn i river) dziedziczą po klasie RoundBase, której istotną częścią jest uniwersalne dla wszystkich rund przetwarzanie decyzji użytkownika. Poszczególne implementacje klas różnią się funkcją startRound(), gdzie podejmowane są akcje charakterystyczne dla poszczególnych rund. W funkcji startGame() klasy Game wykonuje się pętla, przeprowadzająca wszystkie rundy. Decyzje graczy są analizowane w funkcji processRound() bazowej klasy rund. Funkcja ta działa dopóki na stole nie zostanie jeden zawodnik, bądź wszyscy nie podbili, względnie nikt nie chce podbijać dalej. Poszczególne decyzje graczy analizowane są w funkcji processDecision(). Każdy gracz zwraca w odpowiedzi na wywołanie na nim funkcji getDecision() instancję jednej z klas implementujących interfejs IDecision (Bet, Call, Check, Fold). Obiekt ten trafia do processDecision() i jest w nim podejmowana decyzja w zależności od tego jakiej instancji jest klasa i czy spełnione zostały wszystkie wymagania dla danej decyzji. Zawodnik, który podejmie błędną decyzję (np. poda zbyt małą kwotę przebijając, bądź będzie chciał przebić o więcej niż posiada) zostaje wyrzucony z gry. Po przejściu wszystkich rund następuje przepisanie stanu pieniędzy z wewnątrz rundy do handlera użytkownika i (jeśli w grze został więcej niż jeden gracz) wyszukanie zwycięzcy. Służą do tego klasa HandChecker, której na początku wysyłane są karty wszystkich pozostałych do finału rozgrywki użytkowników w celu znalezienia ich najlepszej figury (odpowiada za to funkcja getBestPlayerHand()), a następnie z wykorzystaniem funkcji getBestFromHand() odnaleziony zostaje zwycięzca – bądź zwycięzcy, jeśli mamy do czynienia z remisem. Po sprawdzeniu kto wygrał następuje rozesłanie informacji o wynikach do zawodników i odpytanie, czy chcą kontynuować grę, jeśli skończyły im się pieniądze (na zasadzie repay’u z banku, który na końcu rozgrywki zostanie im odjęty od ostatecznego rozrachunku). Po tym index dealera jest przesuwany do przodu i rozgrywana jest kolejna partia, których ilość jest argumentem konstruktora gry. 3. Użytkowanie Korzystanie z projektu w wersji offline jest bardzo proste. Najpierw należy pobrać z SVNa projekty PokerTableCommons i PokerTableEngine. Aby móc z nich korzystać należy mieć zainstalowanego mavena w wersji co najmniej 2.0. Zbudować projekt można z konsoli, wywołując mvn –U cleaninstall najpierw w katalogu z plikiem pom.xml projektu PokerTableCommons, a następnie projektu PokerTableEngine. Wygodniejszym rozwiązaniem będzie jednak niewątpliwie skorzystanie z Eclipse’a i wtyczki do obsługi mavena z jego poziomu, np. m2e. Po ściągnięciu projekty powinny zachowywać się w Eclipsie poprawnie, jednak dla wszelkiej pewności warto przed jakimikolwiek modyfikacjami wejść do obydwu katalogów z projektami i wykonać komendę mvneclipse:eclipse. Bot implementowany do gry z wykorzystaniem naszej platformy powinien rozszerzać klasę PlayerBasicImpl. Zasadnicza część implementacji to wspomniana funkcja getDecision, w której Bot otrzymuje informacje o stanie rundy i karty, które posiada. Informacje o rundzie zawarte są w obiekcie implementującym interfejs IRound: publicinterfaceIRound { public String getName(); publicIterable<IPlayerInfo>getPlayersInfo(); publicIterable<Card>getTableCards(); publicintgetTableMoney(); publicintgetMinRaiseVal(); publicintgetCallValue(intplayerId); publicintgetMinBetValue(intplayerId); } Na podstawie tych informacji należy zwrócić jedną z klas Bet, Call, Check lub Fold z odpowiednimi parametrami. Utworzonego zgodnie z powyższymi założeniami bota można przetestować wpinając go do gry w klasie GameTest i uruchamiając ją. Testy mogą wspomóc przykładowe boty: PokerBot_call, PokerBot_fold, PokerBot_raise, PokerBot_random, zachowujące się zgodnie ze swoimi nazwami. Platforma poza zastosowaniem offline wykorzystywana jest w działającym na serwerze projekcie pokerTable, który w założeniu ma być niezależny od języka implementacji. W tym zastosowaniu projekt nasz nie wywołuje funkcji bezpośrednio na użytkownikach, ale na odpowiednich Proxy dostarczanych nam przez komunikację.