Wo ist heute nacht die Party? Wie komme ich da hin? Wie sorge ich dafür, dass die ganzen Spacken nicht kommen? Wie werde ich zur nächsten Party wieder eingeladen? Wir coden Studenten, die alle versuchen, mehr Spaß als die anderen zu haben.
Wie schon die letzten Jahre wird es hier eine kurze Einführung geben. Der Server läuft dann die ganze Zeit. Oder auch nicht. Wir warten noch auf unseren eigenen internen Server. Stay tuned.
Worum geht's?
Jede Spielrunde geht ueber mehrere Tage. Jeder Tag besteht aus der Tagesphase und der Nachtphase. Tagsueber wird kommuniziert und umhergelaufen. Nachts wird gefeiert und es gibt dafuer Punkte. Jeder Mitspieler schreibt sich ein Programm, welches sich mit dem Server verbindet und einen Spieler steuert.
Es gibt 10 unterschiedliche Orte. An einem dieser Orte findet jede Nacht eine Party statt. Ein oder zwei zufaellige Spieler bekommen morgens Bescheid gesagt, wo die Party stattfindet. Sie koennen nun entscheiden, welchen anderen Spieler die davon in Kenntnis setzen. Um mit anderen Spielern zu kommunizieren muessen sich beide am selben Ort befinden oder sich bereits von vorherigen Partys kennen (aka Handynummern getauscht haben). Einem anderen Spieler kann dabei mitgeteilt werden, wo eine Party stattfindet, wo keine Party stattfindet, dass ein anderer Spieler luegt oder ein anderer Spieler die Wahrheit sagt. Natuerlich muss keine der gemachten Aussagen wahr sein.
Damit die nachts stattfindende Party Spass macht und dafuer Punkte verteilt werden, muss sich eine Mindestanzahl von Spielern dort einfinden. Sind es zu wenig Spieler, so bekommt niemand Punkte. Sind es zu viele, bekommt zwar jeder Punkte, allerdings verringert sich dadurch die Punkteanzahl.
Technisches
Der Server ist per TCP erreichbar und spricht ein einfaches Klartextprotokoll. Nachrichten umfassen immer genau eine durch Newline beendete Zeile. Jede Art von Nachricht hat dabei folgendes Format:
<TYP> <#args> [<arg1> <arg2> ...] : <Human-Readable>
TYP gibt an, um welche Art von Nachricht es sich handelt. #args gibt an, viel Parameter diese Nachricht hat. Anschliessend folgen die einzelnen Parameter. Zu Debuggingzwecken, und um das Protokoll kennen zu lernen folgt am Ende der Zeile jeweils noch eine Menschlesbare Version der Nachricht.
TYP, #args und die Argumente sind immer durch SPACE getrennt. Es gibt zwei Arten von Argumenten: Ganzzahlen und Strings. Ganzzahlen stehen direkt in ihrer Stringrepresentation da, Strings werden durch umschliessende doppelte Anfuehrungszeichen gekennzeichnet.
Hier die Ausgabe nach dem Einloggen und einem kompletten (langweiligen) Tages-Nacht-Zyklus:
71 0 : Welcome to the party game. Please log in. login foo bar 20 1 "foo" : player foo has entered the game 70 0 : welcome foo 41 1 10 : the next game will start in 10 seconds 41 1 9 : the next game will start in 9 seconds 41 1 8 : the next game will start in 8 seconds 41 1 7 : the next game will start in 7 seconds 41 1 6 : the next game will start in 6 seconds 41 1 5 : the next game will start in 5 seconds 41 1 4 : the next game will start in 4 seconds 41 1 3 : the next game will start in 3 seconds 41 1 2 : the next game will start in 2 seconds 41 1 1 : the next game will start in 1 seconds 42 0 : starting 43 1 "p58" : you are 'p58' 22 2 "p58" 0 : you spawned in 0 60 1 0 : there is a party at 0 65 1 10 : you have 10 actions 50 1 1 : day 1 started 51 1 5 : the day ends in 5 seconds 51 1 4 : the day ends in 4 seconds 51 1 3 : the day ends in 3 seconds 51 1 2 : the day ends in 2 seconds 51 1 1 : the day ends in 1 seconds 52 0 : the sun is falling. prepare to party 53 1 1 : night 1 started 60 1 0 : the party in at 0 61 2 "p0" 4 : p0 in in 4 61 2 "p58" 0 : p58 in in 0 63 2 1 2 : this is a boring party. only 1 people. no points tonight. 54 1 5 : the night lasts for 5 seconds 54 1 4 : the night lasts for 4 seconds 54 1 3 : the night lasts for 3 seconds 54 1 2 : the night lasts for 2 seconds 54 1 1 : the night lasts for 1 seconds 55 0 : night ends 65 1 10 : you have 10 actions 50 1 2 : day 2 started
Die zweite Zeile enthaelt den Loginbefehl, der an den Server geschickt wurde. Alles andere sind Zeilen die der Server an die Client geschickt hat.
Es gibt nur XXX Befehle:
login <user> <pass> | Einloggen. Das ist die erste Aktion. |
goto <location> | Tagsueber zu gegebenem Ort laufen. Verbraucht eine Aktion. |
party <playerid> <location> | Spieler <playerid> von einer Party an Ort <location> benachrichtigen. Nur moeglich, sofern sich der Spieler am selben Ort befindet oder bereits durch eine fruehere Party bekannt ist. |
no_party <playerid> <location> | Spieler <playerid> von nicht stattfindender Party an Ort <location> benachrichtigen. Nur moeglich, sofern sich der Spieler am selben Ort befindet oder bereits durch eine fruehere Party bekannt ist. |
liar <playerid> <aboutplayerid> | Spieler <playerid> ueber einen luegenden Spieler <aboutplayerid> benachrichtigen. |
recommand <playerid> <aboutplayerid> | Spieler <playerid> ueber einen vertrauenswuerdigen Spieler <aboutplayerid> benachrichtigen. |
Natuerlich muessen die gemachten Aussagen nicht stimmen :-)
Libraries und Beispielcode
Lisp
Einen client-rohbau in lisp gibt es hier.
Python
Einen Client-Adapter in Python gibt es hier
Verwendung:
#!/usr/bin/python from pyParty import * class PartyClient(PartyAdapter): def __init__(self): PartyAdapter.__init__(self, "partynator2", 1234) def messageReceived(self, type, args, comment, line): print "%s %s %s" % (type, args, comment) if __name__ == "__main__": runPartyClient(PartyClient)
Haskell
Auf http://darcs.nomeata.de/haskell-partty/ findet ihr ein Haskell-Framework (Partty.hs), das euch die Kommunikation und einiges an Book-Keeping über den aktuellen Zustand abnimmt. Damit ist ein einfacher Bot schnell geschrieben. Die ideale Gelegenheit Haskell zu lernen! Dort findet ihr auch 6 fertige Bots (und zwei nicht ganz sinnvolle) zum herumspielen.
Inzwischen ist das Modul auch vollständig dokumentiert. Wenn ihr wollt dass die Links auf andere Definition stimmen, könnt ihr die Doku mit ./gendoc.hs neu generieren.
import Control.Monad.Trans import Control.Monad.State import Control.Monad.Reader import System.Random import Partty {- - Stupid player: Goes to a party it knows about for sure, otherwise guesses -} type UserData = () dcb :: DayCallback UserData dcb (DayStarts _) = do mbp <- asks psPartyPlace room <- case mbp of Nothing -> do say $ "No idea where to go, guessing..." liftIO $ randomRIO (0,9) Just room -> do say $ "Yay, I know where to go! (" ++ show room ++")" return room send (Goto room) dcb e = return () ncb :: NightCallback UserData ncb (NightResult {nrScore = score }) = do say $ "Got score: " ++ show score main = parttyMain dcb ncb ()