# Konzept Problem



## Fettsau (24. Feb 2010)

Hi also ich wollte mein geschriebenes TicTacToe nun so erweiter, dass ich es per Netzwerk auf zwei Rechnern spielen kann.

Eigentlich dachte ich mir ich mache das so:
Ich habe 2 Clients und schicke jeweils die Information an den Server welches Feld/Knopf gedrückt wurde von den 9, der Server sendet das dann auch an den zweiten Client, ich synchronisiere quasi das Spielfeld immer und muss dann natürlich auch nach jedem Zug überprüfen lassen ob ein Spieler gewonnen hat.

Ich habe auch schon einen ChatServer für die Konsole programmier gehabt als ich gelernt habe was man alles für die Netzwerkprogrammierung braucht... Aber ich stehe jetzt iwie auf dem Schlauch wie ich das für mein TicTacToe mache..

Hier ist mein TicTacToe: (funktioniert prima, man kann halt gegen sich selber spielen momentan ^^)

```
package ptictactoe;

import java.awt.event.*; // Für den ActionListener.
// Quelle: [url=http://java.sun.com/docs/books/tutorial/uiswing/events/actionlistener.html]How to Write an Action Listener (The Java™ Tutorials > Creating a GUI With JFC/Swing > Writing Event Listeners)[/url]

import javax.swing.JOptionPane; // Für das PopUp Fenster, bei einem Sieg oder Remis.
// Quelle: [url=http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JOptionPane.html]JOptionPane (Java 2 Platform SE v1.4.2)[/url]

import basis.*; // Für die Knöpfe und das Fenster.

public class TicTacToe implements ActionListener {  // Klasse TicTacToe mit implementierten
	                                               // ActionListener, siehe Quelle oben.

	// Deklaration
	private Fenster mf;
	private Knopf mk1, mk2, mk3, mk4, mk5, mk6, mk7, mk8, mk9;
	private String spieler;
	private int spielzuege;
	private boolean sieg;

	public TicTacToe() { // Konstruktor der Klasse TicTacToe().

		// Konstruktion
		mf = new Fenster();
		mf.setzeTitel("SPIELER X IST DRAN !!!");
		mf.setzeGroesse(300, 300);
		mk1 = new Knopf("", 0, 0, 100, 100);
		mk1.setzeHintergrundFarbe(Farbe.WEISS);
		mk2 = new Knopf("", 100, 0, 100, 100);
		mk2.setzeHintergrundFarbe(Farbe.WEISS);
		mk3 = new Knopf("", 200, 0, 100, 100);
		mk3.setzeHintergrundFarbe(Farbe.WEISS);
		mk4 = new Knopf("", 0, 100, 100, 100);
		mk4.setzeHintergrundFarbe(Farbe.WEISS);
		mk5 = new Knopf("", 100, 100, 100, 100);
		mk5.setzeHintergrundFarbe(Farbe.WEISS);
		mk6 = new Knopf("", 200, 100, 100, 100);
		mk6.setzeHintergrundFarbe(Farbe.WEISS);
		mk7 = new Knopf("", 0, 200, 100, 100);
		mk7.setzeHintergrundFarbe(Farbe.WEISS);
		mk8 = new Knopf("", 100, 200, 100, 100);
		mk8.setzeHintergrundFarbe(Farbe.WEISS);
		mk9 = new Knopf("", 200, 200, 100, 100);
		mk9.setzeHintergrundFarbe(Farbe.WEISS);
		spieler = "X";
		spielzuege = 0;
		sieg = false;

		// ActionListener zu den Knöpfen hinzufügen.
		mk1.addActionListener(this);
		mk2.addActionListener(this);
		mk3.addActionListener(this);
		mk4.addActionListener(this);
		mk5.addActionListener(this);
		mk6.addActionListener(this);
		mk7.addActionListener(this);
		mk8.addActionListener(this);
		mk9.addActionListener(this);
	}

	private void AktiverSpieler() {
		
		// Für Spieler X, der anfängt.
		if (spielzuege == 1 || spielzuege == 3 || spielzuege == 5
				|| spielzuege == 7 || spielzuege == 9) {
			spieler = "X";
			mf.setzeTitel("SPIELER O IST DRAN !!!");
		}
		// Für Spieler O, der immer nach Spieler X setzt.
		if (spielzuege == 2 || spielzuege == 4 || spielzuege == 6
				|| spielzuege == 8 || spielzuege == 10) {
			spieler = "O";
			mf.setzeTitel("SPIELER X IST DRAN !!!");
		}
	}

	private void Gewinnmöglichkeiten() {

		// horizantal prüfen.
		if (mk1.text() == mk2.text() && mk2.text() == mk3.text()) {
			sieg = true;
		} else if (mk4.text() == mk5.text() && mk5.text() == mk6.text()) {
			sieg = true;
		} else if (mk7.text() == mk8.text() && mk8.text() == mk9.text()) {
			sieg = true;
		}

		// vertikal prüfen.
		if (mk1.text() == mk4.text() && mk4.text() == mk7.text()) {
			sieg = true;
		} else if (mk2.text() == mk5.text() && mk5.text() == mk8.text()) {
			sieg = true;
		} else if (mk3.text() == mk6.text() && mk6.text() == mk9.text()) {
			sieg = true;
		}

		// diagonal prüfen.
		if (mk1.text() == mk5.text() && mk5.text() == mk9.text()
				&& mk1.text() != "") {
			sieg = true;
		} else if (mk3.text() == mk5.text() && mk5.text() == mk7.text()
				&& mk3.text() != "") {
			sieg = true;
		} else {
			sieg = false;
		}
	}

	private void SiegOderRemis() {
		
        // Meldung, wenn ein Spieler gewonnen hat.
		if (sieg == true) {
			JOptionPane.showMessageDialog(null, spieler + " WINS!");
			Hilfe.warte(500);
			mf.gibFrei();
		}
		// Meldung, falls kein Spieler nach 9 Zügen gewonnen hat.
		if (spielzuege == 9 && sieg == false) {
			JOptionPane.showMessageDialog(null, "Remis! Kein Gewinner.");
			Hilfe.warte(500);
			mf.gibFrei();
		}
	}

	public void actionPerformed(ActionEvent a) {
		spielzuege++; // Die Variable wird jedes mal um 1 erhöht, wenn die
		// Methode aufgerufen wird.
		
		this.AktiverSpieler(); // Bestimmung, wer am Zug ist.
		
		// Zeichenzuweisung der Knöpfe. Zeichen jenachdem, welcher Spieler am
		// Zug war.
		  if (a.getSource() == mk1) {
			mk1.setzeText(spieler);
			mk1.setzeBenutzbar(false);}
		  if (a.getSource() == mk2) {
			mk2.setzeText(spieler);	
			mk2.setzeBenutzbar(false);}
		  if (a.getSource() == mk3) {
			mk3.setzeText(spieler);	
			mk3.setzeBenutzbar(false);}
		  if (a.getSource() == mk4) {
			mk4.setzeText(spieler);
			mk4.setzeBenutzbar(false);}
		  if (a.getSource() == mk5) {
			mk5.setzeText(spieler);
			mk5.setzeBenutzbar(false);}
		  if (a.getSource() == mk6) {
			mk6.setzeText(spieler);
			mk6.setzeBenutzbar(false);}
	 	  if (a.getSource() == mk7) {
	 		mk7.setzeText(spieler);
			mk7.setzeBenutzbar(false);}
		  if (a.getSource() == mk8) {
			mk8.setzeText(spieler);
			mk8.setzeBenutzbar(false);}
		  if (a.getSource() == mk9) {
			mk9.setzeText(spieler);
			mk9.setzeBenutzbar(false);}

		this.Gewinnmöglichkeiten(); // Bestimmung der Gewinnmöglichkeiten.
		this.SiegOderRemis(); 		// Erzeugen eines PopUp Fensters, falls jemand gewonnen hat, oder es
		                           // Unentschieden steht.
	}
}
```

