Java Projekt: Tick Tack Toe

 

Rechnerpraktikum aus Programmierung

 

Kerstin Baumgarten

11-01-2004

Java Code

Über den Autor:

 

 

Name: Kerstin Baumgarten

 

Matrikelnummer: 0025447

 

Lehrveranstaltung: Rechnerpraktikum aus Programmierung

 

Leiter: Dr. Michael Hahsler

 

Semster: WS 2003/04 – 2. Halbsemester

 

E-mail: h0025447@wu-wien.ac.at

 

 

 

 

Problemdefinition:

 

 

Projektziel:

 

Es soll ein lauffähiges Programm geschrieben werden, damit verschiedene Spieler (pro Spiel 2 Mitspieler) an verschiedenen Orten, das Spiel Tic Tac Toe miteinander spielen können.

 

Lösung:

 

Verschiedene Spieler sollen über eigene Clients (ausführbar über Telnet / bzw. mittels Gui) über Sockets mit einem Server kommunizieren. Die Clients können auch über verschiedene Rechner laufen und über einen gemeinsamen Server mittels Sockets kommunizieren. Die Programmiersprache ist Java. Für das Gui wurden Swing-Klassen verwendet.

 

 

Das Spiel Tic Tac Toe:

 

Das Spielfeld von Tic Tac Toe besteht aus 9 Feldern, die in drei Reihen und Spalten angeordnet sind. Ziel des Spieles ist es 3 gleiche entweder waagrecht, senkrecht oder diagonal nebeneinander zu setzen.

Am Anfang sind alle Felder frei. Zwei Spieler ziehen abwechselnd. Ein Zug eines Spieler besteht aus dem Besetzen eines beliebigen bis dahin freien Felds. Wenn ein Spieler 3 Felder waagrecht, senkrecht oder diagonal besetzen kann, hat er sofort gewonnen. Sind alle Felder belegt und kein Spieler konnte 3 Felder waagrecht, senkrecht oder diagonal besetzen so endet das Spiel unentschieden.

 

 

 


Analyse:

 

 

Use Case Diagramm:

 

 

 

Das Use Case “Anmelden” beschreibt die Anmeldeprozedur eines neuen Spielers. Er gibt zuerst seinen Namen ein und sucht dann aus der Liste einen Mitspieler aus.

Fehlszenario: Wenn schon ein User mit diesem Name angemeldet ist, muss er einen anderen Namen wählen.

 

 

Das Use Case „Spielen“ beschreibt den Spielablauf. Züge werden durch klicken auf das Spielfeld gesetzt und dann überprüft ob sie korrekt oder falsch sind.

Fehlszenario: Falsche Züge müssen korrigiert werden. Gezogen wird abwechselnd.

 

 

Das Use Case „Hilfe“ gibt Anleitung wie man mit dem Programm umzugehen hat.

 

 

Das Use Case „Anleitung“ gibt Hilfe zu den Spielregeln.

 

 

Das Use Case „Abmelden“ beschreibt den Abmeldevorgang. Der Spieler muss aus der Liste der möglichen Mitspieler entfernt werden. Während eines Spiels muss der Mitspieler verständigt werden.

 


Design:

 

 

Sequenzdiagramm:

Klassendiagramm:

 

 

Das Klassendiagramm gibt den Zusammenhang der selbstgeschriebenen Klassen wieder. Javastandardklassen wie aus java.net.*; java.io.*; java.util.*; java.awt.*; java.awt.event.*; javax.swing.*; verwendet wurden, werden nicht extra beschrieben. Für die Kommunikation zwischen Server und Client wurden Standardsockets mit Klassen und Methoden verwendet auch das Gui wurde mit Standardswing Klassen geschrieben.

Wenn ein Client sich beim Server anmelden will dann wird ein neues ServerThread-Objekt für ihn erzeugt. Wenn 2 Spieler ein Spiel spielen teilen sie sich ein gemeinsames Objekt der Klasse TTTSpiel.

 

 

Klassendiagramm Server:

 

