Skip to content

Latest commit

 

History

History
257 lines (179 loc) · 9.28 KB

index.rst

File metadata and controls

257 lines (179 loc) · 9.28 KB

Gra robotów

Pole gry

Spróbujemy teraz pokazać rozgrywkę z gry robotów <robot-game>. Zaczniemy od zbudowania areny wykorzystywanej w grze. W pliku mcpi-rg.py umieszczamy następujący kod:

Kod nr

python

mcpi-rg01.py

Zaczynamy od definicji klasy GraRobotow, której instancję tworzymy w funkcji głównej main() i przypisujemy do zmiennej: gra = GraRobotow(mc). Konstruktor klasy wywołuje metodę poleGry(), która buduje pusty plac i arenę, na której walczą roboty.

Pole gry wpisane jest w kwadrat o boku 19 jednostek. Część pól kwadratu wyłączona jest z rozgrywki, ich współrzędne zawiera lista obstacle. Funkcja poleGry() wykorzystuje dwie zagnieżdżone pętle, w których zmienne iteracyjne i, j przyjmują wartości od 0 do 18, wyznaczając wszystkie pola kwadratu. Jeżeli dane pole zawarte jest w liście pól wyłączonych if (i, j) in obstacle, umieszczamy w nim blok trawy – wyznaczą one granice planszy. W przeciwnym wypadku dołączamy współrzędne pola w postaci tupli do listy pól dozwolonych: self.plansza.append((x + i, z + j)). Wykorzystamy tę listę później do "czyszczenia" pola gry.

Po uruchomieniu powinniśmy zobaczyć plac gry, a w konsoli listę pól, na których będą walczyć roboty.

Dane gry

Dane gry, czyli zapis 100 rund rozgrywki zawierający m. in. informacje o położeniu robotów oraz ich sile (punkty hp) musimy wygenerować uruchamiając walkę gotowych lub napisanych przez nas robotów.

W tym celu trzeba zmodyfikować bibliotekę game.py z pakietu rgkit. Jeżeli korzystałeś z naszego scenariusza <robot-game> i zainstalowałeś rgkit w wirtualnym środowisku <rg-env> ~/robot/env, plik ten znajdziesz w ścieżce ~/robot/env/lib/python2.7/site-packages/rgkit/game.py. Na końcu funkcji run_all_turns() po linii nr 386 wstawiamy podany niżej kod:

# BEGIN DODANE na potrzeby Kzk
import json
plik = open('lastgame.log', 'w')
json.dump(self.history, plik)
plik.close()
# END OF DODANE

Następnie po wywołaniu przykładowej walki: (env) root@kzk:~/robot$ rgrun bots/stupid26.py bots/Wall-E.py w katalogu ~/robot znajdziemy plik lastgame.log, który musimy umieścić w katalogu ze skryptem mcpi-rg.py.

Do definicji klasy GraRobotow w pliku mcpi-rg.py dodajemy metodę uruchom():

Kod nr

python

mcpi-rg02.py

Omawianą metodę wywołujemy w funkcji głównej main() przekazując jej jako parametry nazwę pliku z zapisem rozgrywki oraz ilość rund do pokazania: gra.uruchom("lastgame.log", 10).

W samej metodzie zaczynamy od sprawdzenia, czy podany plik istnieje w katalogu ze skryptem. Jeżeli nie istnieje (if not os.path.exists(plik):) drukujemy komunikat i wychodzimy z funkcji.

Jeżeli plik istnieje, otwieramy go w trybie tylko do odczytu. Dalej, ponieważ dane gry zapisane są w formacie json, w pętli for runda in json.load(plik): dekodujemy jego zawartość wykorzystując metodę load() modułu json. Instrukcja print runda pokaże nam w konsoli format danych kolejnych rund.

Po uruchomieniu kodu widzimy, że każda runda to lista zawierająca słowniki określające właściwości poszczególnych robotów.

Ćwiczenie 1

Skopiuj z konsoli dane jednej z rund, uruchom konsolę IPython Qt i wklej do niej.

Następnie przećwicz wydobywanie słowników z listy:

– oraz wydobywanie konkretnych danych ze słowników, a także rozpakowywanie tupli (robot['location']) określających położenie robota:

Pokaż rundę

Słowniki opisujące roboty walczące w danej rundzie zawierają m.in. identyfikatory gracza, położenie robota oraz jego ilość punktów hp. Wykorzystamy te informacje w funkcji pokazRunde().