Kann mir evtl einer sagen was an meinem Konzept falsch gedacht ist oder ob ich was bei meinem TicTacToe umschreiben muss? Weil ich nicht so ganz weiß was ich zum Server senden soll...
Bei nem Chatserver war es ja einfach nur ein String.. 
Hoffe mir kann geholfen werden


----------



## miwoe (24. Feb 2010)

Ich glaube, da kann man dir viele viele Vorschläge machen. Was ich nicht verstehe, dass du nicht weißt, was du "zum Server senden" sollst. 

Das wichtigste scheint ja wohl mal die Koordinate, an dem ein Spieler seine nächstes zeichen macht.

Je nach Design kann man noch viele andere Daten brauchen.

Server->Client : Du bist dran
Server->Client : Du hast gewonnen
Client->Server : Ich will mitspielen

.....

Wie gesagt, je nach dem wie man es aufzieht. Vielleicht willst du ja auch gar kein Server, sondern eine Peer-to-Peer-Kommunikation. 

Schau dir mal die "Sequenzdiagramme" an. Wenn du versuchst da die Kommunikation einzuzeichnen, wird dir wahrscheinlich schnell klar, was du wie brauchst und vielleicht auch wo man Kommunikation sparen kann, cheaten/bugs unterbinden muss etc. etc.


----------



## Marco13 (24. Feb 2010)

Ja, miwoe hat Recht: Da könnte man jetzt seitenlang drüber referieren. Das mindeste ist wohl, in der actionPerformed sowas zu machen wie