Klassendiagramm fürs Gui:

 

 

Die Klasse ActionAdapter und WindowClosingAdapter sind Standardinterfaces die im TTTClient als Eventhandler implementiert werden.

 

 

 


Klassen im Detail:

 

Hier werden die Klassen, die im Klassendiagramm beschrieben wurden, detailliert mit ihren Instanzvariablen und Methoden beschrieben.

 

 

Klassendiagramm Server - Detail:

 

 

 


Klassendiagramm fürs Gui - Detail:

 

 

 

Klassenbeschreibung für den Server:

 

 

Klasse:

 

public class TTTServer

Main-Methode zum Starten des Server. Eine Spielerliste wird erzeugt, jeder Spieler der sich anmeldet wird in diese Spielerliste eingetragen. Die Spielerliste steht jedem Spieler zur Verfügung. Die Methode ServerSocket.accept() wartet auf Clients die sich anmelden. Für jeden Client wird ein TTTServerThread-Objekt erzeugt.

 

 

Methode:

 

public static void main (String[] args) throws IOException

 

 

 

 


Klasse:

 

public class TTTServerThread extends Thread

Jedes Objekt dieser Klasse gehört zu einem Spieler. Der TTTServerThread wickelt die oberste Ebene der Kommunikation Client-Server ab.

Hier werden die Reader und Writer für die Socket-Kommunikation instanziert.

 

 

Instanzvariablen:

 

private Socket socket = null;

private TTTProtokoll protokoll;

 

 

Methoden:

 

public TTTServerThread (Socket socket, LinkedList spielerliste)

Konstruktor bekommt die Socket und die Spielerliste vom TTTServer.

Ein Objekt von TTTProtokoll wird erzeugt. Dieses wickelt die Details der Kommunikation zwischen Client - Server bez. einem anderen Client ab.

 

 

public void run()

Run-Methode für den Thread. Wartet auf Messages vom Client und verarbeitet sie mit Hilfe von Methoden vom TTTProtokoll.

 

 

 

 

 

Klasse:

 

public class TTTProtokoll

Wickelt die Details des TTTProtokolls der Server-Client Kommunikation und der Client1- Server - Client2 Kommunikation ab. Definiert die verschiedenen Stati im Spiel.

 

 

Konstanten der Stati:

 

final int INIT = 0;

final int START = 1;

final int NAME = 2;

final int SPIELPARTNER = 3;

final int NAMENEU = 4;

final int SPIELEN = 5;

static final int SPIELENDE = 6;

final int EINGELADEN = 7;

final int AUFANTWORTWARTEN = 8;

final int AUFANTWORTWARTENWEITERSPIELEN = 9;

final int NAMEEINGEGEBEN = 10;


Instanzvariablen:

 

private int status;

private TTTSpieler spieler;       //merkt sich die Daten der Spieler

private LinkedList sliste;           //Liste der anderen Mitspieler vom Server

private TTTSpiel spiel;             //Das Spiel das gerade gespielt wird

private PrintWriter out;            //Writer zum Client

private boolean erster; //True wenn dieser Spieler das Spiel beginnt, sonst false

 

 

Instanzvariable für die Weiterspielprozedur:

 

private int ichspieleweiter;        //0 noch keine Antwort, 1 = ja, 2 = nein!

private int partnerspieltweiter;   //0 noch keine Antwort, 1 = ja, 2 = nein!

 

 

Instanzvariable für die Einladungsprozedur:

 

private TTTProtokoll einladungsprotokoll; //Protokoll vom Einlader, der ein Spiel spielen will

 

 

Konstruktor:

 

public TTTProtokoll (LinkedList spielerliste)

 

 

Methoden:

 

public void austragen ()

Spieler wird aus der Spielerliste ausgetragen

 

 

public String processInput (String inputLine)

Messages vom Client werden verarbeitet

Einzelne Befehle die das Protokoll versteht

Zurückgeschickt werden Nachrichten die dem Client geschickt werden

 

 

public String processOutput ()

