Kortspelet Plump Projekt i Nätverksprogrammering (EDA095) Markus Larsson - atp10mla@student.lu.se Daniel Forsman - atp10dfo@student.lu.se Eric Ottosson - ada10eot@student.lu.se Antonina Tokarchuk - ada10ato@student.lu.se 21 maj 2014 1
1 Beskrivning av spelet Plump I projektet har en nätverksbaserad version av kortspelet plump utvecklats. Plump är ett kortspel för 2-5 spelare och består oftast av 10 rundor. Om man väljer att spela med 10 rundor så inleds den första rundan med att samtliga spelare tilldelas 10 kort. Spelaren efter den spelare som delade ut kort ska därefter säga hur många stick den tror att den kommer att ta. Ett stick får den spelare som vid en given stickomgång lagt högsta trumfen och om en sådan ej är lagd högst valör i den färg som den första spelaren i stickomgången lade. För att förstå detta måste tre begrepp förklaras: Trumf - Den mest värdefulla färgen under rundan. Bestäms i början av varje runda och bibehålls under hela rundan. Ett trumfkort måste läggas om en spelare ej har några kort på sin hand som har samma färg som det kort den första spelaren lade i den stickomgången. Om en spelare har ett eller flera kort i samma färg, så måste den lägga ett av dessa kort. Då en spelare är först att lägga ut ett kort i en stickomgång är det fritt fram för denna att välja vilket kort som helst på dess hand. Valör - Varje kort har en valör där korten 2-10 har värdet 2-10, knekt 11, dam 12, kung 13 och ess 14. Stickomgång - Innebär att varje spelare i medsols riktning från den första spelaren har lagt ett kort. Därmed består en runda av lika många stickomgångar som vardera spelare har kort. En stickomgång för en given runda inleds med att spelaren som satsade på att den skulle få flest stick börjar. Om flera har valt lika antal stick så börjar den som sitter till vänster om givaren. Resterande stickomgångar inleder den spelare som vann föregående stick. För att varje spelare inte ska kunna lyckas ta rätt antal stick varje runda finns där en regel som säger att det totala antalet bjudna stick ej får vara samma som antalet kort i omgången. Därför får den sista personen att säga antalet kort i varje stickomgång ej välja ett antal stick så att totala antalet stick är samma som antalet kort som varje spelare har på handen. Efter en avslutad runda erhålls poäng till de spelare som lyckades ta lika många stick som de trodde att de skulle ta. Poängsättningen är sådan att man får 10 poäng plus antalet stick man tog. Om en spelare önskade noll stick, får denna spelare enbart 5 poäng om den lyckades. Om den första rundan startades med 10 kort, spelas nästa med 9 kort och så fortsätter det fram till man genomfört rundan med 1 kort. Efter den rundan påbörjar man rundorna som ska ta spelet upp till rundan med 10 kort igen. Det vill säga elfte rundan har 1 kort, tolfte rundan 2 kort och så vidare. När den sista rundan är avslutad räknas poängen ihop och spelaren eller spelarna med högst poäng vinner spelet. Kortspelets regler kan variera något, men det är dessa regler som vår nätverksbaserade version av spelet bygger på. 2 Kravspecifikation Varje spelare representeras av en klient som kan ansluta till ett spel (server). 2
Funktionalitet: 1. Varje spelare ska kunna se korten i takt med att de spelas. 2. Varje spelare ska kunna se samtliga spelares önskade och i nuläget tagna antal stick. 3. Varje spelare ska alltid kunna se alla sina egna kort. 4. Det ska finnas en poängtavla som visar poängen för varje spelare i realtid. 5. Spelsystemet ska vara anpassat för 2-5 spelare och maximalt 10 kort i en runda. 6. Om en spelare avbryter ska en bot gå in och lägga slumpmässiga kort för den givna spelaren. 7. Det ska finnas en tidsbegränsning för respektive spelare att lägga ett nytt kort. Om tidsgränsen går ut ska ett slumpmässigt kort läggas. 8. En spelare har tillåtelse att ansöka om två minuter extra betänketid för att hinna att lämna spelet en kort stund. Ansökan om extra betänketid ska tydligt visas för övriga spelare. 9. Det ska synas en klocka för respektive spelare som visar återstående betänketiden. 10. Från att den första spelaren har anslutit till servern har återstående spelare 2 minuter på sig att ansluta. Möjliga framtida extra funktioner: Möjlighet för en spelare att starta ett nytt spel där den anger inställningar för spelet, t.ex. antalet rundor. Utveckla servern så att den kan hantera flera spel samtidigt. Implementera en chattfunktion i spelet. 3 Design 3.1 Klient Programmet är uppdelat i två olika delar: en klient och en server. Klienten är den del av programmet som användaren interagerar med och består utav ett gränssnitt som tar emot in-data från användaren, samt ett antal klasser för att hantera data och input/output. 3.1.1 Klasser Klienten är uppdelad i 8 klasser som tar hand om in-data, gränssnitt etc. vilka, tillsammans med relationer, finns illustrerade i Figur 1. Bland dessa klasser är de viktigaste de som tar hand om interaktionen med användaren, in- och ut-data samt hur data lagras i programmet. Nedan följer korta beskrivningar av de viktigaste klasserna i klienten; vad de gör, hur de fungerar och hur de kommunicerar med andra klasser. 3
Figur 1: UML-diagram som beskriver klientens klasser och dess förhållanden (privata metoder/variabler är gömda). 4
GUI.java Denna klassen representerar det grafiska gränssnitt som användaren interagerar med. I gränssnittet presenteras all relevant information om spelets nuvarande tillstånd, som t.ex. poäng, de kort man har på hand, det senaste spelade kortet etc. De viktigaste uppgifterna för klassen är att presentera information och att ta emot in-data från användaren. Detta sker genom att ett ISHandler-objekt anropar funktioner för att uppdatera gränssnittet med ny information, samt genom att använda den privata klassen CardListener som lyssnar på interaktioner med ett kort på handen. All interaktion med gränssnittet resulterar i att informationen i monitorn uppdateras. ISHandler.java Denna klass representerar en tråd som tar emot in-data från den server klienten är ansluten till; den typ av in-data som accepteras definieras i det gemensamma protokollet. Klassen tar emot kommandon och in-data genom att konstant försöka läsa data från en InputStream. Om den lyckas ta emot in-data så utför den, beroende på mottaget kommando, olika operationer med gränssnittet. OSHandler.java Denna klass representerar en tråd som skickar ut-data till den server klienten är ansluten till; den typ av ut-data som skickas definieras i det gemensamma protokollet. Klassen skickar kommandon och ut-data som den konstant försöker hämtar från monitorn genom att skriva till en OutputStream. Om det inte finns något kommando att hämta så väntar tråden tills monitorn notifierar den att ett nytt kommando finns att hämta. Monitor.java Denna klass representerar den monitor som klienten använder för att förmedla information mellan de olika klasserna. Monitorn använder sig av javas inbyggda synkronisering för att blockera parallell åtkomst av data. I monitorn lagras en lista av kommandon som ska skickas till servern, det (eventuellt) valda kortet samt antalet stick. Denna data uppdateras av gränssnittet och hämtas utav OSHandler som skickar den över nätverket. Protocol.java Denna klass innehåller information om hur olika kommandon ska representeras när de skickas mellan klient och server. Varje kommando representeras av ett unikt heltal. 3.1.2 Trådar Klienten består utav 2 huvudtrådar och 5 temporära trådar som skapas och startas vid specifika händelser, se Figur 2. Huvudtrådarna är de trådar som körs av ISHandler och OSHandler och är de trådar som tar emot och skickar data mellan klient och server. De temporära trådarna är av två olika typer: dels 3st TimerThreads som är trådar som lagrar en Action som sedan utförs efter ett visst tidsintervall, dels två vanliga Java Threads som skapas temporärt för att uppdatera monitorn med information från gränssnittet. Syftet med TimerThreadsen är att implementera en tidsbegränsning på hur lång tid en spelare får ta på sig att utföra sitt nästa drag. T.ex. så kommer ett slumpmässigt kort från spelarens hand att spelas om denne inte väljer något kort inom 30 sekunder. 5
Figur 2: Diagram som visar de trådar och monitorer som finns i klienten, samt hur data flödar mellan dem (gröna trådar är temporära trådar). 3.2 Server Servern är den del av programmet som spelklienter ansluter till och innehåller den största delen av en av spelet. Den tar emot ett begränsat antal klienter och behandlar all in-data från dessa, samt förser klienterna med uppdaterad information om spelets nuvarande tillstånd under spelets gång. 3.2.1 Klasser Servern är uppdelad i 8 klasser som tar hand om in-data, spellogik etc. vilka, tillsammans med relationer, finns illustrerade i Figur 3. Bland dessa klasser är de viktigaste de som tar hand om spellogiken, in- och ut-data samt hur data lagras i programmet. Nedan följer korta beskrivningar av de viktigaste klasserna i servern; vad de gör, hur de fungerar och hur de kommunicerar med andra klasser. InputHandler.java Denna klass representerar en tråd som tar emot in-data från en viss klient som är ansluten till servern; den typ av in-data som accepteras definieras i det gemensamma protokollet. En tråd (dvs. objekt av klassen) skapas för varje klient som ansluter. Klassen tar emot kommandon och in-data genom att konstant försöka läsa data från en InputStream. Om den lyckas ta emot in-data så lagrar den den mottagna informationen i monitorn. OutputHandler.java Denna klass representerar en tråd som skickar ut-data till den klient servern är ansluten till; den typ av ut-data som skickas definieras i det gemensamma protokollet. En tråd (dvs. objekt av klassen) skapas för varje klient som ansluter. Klassen skickar kommandon och ut-data som den konstant försöker hämta från monitorn genom att skriva till en OutputStream. Om det inte finns något kommando att hämta så väntar tråden tills monitorn notifierar den att ett nytt kommando finns att hämta. Monitor.java Denna klass representerar den monitor som servern använder för att förmedla information mellan de olika klasserna. Monitorn använder sig 6
Figur 3: UML-diagram som beskriver serverns klasser och dess förhållanden (privata metoder/variabler är gömda). 7
Figur 4: Diagram som visar de trådar och monitorer som finns i servern, samt hur data flödar mellan dem (notera att varje unik spelare har sina egna inputoch output-trådar). av javas inbyggda synkronisering för att blockera parallell åtkomst av data. I monitorn lagras information om vilka kort som finns kvar i kortleken, vilka klienter som är anslutna, vilka kort som har spelats och vilka kommandon som ska skickas till var och en av de anslutna klienterna. Datan uppdateras av de skapade InputHandler-objekten och hämtas av de skapade OutputHandlerobjekten. För att kunna förmedla kommandon och ny data till alla anslutna klienter så har varje klient sin egen lista med kommandon (lagras som en HashMap med Player/List-par). Samma struktur används även för att lagra de kort varje spelare har spelat. Player.java Denna klassen representerar en spelare (en ansluten klient) som deltar i det nuvarande spelet. Klassen lagrar information om till vilken OutputStream som ut-data för spelaren skall skickas till, samt funktioner för att beräkna poäng. 3.2.2 Trådar Servern består utav 1 konstant tråd och 2 extra trådar för varje ansluten klient, se Figur 4. Den konstanta tråden StartGun tar hand om att starta spelet när tillräckligt många klienter anslutit eller när tiden för att ansluta tagit slut. De 2 extra trådarna är de trådar som körs av InputHandler och OutputHandler för varje ansluten klient och tar emot och skickar ut-data till och från klienter. 3.3 Nätverkskommunikation Kommunikation mellan varje klient och server utförs via en TCP-anslutning som skickar och tar emot data via Input- och OutputStreams. Genom att använda dessa inbyggda klasser så kan vi skicka objekt (strängar, heltal etc.) direkt över nätverket utan att behöva bry oss om hur de kodas och avkodas på vägen. 8
Den data som skickas via TCP kan utformas som ett paket som består utav två delar: ett kommando och den data som skall skickas. Kommandon hämtas direkt från det definierade protokollet och skickas som heltal, medan datan kan innehålla sådana saker som vilket kort som spelades (färg och valör) och antalet valda stick. Tack vare det bra stödet för TCP-anslutningar hos Java, och att programmet har små och simpla data-typer, så är nätverkskommunikationen en av de enklare delarna i programmet. 4 Användningsanvisningar Programmet, vars delar ni finner på hemsidan http://users.student.lth. se/atp10dfo/network/#, består av en server och flera klienter. För att starta ett spel måste först en server sättas upp. Det görs genom att följa följande punkter: 1. Öppna konsollen och navigera till mappen där du har placerat plumpserver.jar. 2. Skriv java -jar plumpserver.jar port number of players number of rounds Spelet stödjer 2-5 spelare och 2-10 rundor. Ett felmeddelande erhålls om man försöker starta ett spel som ej uppfyller detta. Därefter ansluter varje spelare till servern genom att följa följande punkter: 1. Öppna konsollen och navigera till mappen där du har placerat plumpclient.jar. 2. Skriv java -jar plumpclient.jar server port Existerar inte servern på den givna adressen och porten erhålls ett felmeddelande. Efter att den första spelaren har anslutit har övriga spelare två minuter på sig att ansluta till spelet. Om det anslutit lika många spelare som det angavs när servern skapades kommer också spelet att startas. Spelarna kommer bli informerade via den röda texten, se Firgur 5, om vad tillståndet är i spelet. De olika tillstånden är: Waiting for other players - Vänta för en eller flera andra spelare ska välja antalet stick eller spela nästa kort. Set number of sticks - Det är spelarens tur att välja antalet stick som den tror att den kommer att ta. This number of sticks is not allowed - Om en spelare är sist att välja antalet stick i en runda och den väljer ett stickantal som är lika med antalet kort i den givna rundan visas detta felmeddelande. Choose card - Det är spelarens tur att välja nästa kort som den vill spela. Klickar spelaren på ett kort som ej är tillåtet(följer ej färg eller trumf) händer ingenting, vilket innebär att spelaren får välja ett nytt kort. The game has ended in a draw - Visas om spelet avslutas med delade segrare. 9
Figur 5: GUI för användaren. Player X has won the game. Congratulations! - Visas när spelet är slut och spelare X har vunnit. 5 Utvärdering I projektet lyckades vi uppfylla de mest fundamentala kraven som sattes upp i början av projektet. Närmare bestämt var det punkt 6 och 8 ovan från kravspecifikationen som inte implementerades. Anledningen var att programmets storlek blev större och dess komplexitet mer avancerad än vad vi från början trodde. Vi fick därför fokusera på att skapa ett fungerande och så buggfritt program som möjligt istället för att lägga till extra funktionaliteter. Om punkt 6 skulle implementeras skulle en del av programmet behöva designas om då det i nuläget enbart är klienterna som har koll på vilka kort respektive spelare har. Denna logik skulle servern behöva för att kunna välja kort åt en specifik spelare 10
när denne avbryter spelet. Denna lösning skulle även vara bra för att motverka fusk bland spelarna, då servern skulle kunna kontrollera om en spelare verkligen hade det kort som den skickade att det spelade kortet följde reglerna. Ingen av de möjliga framtida funktionerna implementerades på grund av projektets omfattning. Funktionerna skulle speciellt kräva en hel del ny design för GUI:n och ett ännu mer utvecklat nätverksprotokoll. Vi trodde att programmet skulle vara enklare att skapa än det var och därför satte vi upp mål som var orimliga i förhållande till projektets omfattning. Till nästa gång skulle vi istället sätta upp mer grundläggande mål och låta specialfunktionerna höra till andra mål som genomförs om tid blir över. Projektuppgiften var rolig då vi själva fick vara med och bestämma vad projektet skulle handla om. Samtidigt är det bra att där fanns projektförslag för att både förstå projektets storlek och underlätta för de studenter med mindre kreativitet. 6 Programlistor Källkoden för programmet finns tillgänglig på: https://github.com/atp10mla/project_network_programming En hemsida är utvecklad där bland annat jar-filer för server och klient finns tillgängliga: http://users.student.lth.se/atp10dfo/network/# 11