```
if (a.getSource() == mk1) {
            mk1.setzeText(spieler);
            mk1.setzeBenutzbar(false);
            [b]schickeAnDenAnderen("1");[/b]
        }
```
Aber das auch nur, wenn man davon ausgeht, dass die Clients "schlau" sind, und den Spielablauf selbst (er)kennen (also z.B. BEIDE "automatisch" wissen, wann ein Spiel zuende ist, und dass sie abwechselnd dran sind und so...). Ansonsten können Synchronisation & Co natürlich beliebig aufwändig werden - spätestens, wenn (mindestens) einer der Clients eine KI ist, die auf Züge des Gegners _warten_ muss, wird's interessanter...


----------



## Fettsau (25. Feb 2010)

Ja okey ich schicke dem anderen dann ne 1, aber wie sage ich dem dann das der button 1 jetzt nun von dem andern belegt wurde? 
Ich kann keine Peer-to-Peer Funktion machen, weil ich ja das Client Server Prinzip anhand eines solchen Spieles vorstellen muss.


----------



## Marco13 (25. Feb 2010)

Wie gesagt, das war nur zur Verdeutlichung. Auf der anderen Seite gäbe es dann sowas wie

```
void empfangeDaten(String daten)
{
    if (daten.equals("1"))
    {
        mk1.setzeText(andererSpieler);
        mk1.setzeBenutzbar(false);}
    }
    ....
}
```
aber insgesamt sollte man sich dafür natürlich (wenn es "vernünftig" werden soll) andere Strukturen überlegen. Angefangen bei einem Array für die ganzen Knöpfe über MVC bis zu allgemeineren Schnittstellen für die Kommunikation....


----------



## Fettsau (25. Feb 2010)

achso also quasi 9 if verzweigungen für alle 9 knöpfe, und dann bei der gewinnüberprüfung einfach immer jeden spielzug checken ob der spieler selber oder der andere spieler gewonnen hat.. 
das könnte klappen .. danke  

ja das mit dem arrays und so wäre natürlich ne verbesserung, soll aber erst mal nur ganz primitiv und einfach sein, hauptsache es klappt


----------



## Atze (25. Feb 2010)

wenn du's unbedingt so machen willst (vielleicht fällt dir ja noch n anderes konzept ein), dann zumindest mit nem switch case, 9 if/else klingt schön hässlich


----------



## Fettsau (25. Feb 2010)

ja mach ich wohl erstmal so..
glaub mir ich bin da schon seid 4tagen dran ohne wirklich nen ergebniss da bin ich froh wenn ich jetzt zumindest schonmal nen denkansatz hab ;D


----------



## Fettsau (25. Feb 2010)

was mir grade eingefallen ist.. 
kann ich es nicht so machen: 
ich starte die 2clients, bei den clients werden die 9 button angezeigt und wenn ich zum Beispiel den 1drücke, schicke ich dem server ne 1.. 
das heißt der server empfängt immer abwechselnd nachrichten von den clients und der server soll auch selber verwalten welcher button jetzt belegt ist und wann einer gewonnen hat... 
und zur grafischen darstellung bei den clients kann man ja einfach per send to all auch ine zahl rausschicken und der client weiß dann welchen button er mit welchem zeichen belegen soll.. 
was sagt ihr dazu?


----------



## Marco13 (25. Feb 2010)

Man könnte eine ganze Liste von Fragen stellen, die deutlich machen, dass man sich da sehr viele Gedanken drüber machen könnte.
Sendet der Server den neuen Zustand an alle Clients, oder nur die Änderung?
Überwacht der Server, dass die Clients abwechelnd ziehen?
Sagt der Server allen Clients, wann ein anderer einen Zug gemacht hat?
Wer speichert/sagt den Clients, wann sie dran sind (z.B. schon wer anfängt)?
...
(da kann jetzt jemand anderes weitermachen... hab nicht so viel Zeit...)


----------



## Fettsau (25. Feb 2010)

Also jetzt mal konkrete Fragen..

Mein Konzept:
Client soll lediglich eine Nachricht senden, wenn ein ein Knopf gedrückt wurde.
Z.B oben links wird gedrückt.... send("ol")...
Ebenfalls soll der Client auf Nachrichten warten und danach auch handeln... 
falls er "1" zugeschickt bekommt wird der Btn oben links auf nicht benutzbar gesetzt.
Falls der Server X,O, oder R sendet wurde ein Sieg oder ein Remis festgestellt vom Server und die Anwendung zeigt dies an.

Der Server soll alles verwalten, Gewinnabfragen, welcher Client dran ist und welcher Btn von welchem Spieler belegt wurde.

Mein Problem ist jetzt wie mache ich den Client klar, dass er 1x setzen darf und dann 1x warten muss?

Hier ist mein Code vom Client: 