Der Server kann den Spieler eine 2te Botschaft schicken.

Es wird im Unterschied zum ProcessInput werden keine Nachrichten vom Client verarbeitet. Es werden nur Nachrichten aufgrund vom Status des Spiels an den Client geschickt. Diese Methode wird vom ServerThread-Objekt nach der Methode ProcessInput aufgerufen.

 

 

public String hallo ()

            Gibt den Hallotext aus

 


public String anleitung ()

            Gibt die Spielanleitung aus

 

 

public String hilfe ()

            Gibt den Hilfetext zum Benützen des Spiels aus

 

 

public String spielerlisteausgeben ()

Spielerliste außer mich selbst

 

 

public boolean namefinden (String spielername)

prüft ob der Name in der Spielerliste enthalten ist

 

 

public TTTProtokoll getprotokollvanderen (String spielername)

liefert das Protokollobjekt des anderen Spielers

 

 

public TTTProtokoll getprotokollvanderen ()

Liefert das Protokollobjekt des anderen Spielers wie oben, nur setzt die Methode voraus dass das Spiel schon existiert

 

 

public void ausgeben(String aus)

Schickt direkt eine Botschaft über den Socket zum Client

 

 

Methoden fürs Einladungsprotokoll:

 

public boolean einladen (TTTProtokoll fragerprotokoll)

            ist vom Mitspieler einladen worden

 

 

public void einladungsantwort (TTTSpieler mitspieler, boolean antwort)

Die Methode mit der ein Spieler einem anderen seine Antwort schicken kann, ob er spielen will.

Der Sender ruft diese Methode vom Empfänger auf, damit er Spielstatus vom Empfänger ändern kann.

 

 

Methoden fürs Weiterspielprotokoll:

 

public void partnerwillweiterspielen (boolean jn)

Methode ähnlich wie Einladungsantwort verwendet, nur wird sie verwendet um den Partner mitzuteilen ob man ein weiters Spiel spielen will.

 

 


Methoden fürs Partnerverständigen:

 

public void partnerverstaendigen ()

Wenn der Andere ‚bye’ sagt damit der Andere das weiss schickt dem Partner eine Message über die Socket.

 

 

Set - Get – Methoden:

 

Setzt und liefert Werte von privaten Instanzvarieblen

 

 

public TTTSpieler getspieler ()

 

 

public void setspielspieler2 (TTTSpiel sp2)

 

 

public int getstatus ()

 

 

public void setstatus (int stat)

 

 

public void setout (PrintWriter sout)

 

 

public PrintWriter getout ()

 

 

 

 

 

Klasse:

 

class TTTSpiel

Die Klasse speichert ein Spiel und seine Zustände, 2 TTTSpieler beziehungsweise TTTProtokolle benützen ein Spiel.

 

 

Stati des Spiels:

 

final int IMSPIEL = 1;

final int GEWONNEN = 2;

final int UNENTSCHIEDEN = 3;

 

final int DEBUG = 5;

 

 


Instanzvariablen:

 

private TTTSpieler spieler1; //1 Spieler

private TTTSpieler spieler2; //anderer Spieler

char [] spielfeld;

private boolean bindran; //wechselt je nach Spielzug von True nach False

private int spielstatus; //1 = im Spiel, 2 = Gewonnen, 3 = Unentschieden

 

 

Konstruktor:

 

public TTTSpiel (TTTSpieler s1, TTTSpieler s2)

 

 

Methoden:

 

public String toString ()

Gibt Spielbrett als String aus.

 

 

public String spielzug (TTTSpieler spieler, boolean erster, String zahl)

Prüft ob der Zug ein gültiger Zug ist. Der gültige Zug wird gesetzt.

Prüft ob Sieg, unentschieden oder ob einfach noch weiter gespielt werden muss.

 

 

private boolean istunentschieden ()

Prüft ob der Spielstand unentschieden ist, wenn ja true, sonst false

 

 

private void zugsetzen (String zahl, char chip)