Klasę GraRobotow w pliku mcpi-rg.py uzupełniamy dwoma metodami:

Kod nr

python

mcpi-rg03.py

W metodzie pokazRunde() na początku czyścimy pole gry, czyli wypełniamy je blokami powietrza – to zadanie funkcji czyscPole(). Jak widać, wykorzystuje ona stworzoną wcześniej listę dozwolonych pól. Kolejne tuple współrzędnych odczytujemy w pętli for xz in self.plansza: i rozpakowujemy x, z = xz.

Po wyczyszczeniu pola gry, z danych rundy przekazanych do metody pokazRunde() odczytujemy w pętli for robot in runda: słowniki opisujące kolejne roboty.

W skróconej instrukcji warunkowej sprawdzamy identyfikator gracza: if robot['player_id']. Jeżeli wynosi 1 (jeden), roboty będą oznaczane blokami bawełny, jeżeli 0 (zero) – blokami drewna.

Następnie z każdego słownika rozpakowujemy tuplę określającą położenie robota: x, z = robot['location']. W uzyskanych współrzędnych umieszczamy ustalony dla gracza typ bloku.

Dodatkowo drukujemy kolejne dane w konsoli print robot['player_id'], blok, x, z.

Zanim uruchomimy kod, musimy jeszcze zamienić instrukcję print runda w metodzie uruchom() na wywołanie omówionej funkcji:

Kod nr

python

mcpi-rg03.py

Po uruchomieniu kodu powinniśmy zobaczyć już rozgrywkę:

Kolory

Takie same bloki wykorzystywane do pokazywania ruchów robotów obydwu graczy nie wyglądają zbyt dobrze. Spróbujemy odróżnić od siebie obydwie drużyny i pokazać, że roboty w starciach tracą siłę, czyli punkty życia hp.

Do definicji klasy GraRobotow dodajemy jeszcze jedną metodę o nazwie wybierzBlok():

Kod nr

python

mcpi-rg04.py

Metoda definiuje dwie tuple, po jednej dla każdego gracza, zawierające zestawy bloków używane do wyświetlenia robotów danej drużyny. Dobór typów w tuplach jest oczywiście czysto umowny.

Siła robotów (hp) przyjmuje wartości od 0 do 50, dzieląc tę wartość całkowicie przez 10, otrzymujemy liczby od 0 do 5, które wykorzystamy jako indeksy wskazujące typ bloku przeznaczony do wyświetlenia robota danego zawodnika.

Skrócona instrukcja warunkowa player1_bloki[hp / 10] if player_id else player2_bloki[hp / 10] bada wartość identyfikatora gracza if player_id i zwraca player1_bloki[hp / 10], jeżeli wynosi on 1 (jeden) oraz player2_bloki[hp / 10] jeżeli równa się 0 (zero).

Pozostaje jeszcze zastąpienie instrukcji blok = block.WOOL if robot['player_id'] else block.WOOD w metodzie pokazRunde() wywołaniem omówionej funkcji, czyli:

Kod nr

python

mcpi-rg04.py

Trzeci wymiar

Ćwiczenia

Warto poeksperymentować z wizualizacją gry wykorzystując trójwymiarowość Minecrafta. Można uzyskać spektakularne rezulaty. Poniżej kilka sugestii.

  • Stosunkowo łatwo urozmaicić wizualizację gry używając wartości hp (siła robota) jako współrzędnej określającej położenie bloku w pionie. Wystarczy zmienić instrukcję self.mc.setBlock(x, 0, z, blok) w funkcji pokazRunde().

  • Jeżeli udało ci się wprowadzić powyższą poprawkę i bloki umieszczame są na różnej wysokości, można zmienić typ umieszczanych bloków na piasek (SAND).

  • Można spróbować wykorzystać omawianą w scenariuszu Figury 2D i 3D <mcpifigury> bibliotekę minecraftstuff. Wykorzystując funkcję drawLine() oraz wartość siły robotów robot['hp'] jako współrzędną określającą położenie bloku w pionie, można rysować kolejne rundy w postaci słupków.

Note

Dziękujemy uczestnikom szkolenia przeprowadzonego w ramach programu "Koduj z Klasą" w Krakowie (03.12.2016 r.), którzy zgłosili powyższe pomysły i sugestie.

Źródła:

  • Skrypty mcpi-rg <mcpi-rg.zip>
  • Log RG <lastgame.zip>