```
package ptictactoe;

import java.awt.event.*;
import java.io.*;
import java.net.Socket;
import javax.swing.JOptionPane;
import basis.*;

public class TicTacToe implements ActionListener, Runnable {

	private Fenster mf;

	private Knopf mk1, mk2, mk3, mk4, mk5, mk6, mk7, mk8, mk9;

	private String spieler;

	private Socket socket;

	private DataInputStream din;

	private DataOutputStream dout;

	public TicTacToe(String host, int port) {

		try {
			socket = new Socket(host, port);
			din = new DataInputStream(socket.getInputStream());
			dout = new DataOutputStream(socket.getOutputStream());
		} catch (IOException ie) {
		}

		mf = new Fenster();
		mf.setzeTitel("TicTacToe");
		mf.setzeGroesse(300, 300);
		mk1 = new Knopf("", 0, 0, 100, 100);
		mk1.setzeHintergrundFarbe(Farbe.WEISS);
		mk2 = new Knopf("", 100, 0, 100, 100);
		mk2.setzeHintergrundFarbe(Farbe.WEISS);
		mk3 = new Knopf("", 200, 0, 100, 100);
		mk3.setzeHintergrundFarbe(Farbe.WEISS);
		mk4 = new Knopf("", 0, 100, 100, 100);
		mk4.setzeHintergrundFarbe(Farbe.WEISS);
		mk5 = new Knopf("", 100, 100, 100, 100);
		mk5.setzeHintergrundFarbe(Farbe.WEISS);
		mk6 = new Knopf("", 200, 100, 100, 100);
		mk6.setzeHintergrundFarbe(Farbe.WEISS);
		mk7 = new Knopf("", 0, 200, 100, 100);
		mk7.setzeHintergrundFarbe(Farbe.WEISS);
		mk8 = new Knopf("", 100, 200, 100, 100);
		mk8.setzeHintergrundFarbe(Farbe.WEISS);
		mk9 = new Knopf("", 200, 200, 100, 100);
		mk9.setzeHintergrundFarbe(Farbe.WEISS);

		mk1.addActionListener(this);
		mk2.addActionListener(this);
		mk3.addActionListener(this);
		mk4.addActionListener(this);
		mk5.addActionListener(this);
		mk6.addActionListener(this);
		mk7.addActionListener(this);
		mk8.addActionListener(this);
		mk9.addActionListener(this);
	}

	private void send(String output) {
		try {
			dout.writeUTF(output);
		} catch (IOException e) {
		}
	}

	public void run() {
		try {
			while (true) {
				String input = din.readUTF();
				if (input.equals("1")) {
					mk1.setzeBenutzbar(false);
				}
				if (input.equals("2")) {
					mk1.setzeBenutzbar(false);
				}
				if (input.equals("3")) {
					mk1.setzeBenutzbar(false);
				}
				if (input.equals("4")) {
					mk1.setzeBenutzbar(false);
				}
				if (input.equals("5")) {
					mk1.setzeBenutzbar(false);
				}
				if (input.equals("6")) {
					mk1.setzeBenutzbar(false);
				}
				if (input.equals("7")) {
					mk1.setzeBenutzbar(false);
				}
				if (input.equals("8")) {
					mk1.setzeBenutzbar(false);
				}
				if (input.equals("9")) {
					mk1.setzeBenutzbar(false);
				}
				if(input.equals("X")){
					JOptionPane.showMessageDialog(null, "Spieler X gewinnt.");
					Hilfe.warte(500);
					mf.gibFrei();
				}
				if(input.equals("O")){
					JOptionPane.showMessageDialog(null, "Spieler O gewinnt.");
					Hilfe.warte(500);
					mf.gibFrei();
				}
				if(input.equals("R")){
					JOptionPane.showMessageDialog(null, "Remis! Kein Gewinner.");
					Hilfe.warte(500);
					mf.gibFrei();
				}
			}
		} catch (IOException ie) {
		}
	}

	public void actionPerformed(ActionEvent btn) {
		if (btn.getSource() == mk1) {
			send("ol");
		}
		if (btn.getSource() == mk2) {
			send("om");
		}
		if (btn.getSource() == mk3) {
			send("or");
		}
		if (btn.getSource() == mk4) {
			send("ml");
		}
		if (btn.getSource() == mk5) {
			send("mm");
		}
		if (btn.getSource() == mk6) {
			send("mr");
		}
		if (btn.getSource() == mk7) {
			send("ul");
		}
		if (btn.getSource() == mk8) {
			send("um");
		}
		if (btn.getSource() == mk9) {
			send("ur");
		}
	}

}
```


----------



## Atze (25. Feb 2010)

kannst du nicht ne variable einbauen, die vom server jeweils true gesetzt wird, wenn der client ziehen/setzen darf? und wenn nicht, dann eben false.


----------



## Fettsau (26. Feb 2010)

..


----------