Setzt einen Zug, Chip kann 'o' oder 'x' sein.

 

 

private boolean zugpruefen (String zahl)

Prüft ob der Zug gültig ist

 

 

private boolean istgewonnen (char chip)

Prüft ob das Spiel gewonnen ist

 

 

public String getweiterspielensatz ()

Gibt die Frage für den Spieler ob er weiterspielen möchte aus.

 

 

public void clear ()

Setzt den Spielstatus auf den Anfangszustand.

 

 


Get- Set- Methoden:

 

public TTTSpieler getspieler1 ()

 

 

public TTTSpieler getspieler2 ()

 

 

public int getspielstatus ()

 

 

 

 

 

Klasse:

 

class TTTSpieler

Speichert Daten zum Spieler, insbesonders seinen Namen und einen Link des Spielers zu seinem TTTProtokoll.

 

 

Instanzvariablen:

 

private String name;

private TTTProtokoll sprotokoll; //Variable damit man sich merkt welches Protokoll zu welchem Spieler gehört.

 

 

Konstruktor:

 

public TTTSpieler ()

 

 

Get- Set- Methoden:

 

public void setname (String n)

 

 

public void setprotokoll (TTTProtokoll sp)

 

 

public String getname ()

 

 

public TTTProtokoll getprotokoll ()

 

 

 

 

 


Klassen fürs GUI:

 

 

Klasse:

 

public class TTTClient

Der Client implementiert das Gui der mit dem TTTServer kommuniziert.

Beim Start meldet sich der Client via Socket beim Server an, während des Spiels bekommt er vom Server Messages über den Socket, die der Client darstellt. Usereingaben meldet der Client über die Socketverbindung an den Server.

 

 

Konstante: Die IP-Adresse ist hier änderbar und muss die IP-Adresse des TTTServers sein damit der Client funktioniert

 

final private static String IP = "localhost";         //IP Adresse vom server

final private static int PORT = 4444;    //Port vom server

final public static String MARKER = “!”; //der Marker wird auch von den TTTKlassen benützt um das Ende einer Message zu markieren. Der Marker darf daher nur am Ende der Message vorkommen und nicht innerhalb eines Textes.

 

 

Konstanten der Stati:

 

final private static int START = 0;

final private static int VERBINDUNG = 1;

final private static int BYE = 2;

 

 

Instanzvariable:

 

private static int status;

private static String eigenerName;

private static JFrame mainFrame = null;

private static JTextField eingabeFeld = null;

private static JTextArea ausgabeText = null;

private static JTextField nameFeld = null;

private static Button[] tButton;

private static int debug = 0;

private static JRadioButton jaButton;

private static JRadioButton neinButton;

private static Socket clientSocket;

 

private static BufferedReader in;

private static PrintWriter out;

 

 

Methoden:

 

public static void main (String[] args) throws IOException

Main Methode erzeugt Gui baut Socketverbindung zum Server auf, liest Messages des Servers ein.

 

 

public static void sendmessage (String sm)

Schickt dem Server eine Message via Sockets.

 

 

public static void inputverarbeiten (String message)

Verarbeitet Messages vom Server.

Die verschiedenen Messages werden erkannt und für bestimmt Messages können sie geändert werden und spezielle Reaktionen des Guis werden hier gesteuert.

 

 

public static void initGUI ()

Hier wird das Gui erzeugt.

Auch der Eventhandler für den Window CloseEvent wird hier implementiert. Wenn der User das Window schliesst wird eine Botschaft an den Gui geschickt, der wird vom Eventhandler aufgefangen der dann eine Message (Socket) an den Server schickt (damit der Server den Client aus der Spielerliste austragen kann, bzw. einen Mitspieler informiert).

 

 

public static JPanel initpane1 ()

Wird vom initGui verwendet und definiert das Erscheinungsbild des Guis.

Auch die Methoden für die Eventhandler (Buttons, Das Eingabefeld, RadioButton) werden hier implementiert. Das Spielfeld wird mit 9 Buttons implementiert, ein Button ist ein Spielfeld.

 

 

