Jak działa runGame
:
-
argumenty:
game
,bots
,options
game
: obiekt zawierający polacommand
- polecenie (a właściwie ścieżka do programu), które ma wywołać zarządcę gry orazargs
- lista argumentów, które chcemy przekazać do programu. Do listy argumentów dodane zostaną dwie wartości: ziarno, które program może użyć do losowania oraz liczba graczybots
: lista obiektów opisujących, jak uruchomić boty w takim samym formacie jak dlagame
(tylko boty nie dostają tych dwóch dodatkowych argumentów)options
: obiekt zawierający (lub nie, wtedy brana jest wartość domyślna) 3 pola:timeLimit
: czas w milisekundach, jaki ma bot od momentu wysłania do niego opisu tury do momentu wysłania komend na serwer (domyślnie1000
)messageTimeLimit
: maksymalny czas w milisekundach, jaki może upłynąć pomiędzy dwiema wiadomościami wysłanymi przez nadzorcę (o wiadomościach później). Służy on tylko do wykrywania i ubijania zawieszających się nadzorców. Domyślnie10000
seed
: ziarno przekazane do nadzorcy (domyślnie0
)
-
funkcja tworzy sobie jakiś katalog znajdujący się w
data/games/
, w którym umieści pliki opisujące przebieg gry -
zwraca
Promise
na obiekt zawierający następujące pola:results
: tablica długości równej liczbie botów. I-ta komórka powinna mówić, które miejsce zajął i-ty bot (licząc od 1). Dopuszczalne są remisyinputs
: tablica długości równej liczbie botów, która zawiera ścieżki do plików z wejściem przekazanym z serwera do botówoutputs
: j.w. tylko pliki zawierają wyjście wypisane przez botyerrs
: j.w. tylko pliki zawierają tekst wypisany przez boty nastderr
<- to trzeba jeszcze dopracowaćhistory
: zawiera ścieżkę do jsona, który opisuje przebieg gry. Json ma następujące pola:updates
: obiekt zawierającyturn
- numer tury idescription
- opis świata, który może być dowolny (zależny od gry). Może być kilka update'ów z tym samym numerem tury! To zależy od typu gry - kiedy gra jest taka, że wszyscy wykonują ruchy jednocześnie, zazwyczaj będziemy robić jeden update na turę, kiedy gracze robią ruchy na przemian, będzie kilka update'ów na turę (po każdym ruchu)fails
: lista faili botów (na przykład kiedy bot wypisał niepoprawne wyjście). Każdy wpis zawiera polaplayer
(numer gracza),reason
(wyjaśnienie błędu) iturn
(numer tury). Fail oznacza natychmiastowe wypadnięcie bota z gryresults
: wyniki gry, w takim formacie jak wcześniejinitialInfo
: może zawierać cokolwiek, co gra uzna za potrzebne dla wizualizacji. Może też być nullem
-
nadzorca gry musi dbać o 3 rzeczy:
-
wysyłanie informacji o grze do serwera. W tym celu wypisuje na standardowe wyjście json, który zawsze zawiera pole
type
. Pozostałe pola zależą od typu: Dostępne typy:player_failed
- wtedy wiadomość powinna też zawierać polaplayer
ireason
informujące o tym, który gracz przegrał i dlaczegofinished
- informacja o końcu gry, wiadomość powinna zawierać poleresults
w takim formacie, jak wcześniejupdate
- przesłanie update'a. Zawiera pola:nextTurn
- czy ten update zakończył turę (powinno byćtrue
dla update'a wysyłanego po ruchu ostatniego gracza),description
- jakiś opis świata gryinitial_info
- zawiera poledescription
. Może (ale nie musi) być wysłane raz na początku gry.keep_alive
- raczej nie będzie potrzebne. W przypadku, gdyby gra potrzebowała dużo czasu na obliczenia i nie chciała, żeby serwer ją ubił, może wysyłać co jakiś czas ten komunikat- W Node.JS zamiast wypisywać JSONa na standardowe wyjście, można wysłać odpowiedni obiekt przez funkcję
process.send
. W C++ warto skorzystać z biblioteki https://github.com/nlohmann/json (do działania wymaga tylko ściągnięcia jednego pliku json.hpp)
-
wysyłanie informacji o świecie gry do botów. By wysłać informacje do bota o numerze
i
trzeba utworzyć strumień zapisujący do deskryptora pliku (ang. file descriptor) o numerze2 * i + 3
. Jak nie wiecie, co to deskryptor pliku, to nic nie szkodzi. W C/C++, aby to zrobić, trzeba utworzyć na przykładFILE *output = fdopen(2 * nr + 3, "w")
. Wtedy można pisać do plikuoutput
przezfprintf
. W Pythonie na przykład trzeba użyć funkcji os.fdopen, a w Node.JS odpowiedniej wersji fs.createWriteStream. Wysłany opis może być dowolny (tu już raczej nie używamy JSONów), ale za każdym razem musi się zakończyć osobną linią zawierającąEND
. W C++ ważne jest, żeby po każdym wysłaniu wiadomości wykonaćfflush(output)
. -
odbieranie wiadomości od botów. Tutaj jest analogicznie. Tworzymy strumień czytający z deskryptora pliku
2 * i + 4
(w C++FILE *input = fdopen(2 * nr + 4, "r")
). Także każdy bot, po wysłaniu wszystkich informacji z danej tury, powinien wypisać jedną linię zawierającą słowoEND
. -
boty po prostu działają w pętli (może być nawet nieskończona), w której na zmianę wczytują ze standardowego wejścia opis świata (zakończony linią
END
) i wypisują na wyjście swoje polecenia (też zakończone liniąEND
). Boty też muszą pamiętać offlush(stdout)
-