public static void enableRadioButtons (boolean r)

Radiobuttons können ein und ausgeschalten werden

 

 

public static void enableButtons (boolean b)

Buttons können benutzbar und unbenutzbar gemacht werden

 

 

public static void setzeButton(int i, char chip)

Chip x oder o, wird auf den Button[i] gesetzt.

 

 

public static String willkommenText ()

            Willkommenstext wird angezeigt.

 

 

public static String hilfeText ()

            Hilfetext wird angezeigt.

 

 

public static void spielfeldloeschen (String message)

Das Gui wird auf einen Anfangszustand gesetzt.

 

public static void clearSpiel()

Nur das Spielfeld wird gelöscht.


Klasse:

 

class ActionAdapter implements ActionListener

Das Interface ActionListener wird als Eventhandler für Buttons in der Methode initPanel implementiert.

 

 

Methode:

 

public void actionPerformed (ActionEvent e)

 

 

 

 

 

Klasse:

 

class WindowClosingAdapter implements WindowListener

Eventhandler zum Schließen des Windows.

Server wird mit bye Message informiert, damit User aus der Liste ausgetragen werden kann.

 

 

Methoden:

 

public void windowClosing(WindowEvent e)

            Die Methode windowClosing wird in der Methode initGui implementiert

 

Diese Methoden werden zwar vom Interface zur Verfügung gestellt aber nicht implementiert:

 

public void windowActivated(WindowEvent e)

 

 

public void windowClosed(WindowEvent e)

 

 

public void windowDeactivated(WindowEvent e)

 

 

public void windowDeiconified(WindowEvent e)

 

 

public void windowIconified(WindowEvent e)

 

 

public void windowOpened(WindowEvent e)

 

 

 

 


Implementierung:

 

 

Das Spiel hat eine Server-Client Architektur. Im Server sind das Protokoll (die Kommunikationsregel zwischen Server und Client und damit auch zwischen 2 Clients die über den Server kommunizieren), das Spiel und Daten zum Spieler als Klassen implementiert. Der Server führt eine Liste aller Spieler. Der gesamt Spielzustand ist in der Klasse Spiel implementiert. Im Protokoll wird nicht der Spielzustand(Spielfeld, Spielzüge, ...) sondern der Kommunikationsprozess zwischen Client und Server implementiert.

Die Kommunikation zwischen Client und Server erfolgt mittels Sockets. Im Client sind keine Spielzustände gespeichert, der Spielzustand der im Client angezeigt wird ist jener den er vom Server geschickt bekommt. Alle Messages, die der Server einem Client schickt werden durch einen eindeutigen Marker am Ende der Message abgeschlossen. Diesen Marker benutzt der Client um alle Messages einzeln zu verarbeiten wenn mehrere Messages gleichzeitig geschickt wurden. (While-Schleife in der Main-Methode von TTTClient.java)

Wenn sich ein Client (Telnet oder Gui) beim Server anmeldet dann startet der Server einen Thread für den Client. Wenn sich ein Client abmeldet wird er aus der Spielerliste ausgetragen.

 

 

Aussehen des Guis:

 

 

 

Das Gui wurde mit Swing-Klassen implementiert. Die Spielfläche wurde mit 9 großen Buttons dargestellt. Die Useraktionen (drücken der Buttons) werden von Eventhandlern (Klasse ActionAdapter) aufgefangen. Die Eventhandler schicken Messages an den Server.

 

Die Erstellung des Quellcodes erfolgte auf einen Windows 2000 Rechner mittels Java-Compiler 1.4.2_03.

Der Client hat eine fix eingestellte IP-Adresse, da davon ausgegangen wird das nur ein Server existiert. Wenn sie Localhost hat dann kann nur auf einen Rechner mit verschiedenen Clients gespielt werden. Wenn die IP-Adresse geändert wird muss der Client neu kompiliert werden.

 

 

Wartung:

 

Sollte ein Fehler auftreten, bitte eine Mail mit Beschreibung an mich senden:

h0025447@wu-wien.ac.at

 

 

Bibliographie:

 

http://java.sun.com/j2se/1.4.2/docs/api/

Thinking in Java – Bruce Eckel

Sprechen sie Java – Hanspeter Mössenböck

 

 

 

 


Dokumentation für den Anwender

 

 

Spielbeschreibung:

 

Das Spielfeld von Tic Tac Toe besteht aus 9 Feldern, die in drei Reihen und Spalten angeordnet sind. Ziel des Spieles ist es 3 gleiche entweder waagrecht, senkrecht oder diagonal nebeneinander zu setzen.

Am Anfang sind alle Felder frei. Zwei Spieler ziehen abwechselnd. Ein Zug eines Spieler besteht aus dem Besetzen eines beliebigen bis dahin freien Felds. Wenn ein Spieler 3 Felder waagrecht, senkrecht oder diagonal besetzen kann, hat er sofort gewonnen. Sind alle Felder belegt und kein Spieler konnte 3 Felder waagrecht, senkrecht oder diagonal besetzen so endet das Spiel unentschieden.

 

 

Hilfe:

 

Es gibt 2 Hilfetexte, wird über Telnet gespielt so gibt es eine Hilfe übers Telnet vom Server:

 

Hilfe zum Tic Tac Toe Spiel:

Um das Spiel zu starten, musst du 'start' eingeben.

Danach gibst du deinen Namen ein, suchst einen Spielpartner aus und das Spiel kann beginnen.

Das Tic Tac Toe Spielfeld ist von links oben nach rechts unten durchnummeriert.

Das Spielfeld sieht so aus:

0 | 1 | 2

3 | 4 | 5

6 | 7 | 8

Damit du setzen kannst, tippe einfach die Zahl ein (0-8) wo du deinen Zug machen willst. Nach jedem Zug erscheint das Spielfeld neu und du siehst "die gesetzten Züge.

Wenn das Spiel beendet ist, kannst du mit deinem Partner noch eine Runde spielen. Bei jeder neuen Runde (mit dem selben Partner) beginnt ein anderer.

Falls du Partner wechseln möchtest, ist das nach dem Spiel möglich.

Wenn du das Spiel beenden möchtest gibt 'bye' ein.

 

 

Das Gui gibt eine etwas andere Hilfe aus, weil die Benutzeroberfläche Buttons, ... benützt:

 

Hilfe zum Tic Tac Toe Spiel:

Um das Spiel zu starten, musst du zuerst den Button 'Start' drücken.

Danach gibst du deinen Namen ein, suchst einen Spielpartner aus und das Spiel kann beginnen.

Um einen Zug zu setzen, drücke wenn du dran bist auf ein Feld.

Im Ausgabefeld werden Meldungen angezeigt, die dir sagen was du als nächstes tun sollst.

Werden im Ausgabefeld Fragen gestellt dann gib die Antworten in das Eingabefeld ein.

Wenn eine Frage kommt, die mit Ja oder Nein zu beantworten ist, so drücke auf den JA oder NEIN Button.

Wenn das Spiel beendet ist, kannst du mit deinem Partner noch eine Runde spielen. Bei jeder neuen Runde (mit dem selben Partner) beginnt ein anderer.

Falls du Partner wechseln möchtest, ist das nach dem Spiel möglich.

Wenn du das Spiel beenden möchtest drücke den Button 'Bye'. Das kannst du auch mitten im Spiel tun. In diesem Fall bekommt dein Partner dann die Verständigung dass du aufgehört hast mit ihm zu spielen.

 

 

Grafische Oberfläche:

 

 

 

 

 

Installation:

 

Der TTTClient muss am PC gespeichert sein. Er lässt sich mittels einer Konsole mit dem Befehl: „java TTTClient“ starten.

Wenn die IP-Adresse des Servers geändert wird, muss der Client neu kompiliert werden mittels „javac TTTClient.java“, danach wieder mit „java TTTClient“ starten.