# Spiel: TIC TAC TOE



## Underworld (13. Nov 2009)

Hi, da bin ich wieder 

Ich hab heute aus Spaß versucht Tic Tac Toe zu programmieren. (bin eh krank, hab mich ein bisschen erkältet, da hab ich nichts zu tun *g*)

Java lerne ich erst seit ein paar Wochen im Grundkurs Informatik. Viele Möglichkeiten etwas zu "programmieren" kenne ich noch nicht, jedoch bin ich da offen und würde auch gerne etwas dazulernen.
Methoden die ich bis jetzt so durchgenommen hab: if-Bedingungen, Schleifen(For und while),
Konstruktoren, im Grafikfenster linien, kreis, rechtecke usw. zu zeichnen, oder auch zum Beispiel eine Klasse Stern aus den Klassen Dreieck zu programmieren.
Also eig Grundlegende Sachen, tiefer sind wir aber noch nicht in Java eingestiegen!

So sieht mein Code momentan aus:


```
import java.awt.*;
import javax.swing.*;

public class Oberfläche

{

	public  Oberfläche() {
		// Standard-Grafikoberfläche holen:
		Graphics2D g = GrafikFenster.gibGrafikFläche();

		for (int i = 125; i <= 1000; i += 250) {
			g.drawLine(125, i, 875, i);

			g.drawLine(i, 125, i, 875);
		}

		for (int a = 0; a <= 8; a += 1) {
			if (a <= 2) {
				g.drawString(String.valueOf(a + 1), 250 * a + 130, 140);
			}
			else {
				if (a <= 5) {
					g.drawString(String.valueOf(a + 1), 250 * (a-3) + 130, 390);
				}

				else {
					g.drawString(String.valueOf(a + 1), 250 * (a-6) + 130, 640);
				}
			}
		}
g.setColor(Color.GREEN);
g.setFont(new Font("Helvetica", Font.BOLD, 50));
g.drawString("TIC TAC TOE", 350,75);	
}
}
```


```
import java.awt.*;
import javax.swing.*;

public class Zeichen {
	private Oberfläche Gitter;

	public Zeichen() {
		Gitter = new Oberfläche();

	}

	public void zeichneX(int a) {
		// Standard-Grafikoberfläche holen:
		Graphics2D g = GrafikFenster.gibGrafikFläche();
		g.setColor(Color.BLACK);

		if ((a <= 3) & (a > 0)) {
			g.drawLine(175 + (a - 1) * 250, 175, 325 + (a - 1) * 250, 325);
			g.drawLine(175 + (a - 1) * 250, 325, 325 + (a - 1) * 250, 175);
		}
		else
			if ((a <= 6) & (a >= 4)) {
				g.drawLine(175 + (a - 4) * 250, 425, 325 + (a - 4) * 250, 575);
				g.drawLine(175 + (a - 4) * 250, 575, 325 + (a - 4) * 250, 425);
			}
			else
				if ((a > 6) & (a <= 9)) {
					g.drawLine(175 + (a - 7) * 250, 675, 325 + (a - 7) * 250,
							825);
					g.drawLine(175 + (a - 7) * 250, 825, 325 + (a - 7) * 250,
							675);
				}
				else
					if ((a < 0) | (a > 9)) {
						g.setColor(Color.RED);
						g.drawString("Du Idiot! Falsche Zahl!", 175, 175 + 500);

					}

		GrafikFenster.aktualisiereGrafik();
	}

	public void zeichneKreis(int a) {
		// Standard-Grafikoberfläche holen:
		Graphics2D g = GrafikFenster.gibGrafikFläche();
		if ((a <= 3) & (a > 0)) {
			g.drawOval(175 + (a - 1) * 250, 175, 150, 150);

		}
		else
			if ((a <= 6) & (a >= 4)) {
				g.drawOval(175 + (a - 4) * 250, 425, 150, 150);
			}
			else
				if ((a < 0) | (a > 9)) {
					g.drawOval(175 + (a - 7) * 250, 675, 150, 150);
				}
				else
					if ((a < 0) | (a > 9)) {
						g.setColor(Color.RED);
						g.drawString("Du Idiot! Falsche Zahl!", 175, 175 + 500);

					}

		GrafikFenster.aktualisiereGrafik();
	}
}
```


Eig kann man da schon ganz gut Tic Tac Toe spielen. Ist zwar nen bisschen umständlich und es gibt auch noch keine Überprüfungen etc.

Um das zu verbessern habe ich einige Fragen.

1. Wie kann ich abfragen, ob ein "Feld" schon belegt ist? 

2. Wenn ich das weiß, wie kann ich dann abfragen ob sich drei X oder drei O in einer Reihe befinden?

3. Ist es möglich einfach die Eingabe des Feldes über die "Maussteuerung" zu generieren? Wenn ihr meinen Code lest, werdet ihr schnell verstehen, wie ich das momentan gelöst habe!

viele Dank fürs lesen und hoffentlich auch fürs Antworten

lg Flo


----------



## 0din (13. Nov 2009)

Ich blick net ganz durch den code aber ich habn au nur ganz knapp überflogen weil wegn wenig zeit... ^^ 

1. Bau dir ne int variable in dein Feld; -1 = frei; 0 = belegt player1; 1 = belegt player2
2. Nach jedem zug die felder abfragen lassen un wenn sich auf den entsprechenden stellen gleiche zahlen befinden haste nen sieger
sowas in die richtig

```
for(each feld)
{
arraylist.add(feld)
}
```
dann kannste auf die entsprechenden positionen vergleichen bzw zusammen addieren
3.kp, die gui sachn habsch mir bei dir net angesehn... ^^


----------



## Marco13 (14. Nov 2009)

Underworld hat gesagt.:


> Wenn ihr meinen Code lest, werdet ihr schnell verstehen, wie ich das momentan gelöst habe!



NEIN

Sorry, das wollte ich gerade mal so deutlich sagen  Erstens fehlt die Klasse "Grafikfenster" (die habe ich glaube ich sogar noch aus einem früheren Thread...), es gibt keinen Hinweis auf irgendwas, was mit der Maus zu tun hat, aber viel wichtiger: Man versteht fremden Code nicht einfach durch durchlesen. Beispiel gefällig?

```
class _{public static void main(String I[]){int i=5,í[][]=new int[i][i];_(i,1,i
/2,i-1,í);î(í);}static int _(int ì,int i,int í,int î,int ï[][]){return i>ì*ì?i-
1:(ï[í][î]=_(ì,i+1,(í+(i%ì==0?0:1))%ì,(î+(i%ì==0?-1:1))%ì,ï))-1;}static void î(
int î[][]){for(int i=0;i<î.length;i++){for(int í=0;í<î[i].length;í++)System.out
.print((î[í][i]<10?" ":"")+î[í][i]+" ");System.out.println();}}}
```


Man versteht ihn bestenfalls durch _nachvollziehen_. Und das kostet Zeit. 

Wie auch immer. Ein TicTacToe zu schreiben, und das Spiel ausschließlich durch Linien auf einem Bild repräsentieren zu wollen, ist ... ein falscher Ansatz. Überlege dir, was man mit _einem Tic-Tac-Toe-Spiel_ machen können will. Und schreibe das als Methoden in eine Klasse (die Methoden können erstmal leer sein - erst überlegen, _welche_ Methoden man braucht) :

```
class TicTacToe
{
    public void setzeZeichen(char zeichen, int zeile, int spalte)
    {
    }

    .... // Was noch?
   ...
}
```
Dann überlege dir, welche Dinge du brauchst, um das Spielfeld zu repräsentieren. (Als Tipp: Ein array - und wenn ihr das "noch nicht gelernt habt", dann ... lies es dir in einem Tutorial durch :rtfm:  )

Das GUI ... kommt ganz am Ende.


----------



## Underworld (14. Nov 2009)

Hi,

sorry, ich habe gedacht man kann meinen Code schnell verstehen 
Kurz zum erklären der Funktionsweise:
1 Klasse: Oberfläche in ein Grafikfenster zeichnen(ein Gitter mit 9 Fenstern)
2 Klasse: Sie beinhaltet 2 Methoden. Eine Methode zeichnet das "X", die andere das "O". Um das "X" oder das "O" zu zeichnen, muss ich nur eine Variable eingeben (von 1-9) und das Programm weiß auf welcher Position das "Zeichen" zu setzen ist

Aus mehr besteht, das Programm momentan noch nicht. Weil ich nicht genau weiß ich wie weiter machen soll *g*

Zu den Arrays, diese habe "ich noch nicht gelernt".
Ich werde wieder kommen, wenn ich mir die Funktionsweise von Arrays angeeignet habe!

Zu der Mauseingabe. Da kann man momentan auch noch gar nichts finden. Ich habe nämlich keine Ahnung wie ich die einsetzen kann. Wenn dass aber für meinen Kenntnisstand noch zu schwierig ist, kein Problem. Ich habe mich wohl "falsch" ausgedrückt.


Und jetzt schon mal an Marco13 und seinen Code:

```
public void setzeZeichen(char zeichen, int zeile, int spalte)
```

Warum benutzt du int zeile und int spalte? Du kannst doch nur durch die Angabe von 1-9 schon die Position des Zeichen berrechnen. Zumindest in meiner Lösung. Die wird dir wahrscheinlich aber nicht zussagen *g*

Vielen Dank für die Antworten. Die helfen mir schon ein bisschen!

lg Flo


----------



## Ark (14. Nov 2009)

Underworld hat gesagt.:


> Warum benutzt du int zeile und int spalte? Du kannst doch nur durch die Angabe von 1-9 schon die Position des Zeichen berrechnen.



Etwas Wichtiges, das jeder Informatiker im Laufe seiner Karriere lernt: Unterscheiden zwischen der internen Repräsentation (z.B. eines Objekts) und seinem Verhalten nach außen (z.B. gegenüber dem Endanwender).

Einfaches Beispiel: Der Endanwender sieht ein leeres Feld, ein Kreuz oder einen Kreis. Das Programm verarbeitet diese Zeichen aber anders, es gibt ihnen Nummern (meistens natürliche Zahlen, z.B. 0, 1 und 2). Auf diese Weise werden die Zusammenhänge im Spiel für eine Rechenmaschine beschreibbar.

Noch ein Beispiel: die von dir beschriebene Signatur einer Methode beschreibt die Schnittstellen nach außen(!), normalerweise gegenüber anderen Objekten. Ob dieses Objekt jedoch intern(!) mit eindimensionalen oder zweidimensionalen Arrays oder mit einzelnen Variablen arbeitet, ist egal:

```
// Beispielimplementierung 1:
public void setzeZeichen(char zeichen, int zeile, int spalte){
	spielfeld[zeile][spalte] = zeichen;
}


// Beispielimplementierung 2:
public void setzeZeichen(char zeichen, int zeile, int spalte){
	spielfeld[zeile*3+spalte] = zeichen;
}
```
Beide Male sind die Koordinaten jeweils als Zahlen zwischen 0 und 2 anzugeben. Im ersten Fall wird intern ein zweidimensionales Array verwendet. Fall zwei bedient sich dagegen eines eindimensionalen Arrays und nimmt dazu eine Umrechnung vor. Intern, wie gesagt, lösen beide Implmentierungen das Problem auf verschiedene Weise, gegenüber anderen Objekten ist das Verhalten aber gleich.

Ich rate dringend dazu, die interne Repräsentation der Objekte jeweils so zu wählen, dass sie die Aufgaben, für die sie zuständig sind, so einfach wie möglich erledigen können.

Ark


----------



## Marco13 (14. Nov 2009)

Underworld hat gesagt.:


> sorry, ich habe gedacht man kann meinen Code schnell verstehen


Ja, in diesem Fall ging es ja noch  ich wollte nur (übertrieben deutlich) darauf hinweisen, dass ein gewaltiger Unterschied besteht zwischen 
- Code, den man _selbst_ auf Basis von Wissen um das Problem, Kenntnis der Rahmenbedingungen und Selbst-Erarbeitung eines Lösungweges geschrieben hat und
- Code, den irgendjemand anderes (irgendein krankes Hirn  ) aus nicht mehr nachvollziehbaren Gründen genau so hingeschrieben hat.

Bei sowas wie

```
for (int i = 125; i <= 1000; i += 250) {
            g.drawLine(125, i, 875, i);
```
stehen halt irgendwelche magischen Zahlen dort, die _genau so_ sein müssen, weil das Grafikfenster _genau die_ Größe hat, und du das _genau so _ haben wolltest. 

Das jetzt nicht als "Dämpfer" ansehen: Es ist _genau das richtige_ wenn du dir Programme überlegst, die du im Rahmen deiner Möglichkeiten schreiben kannst, und damit Übung bekommst und Kenntnisse verbesserst (oder wie in einer Signatur hier im Forum: "Programmieren lernt man nur durch Programmieren"). 

BTW: Diese "Grafikfenster" Klasse soll eine Vereinfachung sein - an sich ist das nicht verkehrt: Es sorgt sicher für Motivation, wenn man mit ein paar einfachen Befehlen ein bißchen Grafik auf den Bildschirm zaubern kann. Aber wie ich ja schon im "Funktionsplotter"-Thread angedeutet habe: Das suggeriert vielleicht eine Einfachheit, die nicht immer gegeben ist - und spätestens, wenn man Dinge wie Mausinteraktion einbauen will, kann es sein, dass man mit solchen vereinfachenden Hilfsklassen an Grenzen stößt. 
Ich würde dir DRINGEND empfehlen, dir mal Lesson: Performing Custom Painting (The Java™ Tutorials > Creating a GUI With JFC/Swing) durchzulesen. Dort wird beschrieben, wie man eine eigene Component entwickelt, auf die man zeichnen kann, und wie die Maus-Interaktion grundsätzlich funktioniert. Wenn du das durchgearbeitet hast, wirst du sicher leicht eine eigene Component erstellen können, namens "TicTacToeSpielfeld", die dein Spielfeld zeichnet, und durch die du mit der Maus dein TicTacToe bedienen kannst. 
Aber nochmal: Das eigentliche Spiel (die angedeutete Klasse "TicTacToe") hat mit dem GUI (also das "TicTacToeSpielfeld") nichts zu tun. Das GUI wird nur verwendet, um das Spiel anzuzeigen und zu steuern, aber das Spiel selbst könnte auch ohne GUI laufen.

Das 
public void setzeZeichen(char zeichen, int zeile, int spalte)
hat Ark ja schon schön erklärt. 
Aber nochmal zum Prozess an sich: Ich hatte ja gesagt, dass du diese Methoden erstmal leer lassen kannst, und erstmal nur überlegen sollst, WELCHE Methoden es gebe muss. Dieses Konzept wird in der Praxis oft konsequenter gemacht, indem man interfaces verwendet. In einem Interface stehen NUR die Methoden, und man plant einen großen Teil seines Programmes allein damit. Tatsächlich ist es so, dass oft schon der größte Teil der Arbeit dafür aufgewendet wird, sich die Interfaces zu überlegen.

Du erinnerst dich vielleicht an das "interface Function", aus dem Funktionsplotter: Man konnte den eigentlichen Plotter schon schreiben, obwohl man nur dieses leere Interface defniert hatte. Ob das dann später mit "f(x)=x*x" gefüllt wurde, oder mit "f(x)=0.5*x-2" spielte keine Rolle...


----------



## Underworld (16. Nov 2009)

Hi,

habe mich heute ein wenig in die Arrays reingelesen.

Habe jetzt zumindest verstanden für was sie da sind und hab auch schein "kleinere" Anwendungen verstanden.

Als Hilfe diente mir vor allem diese Seite:
Java/Array ? ZUM-Wiki

Jetzt sehe ich auch schon viel klarer, wie ich das TicTacToe gestalten kann!
2 Dimensionale Arrays muss ich noch nachvollziehen, ich denke, die könnten ganz hilfreich sein, sowie Ark das beschrieben hat.


```
// Beispielimplementierung 1:
public void setzeZeichen(char zeichen, int zeile, int spalte){
    spielfeld[zeile][spalte] = zeichen;
}
 
 
// Beispielimplementierung 2:
public void setzeZeichen(char zeichen, int zeile, int spalte){
    spielfeld[zeile*3+spalte] = zeichen;
}
```


Das zweite Beispiel sagt mir zwar momentan noch mehr zu, aber das gibt sich hoffentlich, wenn ich weiß ich die mehr dimensionalen Arrays benutzen kann!

Ich wollte mich nur noch mal melden, damit ihr wisst, dass ich eure Hilfe zu schätzen weiß und dass ich immer noch versuche das "Spiel" zu programmiere und nicht aufgegeben habe 

lg Flo


EDIT: Hab grad noch die Übungsaufgaben, der Seite gemacht. Arrays sind bis jetzt das interessanteste was ich bisher gemacht hab. Da zeigen sich ja aufeinmal nen Vielfaches von neuen Möglichkeiten


----------



## 0din (16. Nov 2009)

beim ersten bsp. sparst du dir das rum rechnen un das macht den code leichter zu lesen

was ich vllt anmerken sollte, in deinen bsps müsste dein spielfeld ein zweidimensionales char array sein 
also sowas

```
char[][] spielfeld = new char[3][3];
```

es wär also vllt sinniger deine "feld" klasse so zu gestallten das man se mim char füttern kann

```
public class Feld
{
private char token;

public void setToken(char zeichen)
{
this.token = zeichen;
}

public char getToken()
{
return token;
}
}
```


----------



## Underworld (17. Nov 2009)

eine Frage zu char

Das haben wir noch nicht durchgenommen und im Internet steht, dass char ein Buchstabe ist!

kann man char ungefähr so ansehen wie ein String nur mit einem einzelnem Buchstaben?


----------



## unregistriert (17. Nov 2009)

Char steht für ein Zeichen. Das kann auch eine Zahl sein.


----------



## Michael... (17. Nov 2009)

unregistriert hat gesagt.:


> Char steht für ein Zeichen. Das kann auch eine Zahl sein.


meinst wohl Ziffer.
ein char entspricht einem Integer, der ein Zeichen (Buchstabe, Ziffer, Symbol, Steuerzeichen...) repräsentiert.
siehe ASCII


----------



## Ark (17. Nov 2009)

Michael... hat gesagt.:


> siehe ASCII


Und nicht nur ASCII, sondern eher Unicode. 



0din hat gesagt.:


> beim ersten bsp. sparst du dir das rum rechnen un das macht den code leichter zu lesen


Jein. Die Umrechnung ist nur nötig, wenn tatsächlich Zeile und Spalte angegeben werden. Ändert man jedoch die Schnittstelle, so ergibt sich ein ganz anderes Bild:


```
// Beispielimplementierung 1:
public void setzeZeichen(char zeichen, int position){
	spielfeld[position/3][position%3] = zeichen;
}


// Beispielimplementierung 2:
public void setzeZeichen(char zeichen, int position){
	spielfeld[position] = zeichen;
}
```
Nun gibt man nicht mehr Zeile und Spalte getrennt, sondern eine Position (0 bis 8) an, die beide Angaben in sich vereint. Ergebnis dieser Änderung: die eindimensionale Variante ist nun einfacher als die zweidimensionale. Die Frage ist eben, welche der beiden internen Darstellungen in den meisten Fällen von Vorteil ist. Dabei steht nach wie vor die _interne_ Verarbeitung im Vordergrund, dies zu entscheiden: die Umrechnung von der externen Darstellung in die interne Darstellung macht man für gewöhnlich seltener, als die Daten anschließend (in der internen Darstellung) zu verarbeiten. Deswegen ist es nicht besonders klug, sich bei den internen Angelegenheiten eines Objekts zu verrenken, nur damit das Rein und Raus der Daten "schön" aussieht.

Ich persönlich vermute, dass z.B. das Überprüfen auf Gewinnen mit einem eindimensionalen Array einfacher zu bewerkstelligen sein wird, und bevorzuge deshalb diese Variante. Daraus ergibt sich auch schon, sich auf die einfachere Implementierung (siehe oben) zu stützen; erst bei Bedarf kann man dann auch die anderen Schnittstellen zur Verfügung stellen. Das eindimensionale Array hat weiterhin den Vorteil, dass die einfachere Positionsangabe gut mit einer möglichen Art der Eingabe seitens des Benutzers einhergeht: Gibt der Benutzer eine Zahl zwischen 1 und 9 an, so braucht der Aufrufer der Methode nur ein "minus Eins" an den Wert hängen, und schon ist die Eingabe in die interne Sicht überführt.



0din hat gesagt.:


> was ich vllt anmerken sollte, in deinen bsps müsste dein spielfeld ein zweidimensionales char array sein


Auch hier eher jein. Sauberer ist es wohl, [c]int[/c] statt [c]char[/c] zu benutzen und Konstanten zu verwenden, ungefähr so:

```
public static final int NOTHING = 0, PLAYER1 = 1, PLAYER2 = 2;
```
Die beiden [c]PLAYER[/c]-Konstanten sind wahrscheinlich sowieso obsolet. Zugegeben, das ist kein echtes Argument gegen [c]char[/c], jedoch kommt man bei [c]int[/c] in diesem Spiel nicht so schnell auf die Idee, die externe Sicht (' ', 'X', 'O') mit der internen Sicht (0, 1, 2) zu vermischen. Falls jemand nämlich auf die Idee kommt, statt X und O etwas anderes zu verwenden, wäre bei einer strikten Trennung von interner und externer Darstellung (also die Verwendung von [c]int[/c]) keine einzige Änderung in dieser Klasse nötig.

Ob der Einsatz von [c]enum[/c]s sinnvoll ist, lasse ich mal dahingestellt.

Ark


----------



## Marco13 (17. Nov 2009)

Ark hat gesagt.:


> Dabei steht nach wie vor die _interne_ Verarbeitung im Vordergrund, dies zu entscheiden: die Umrechnung von der externen Darstellung in die interne Darstellung macht man für gewöhnlich seltener, als die Daten anschließend (in der internen Darstellung) zu verarbeiten. Deswegen ist es nicht besonders klug, sich bei den internen Angelegenheiten eines Objekts zu verrenken, nur damit das Rein und Raus der Daten "schön" aussieht.



*einhak* Das sehe ich ... ziemlich anders. Was man ... eigentlich programmiert, bzw. was man entwirft und als (nicht zuuu verwobenes  ) Geflecht von interagierenden Entitäten zusammenfügt, und womit man versucht, die Wirklichkeit nachzumodellieren, sind eigentlich die Interfaces. TicTacToe besteht aus einem Feld der Größe 3x3. Daraus folgt (für mich) direkt, dass man eine Methode [c]get(int x, int y)[/c] hat. Dass es jetzt für eine spezielle KI vielleicht "praktischer" wäre, einen 1D-Array zu haben, sollte bei dieser Entscheidung keine Rolle spielen. 

Man sollte die mögliche interne Darstellung natürlich idealerweise schon im Hinterkopf haben. Und im Idealfall wählt man eine Darstellung nach außen, die "schön" ist, und trotzdem "vollständig" (also keine potentiell wichtigen Informationen weglassen, um die Schnittstelle "schöner" zu machen). 

Am konkreten Beispiel ist vielleicht schwierig zu verdeutlichen, was ich meine... Aber... stell' dir vor, du willst MineSweeper programmieren - mit unterschiedlichen Feldgrößen. Jemand klickt auf einem Feld an die Position (3,5). Man (der Aufrufer) weiß nicht, welchen Array-Index er dort übergeben muss. Er muss erst abfragen, wie breit das Feld ist, und den index dann selbst ausrechnen. Oder muss er vielleicht abfragen, wie hoch das Feld ist? Das weiß er nicht. Wenn das Feld die Größe (4,4) hat, kann er problemlos auf die Position (6,1) zugreifen, und er wird den Fehler u.U. nicht unmittelbar bemerken. 

Ja, nur ein Beispiel. 

Ich wollte nur betonen: Die _interne_ Darstellung sollte beim Entwurf der Schnittstelle IMHO keine Rolle spielen.


----------



## Underworld (17. Nov 2009)

Hi,
habe nen bisschen an der "Spielengine" oder wie man es nennen möchte, gecodet

Prinzip hinter dem Code ist ein 2-dimensionales Array.
Kurzer Überblick über meine Methoden: (Damit ihr die auch verstehen könnt)
1. Erst eine Beispielmethode in der das Feld gefüllt wird, damit ich meine Methoden ausprobieren kann.

2. Dann eine "Setter" Methode, um die Sachen "variabel" zu füllen. Die Getter Methode natürlich gleich dazu.

3. Eine Methode um die Anzahl der Zeichen zu berechnen (gelöst über 2 in sich verbundene for-Schleifen, funktioniert so ganz gut :toll: )

4. Zuletzt die "Wer ist drann"-Methode, die mir ausgibt wer den nächsten Zug ausführen soll.
Hier muss ich noch ein paar Sachen verbessern, vor allem für den Fall wenn die Anzahl X = Anzahl Kreise ist.
Das werde ich aber so lösen, indem ich eine "WerFängtAn" Methode schreibe, die angibt wer gestartet hat. So kann ich relativ einfach die "WerIstDrann" Methode vervollständigen.

Als nächstes kommt, dann der etwas kompliziertere Teil, in dem ich ausgeben muss, ob jemand gewonnen oder unentschieden gespielt gespielt.
Das sollte zumindest dank 2-Dimensionaler Arrays ziemlich simpel gehen. Wenn einfach ein Array mit dem gleichen Wert (X oder O) dreimal den gleichen Index von einen der beiden "Arrayarten" hat, ist dies eine Reihe. (Das konnte ich jetzt leider nicht einfacher ausdrücken, da fehlt mir leider das Fachvokabular  )
Und natürlich für die beiden Sonderfälle, wenns diagonal ist, aber da gehe ich jetzt nicht drauf ein!



```
public class Spielengine {

	int anzahlX = 0;
	int anzahlO = 0;
	char zeichenX = 'X';
	char zeichenKreis = 'O';
	char untentschieden = 'U';

	public Spielengine() {
		spielFeld = new char[3][3];
	}

	char[][] spielFeld = new char[3][3];

	public void setzeBeispielFelder() {
		spielFeld[0][0] = 'X';
		spielFeld[1][0] = 'O';
		spielFeld[2][0] = 'O';
		spielFeld[0][1] = 'O';
		spielFeld[1][1] = 'X';
		spielFeld[2][1] = 'O';
		spielFeld[0][2] = 'X';
		spielFeld[1][2] = 'O';
		spielFeld[2][2] = 'X';

	}

	// Mögliche Zeicheneingabe soll noch programmiert werden: Zeichen: O , X
	public void setCharinFeld(int spalte, int zeile, char zeichen) {
		spielFeld[spalte][zeile] = zeichen;
	}

	public char getCharInFeld(int spalte, int zeile) {
		return spielFeld[spalte][zeile];
	}

	public void anzahlDerZeichen() {
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				if (spielFeld[i][j] == 'X') {
					anzahlX++;
				}
				if (spielFeld[i][j] == 'O') {
					anzahlO++;
				}
			}
		}
	}

	public char werIstDrann() {
		// HIER UMBEDINGT NOCH EINE LÖSUNG FINDEN! Am besten mit Method: Wer hat angefangen!
		if (anzahlX == anzahlO) {
			System.out
					.println("Das ist noch problematisch, hierfür habe ich noch keine Lösung");
		}

		if ((anzahlX + anzahlO) > 9) {
			System.out
					.println("Das Spiel ist längst vorbei, warum führst du diese Methode noch aus?");
		}

		if (anzahlX > anzahlO) {
			return zeichenKreis;
		}
		else {
			return zeichenX;
		}
	}

	public void gewinner() {
	}

}
```

Übrigens habe ich meine beiden Klassen "Oberfläche zeichnen" und "Symbole zeichnen" so vereinfacht, dass sie nun abhängig von der Höhe und Breite des Grafikfensters gemacht.
Ich habe einfach alle "komischen Werte" mittels der getBreite und getHoehe Methode ausgedrückt, die du (Marco13) für mich geschrieben hast. Danke nochmal 

Naja, ich werd jetzt noch nen bisschen für Donnerstag lernen. Da schreib ich Informatikklausur und das Stoffgebiet ist da was ganz anderes als das, was ich hier so mache 
Hinbekommen werd ich das schon, nur den ganzen Code auf nen Blatt zuschreiben wird ein riesen Spaß :shock:


EDIT: Habe eure beiden Posts noch nicht gelesen, als ich das abgeschickt habe.
Ich hab gleich wieder eine frage.

Was hat es mit diesem "Static" auf sich?
Davon habe ich noch nie was gehört und ich hab auch keine Ahnung wie ich damit umgehen soll!

EDIT2: Und von enum hab ich noch weniger gehört :autsch:

EDIT3: Und mit "Schnittstelle" in Informatik kann ich mir nicht wirklich was vorstellen. Ich kann mir das zwar ungefähr denken, was gemeint sein soll, aber in Worte könnte ich das jetzt grad auch nicht packen!


----------



## Ark (17. Nov 2009)

Marco13 hat gesagt.:


> TicTacToe besteht aus einem Feld der Größe 3x3. Daraus folgt (für mich) direkt, dass man eine Methode [c]get(int x, int y)[/c] hat. Dass es jetzt für eine spezielle KI vielleicht "praktischer" wäre, einen 1D-Array zu haben, sollte bei dieser Entscheidung keine Rolle spielen.


Jein. Mehr dazu unten.



Marco13 hat gesagt.:


> Ich wollte nur betonen: Die _interne_ Darstellung sollte beim Entwurf der Schnittstelle IMHO keine Rolle spielen.


Auch hier: jein. Was ich meine, erkläre ich mal mehr oder weniger am Beispiel Tic Tac Toe: Wenn ich weiß, dass ich intern ein 1D-Array nehmen werde, dann biete ich zunächst nur die (aus interner Sicht) "einfachere" Schnittstelle an, halte mir aber als Option offen, auch die "kompliziertere" zur Verfügung zu stellen, falls sie einmal gebraucht werden sollte (gewissermaßen das Gegenstück zu deprecated). Hintergedanke: Die einfache Schnittstelle ist schnell implementiert, die kompliziertere bedarf eines größeren Aufwands. (Okay, bei Tic Tac Toe wird das nicht so deutlich.) Aber warum sollte ich mir an der komplizierteren Schnittstelle schon die Zähne ausbeißen, wenn ich noch gar nicht weiß, ob sie jemals benötigt wird? Da biete ich zunächst lieber die einfachere mit dem Hinweis an, dass die kompliziertere nicht vergessen wurde, aber erst implementiert wird, wenn sie tatsächlich benötigt wird. (Ich sollte vielleicht dazu sagen, dass ich noch nicht an größeren Projekten in Java beteiligt war. Insofern fehlt mir die Erfahrung. *schäm*)

Ark


----------



## 0din (17. Nov 2009)

static = statisch = wird beim erstellen der klasse schon erstellt
enum is ne seperate klasse, müssteste dir ma selbst aneignen 
schnittstelln können allesmögliche sein, vom messer schnitt :lol: bis zum get/set

zu deinem code:
für die gewinne() methode musste dir nen (mathematischen) zusammenhang suchen
also z.b.
if( 1 - 3 == 3 || 1 - 3 == 6)
if( 1, 4, 6 == 3 || 1, 4, 6 == 6)
das wär mein ansatz bei nem int array bei dem 1 und 2 die spieler bzw zeichen darstelln 

werIstDrann()
da kannste simpel nen boolean switchen lassen, true is spieler1 un false spieler2

un die sache,"läuft das spiel noch" zähl doch einmal nen counter bei deinem setzZeichen() hoch, wenn das ding == 9 is, is das game am ende


----------



## 0din (17. Nov 2009)

Ich war mal so frei un hab selbst fix was zusammen gebastelt... obs tut weiß der teufel ^^ aber damit is dir vllt n wenig geholfen... 


```
public class Brett
{

	private Feld[][] felder;
	private boolean spieler;
	private int anzahlZeichen;

	public Brett()
	{
		felder = new Feld[3][3];
		spieler = true;
		anzahlZeichen = 0;
	}
	
	public char getCharInFeld(int x, int y)
	{
		char ret = '-';
		
		if(felder[x][y].getZustand() == 1)
		{
			ret = 'X';
		}
		
		if(felder[x][y].getZustand() == 2)
		{
			ret = 'O';
		}
		
		return ret;
	}

	public void setZeichen(int x, int y)
	{
		anzahlZeichen++;
		spieler = !spieler;		
		
		if (spieler)
		{
			felder[x][y].setZustand(1);
		}
		else
		{
			felder[x][y].setZustand(2);
		}
		checkWinner();
	}

	public void checkWinner()
	{
		//abfrage ob irgendwie drei auf einer reihe liegen für spieler 1
		if ((felder[0][0].getZustand() + felder[1][0].getZustand() + felder[0][0].getZustand()) == 3 || (felder[0][1].getZustand() + felder[1][1].getZustand() + felder[2][1].getZustand()) == 3 || (felder[0][2].getZustand() + felder[1][2].getZustand() + felder[2][2].getZustand()) == 3 || (felder[0][0].getZustand() + felder[0][1].getZustand() + felder[0][2].getZustand()) == 3 || (felder[1][0].getZustand() + felder[1][1].getZustand() + felder[1][2].getZustand()) == 3 || (felder[2][0].getZustand() + felder[2][1].getZustand() + felder[2][2].getZustand()) == 3 || (felder[0][0].getZustand() + felder[1][1].getZustand() + felder[2][2].getZustand()) == 3 || (felder[0][2].getZustand() + felder[1][1].getZustand() + felder[2][2].getZustand()) == 3)
		{
			System.out.println("Wir haben einen sieger!");
			System.out.print("Es ist Spieler 1");
		}
		else
		{
			//das gleiche für spieler 2
			if ((felder[0][0].getZustand() + felder[1][0].getZustand() + felder[0][0].getZustand()) == 6 || (felder[0][1].getZustand() + felder[1][1].getZustand() + felder[2][1].getZustand()) == 6 || (felder[0][2].getZustand() + felder[1][2].getZustand() + felder[2][2].getZustand()) == 6 || (felder[0][0].getZustand() + felder[0][1].getZustand() + felder[0][2].getZustand()) == 6 || (felder[1][0].getZustand() + felder[1][1].getZustand() + felder[1][2].getZustand()) == 6 || (felder[2][0].getZustand() + felder[2][1].getZustand() + felder[2][2].getZustand()) == 6 || (felder[0][0].getZustand() + felder[1][1].getZustand() + felder[2][2].getZustand()) == 6 || (felder[0][2].getZustand() + felder[1][1].getZustand() + felder[2][2].getZustand()) == 6)
			{
				System.out.println("Wir haben einen sieger!");
				System.out.print("Es ist Spieler 2");
			}
			else
			{
				//wenns spiel zuende is, hamma keinen sieger
				//könnte man an nen bool knüpfen
				if (anzahlZeichen == 9)
				{
					System.out.println("Wir haben keinen Sieger.");
				}
			}
		}
	}
}
```

Vorteil des ganzen, die spieler werden automatisch gewechselt.
Die gewinner abfrage tut 
die mühselige abfrage ob jmd gewonnen hat is schon fertig getippt.

eben zur info, ich hab die zustände nich als extra chars gespeichert sondern als int.
hat den vorteil ich die werte in den if abfragen addieren kann  (der anfrangswert im Feld is -10 also fehler durch nen leeres feld sollts net geben)

Notiz: Feld hält nur die zustände bei... eig nur variable + getter/setter

Hoffentlich hilfts dir ^^


----------



## Ark (17. Nov 2009)

@0din: Nichts für ungut, aber deine Lösung halte ich mal für ... verbesserungswürdig. 


Der Test auf Sieg ist z.B. sehr redundant formuliert: einmal hätte auch gereicht.
Erst eben habe ich groß und breit erklärt, dass man die interne und die externe Sicht trennen sollte. Jegliche 'X' und 'O' sollten also besser verschwinden.
Es gibt zwar nur zwei Spieler, aber das sollte dennoch kein Grund sein, deswegen auf boolean zurückzugreifen.
[c]checkWinner()[/c] sollte besser einen Wert zurückgeben, je nach Situation. sysouts sind an der Stelle eher unangebracht.
Und das [c]checkWinner();[/c] am Ende von [c]setZeichen()[/c] hat da mal gar nichts verloren. Das ist ein ganz böser Fauxpas.

(Hoffentlich werde ich jetzt nicht gesteinigt. )

Ark


----------



## 0din (18. Nov 2009)

Das ding is in vllt 15min gebastelt... das des net das optimum is, weiß ich ^^ daher lass ich die steine mal im garten

der sieger test is eig. nur fix zusammen gehaun, ich hat keine große lust mir was gescheites dabei auszudenken

seine gui scheint einen char zurück bekommen zu wolln, also geb ich ihm den char ^^

mit dem bool kannstes aber simpel merken, wie willstes sonst machn?

sys out reicht doch bei den kleinen progs un wenns wirklich inne gui soll is da au fix n return rein geschrieben

der fauxpas macht aber sinn  so weiß ich nach jedem zug ob wer gewonnen hat, sonst muss ich das ganze jedes ma extra aus der gui aufrufen


----------



## Marco13 (18. Nov 2009)

Oh je... (mehr sag' ich dazu nich ... außer vielleicht die Frage: Was soll "getZustand()" liefern?)

@Ark: _...dann biete ich zunächst nur die (aus interner Sicht) "einfachere" Schnittstelle an, halte mir aber als Option offen, auch die "kompliziertere" zur Verfügung zu stellen,_

Ich glaube, zu erahnen, worauf du raus willst: Wenn man eine Schnittstelle hat, die extrem feine Kontrolle über alle möglichen Details bietet (und sehr direkt die internen Strukturen nach draußen zugreifbar macht), dann kann man dort eine Schnittstelle "drumwickeln", die weniger Zugriff auf die Details bietet, aber dafür vielleicht einfacher zu verwenden ist (und evtl. bei jeder Verwendung einen "einfachen", High-Level-Methodenaufruf ggf. in eine Folge von komplizierteren Low-Level-Methodenaufrufen übersetzen muss)
Teilweise hängt das mit dem zusammen, was ich meinte, als ich gesagt habe, die Schnittstelle wäre idealerweise _"vollständig" (also keine potentiell wichtigen Informationen weglassen..._

In diesem konkreten Fall ist es offentlichlich: Das Feld hat eine feste Größe, und man kann sowohl den (x,y)- als auch den (index)-Zuriff einfach in die jeweils andere Form umsetzen. Bei einer nicht-festen Feldgröße wäre die Umrechnung zwischen (x,y) und (index) nicht möglich, wenn man nicht noch die Breite oder Höhe des Feldes weiß (und WAS davon man braucht ist ein höchst-internes Implementierungsdetail - da kloppen sich die Fortran- und C-Programmierer ja schon seit Generationen  ). 

Vielleicht ist es auch eine subjektive Frage, wahrscheinlich aber eine, die man je nach Anwendungsfall entscheiden muss. Trotzdem habe ich die allgemeine Tendenz, die Dinge möglichs pragmatisch so zu modellieren, wie sie sind. 

Man könnte ja auch ein Spiel erstellen:
Gegeben sind 9 nebeneinander liegende Felder
[c]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[/c]
Ziel des Spiels ist es, die Felder abwechselnd zu füllen. Gewonnen hat der Spieler, der zuerst drei aufeinanderfolgende Felder belegt hat, oder drei Felder, die modulo 3 den gleichen Index haben, oder drei Felder, bei denen die Menge der Reste der Divisionen durch 3 die Menge {0,1,2} ist. 

DANN wäre das natürlich ein 1D-Array


----------



## Underworld (18. Nov 2009)

0din hat gesagt.:


> Das ding is in vllt 15min gebastelt... das des net das optimum is, weiß ich ^^ daher lass ich die steine mal im garten
> 
> der sieger test is eig. nur fix zusammen gehaun, ich hat keine große lust mir was gescheites dabei auszudenken
> 
> ...



Hi Odin vielen Dank für den Code, aber sowas ähnliches hab ich mir auch schon zusammengeschustert.

Das mit dem Char war übrigens deine Idee:



> beim ersten bsp. sparst du dir das rum rechnen un das macht den code leichter zu lesen
> 
> was ich vllt anmerken sollte, in deinen bsps müsste dein spielfeld ein zweidimensionales char array sein
> also sowas
> ...



Ich hab das ganze jetzt auch auf Integers umgeschrieben und so konnte ich ganz einfach die einzelnen Werte der Arrays aufaddieren überprüfen und so den Gewinner auslesen. Ähnlich wie du das gemacht hast, nur benötige ich keine Methode "getZustand"

lg Flo


----------



## Manuh (18. Nov 2009)

Bin selbst Java Anfänger und habs grade mal mit Swing und JFrame + JButtons probiert.
Hat mir 15 Minuten gekostet, ist auch bestimmt mit Abstand die schlechteste Version die hier nun im Forum zu finden ist, aber es funktioniert 

Im Anhang hab ich das Grauen mal hochgeladen 

Gruß
Manuh!


----------



## Underworld (18. Nov 2009)

Manuh hat gesagt.:


> Bin selbst Java Anfänger und habs grade mal mit Swing und JFrame + JButtons probiert.
> Hat mir 15 Minuten gekostet, ist auch bestimmt mit Abstand die schlechteste Version die hier nun im Forum zu finden ist, aber es funktioniert
> 
> Im Anhang hab ich das Grauen mal hochgeladen
> ...



Hi, leider kann ich deine "Version" nicht öffnen, poste es doch mal als Code!

Immerhin kennst du schon Begriffe wie "Swing", JFrame und JButtons, die mir momentan noch gar nichts sagen...


----------



## Manuh (18. Nov 2009)

Der Code ist im "src" Ordner des Zip Archivs.
Du kannst das Zip aber schon öffnen oder? Weil dann müsstest du eigentlich nur die .jar Datei ausführen. Sind alles Standardbibliotheken die normal vorhanden sein müssten.


----------



## Marco13 (18. Nov 2009)

@Underworld: An dem Beispiel solltest du dich aber nicht orientieren (sorry...)


----------



## Manuh (18. Nov 2009)

Kein Problem! 

Wollte erst die JButtons etc. in Arrays anlegen, aber das hat auf Anhieb nicht funktioniert, und weil es ja nur eine spielbare Version werden sollte die ratzfatz gemacht ist, hab ichs für demonstrative Zwecke eben so erstellt 

Tut mir leid, aber ich lerne noch =)

Gruß
Manuh


----------



## Underworld (18. Nov 2009)

eine Frage zu Arrays.

Gibt es eine Funktion die ein bestimmtes Array, sobald es einen Wert zugeteilt wurde, als fest deklariert?

Beispiel:
spielFeld[1][1]=1;

Wenn nun aber wieder spielFeld[1][1]=2; eingegeben wird, soll eine Fehlermeldung kommen.

so, nach ein bisschen überlegen, habe ich das nun so gelöst:


```
int zeichenX = 1;
	int zeichenKreis = 2;
	int nothing = 0;

public Spielengine() {
		spielFeld = new int[3][3];
	}

	int[][] spielFeld = new int[3][3];


public void setIntinFeld(int spalte, int zeile, int zeichen) {
	if (spielFeld[spalte] [zeile] == 0)
	{	    
	    spielFeld[spalte][zeile] = zeichen;
	   }
	   else
	   {
	       System.out.println("Dieses Feld ist leider schon belegt. Versuchen sie es mit einem anderen Feld");
	   }
	}
```


Ist die Lösung gut und sollte ich sie so verwenden oder eher nicht?


----------



## Marco13 (18. Nov 2009)

EDIT: Siehe unten!


Das passt schon so. Statt 0,1 und 2 könnte man noch "sprechendere" Konstanten verwenden:

```
public static final int PLAYER_NONE = 0;
public static final int PLAYER_X = 1;
public static final int PLAYER_O = 2;
...

// Setzen:
if (feld[x][y] != PLAYER_NONE) fehlermeldung();
...
```


EDIT: Das hast du ja schon (fast) - bei dir heißt das eben "nothing"...


----------



## Underworld (18. Nov 2009)

sooooooo

Ich bin fast fertig mit dem Spiel.

Alle Methoden die für die "Spielengine" wichtig sind, habe ich geschrieben. (Bis jetzt sogar Bugfrei )

Durch einen Konstruktor gebe ich den Startspieler an.
Dann kann ich durch die Methode setSpielstein in der ich nur die die Feldwerte angeben muss einen Spielstein setzen. Welchen Wert der Spielstein hat, hängt ab wer gestartet hat und wer gerade drann ist.

Und wenn jemand 3 in einer Reihe hat wird sofort der Gewinner ausgegeben!

Jetzt hab ich nur noch eine Aufgabe... Ich muss das ganze noch auf mein Spielfeld bringen. Aber ich glaube, dass im Gegensatz zu dem was ich schon habe, gar nichts mehr


----------



## Underworld (19. Nov 2009)

Hi,
hab jetzt eig alles, ich möchte nur noch einen "Schönheitsfehler korrigieren"

Die Frage ist an Marco13 gerichtet, du hast mir beim "Funktionsplotter" diese Funktion in die Grafikfenster klasse impletiert:


```
public static int gibBreite()
    {
        if (singleton==null){singleton=new GrafikFenster("Das Zeichenfenster");}
        singleton.zeige();
        return singleton.canvas.getWidth();
    }
    public static int gibHoehe()
    {
        if (singleton==null){singleton=new GrafikFenster("Das Zeichenfenster");}
        singleton.zeige();
        return singleton.canvas.getHeight();
    }
```

Ich glaube, zumindest erscheint das bei mir, wird beim Aufruf von gibHoehe() aus einer anderen Klasse automatisch das Grafikfenster gezeichnet. Ist das irgendwie zu verhindern?

Mein Ziel ist es nur den Wert zu bekommen, das Fenster soll jedoch nicht geöffnet werden, weil das "unschön" aussieht. 

lg Flo


----------



## Marco13 (19. Nov 2009)

Ich hätte mich (NOCH!?!) deutlicher von dieser Grafikfenster-Klasse distanzieren sollen. Sie ist eine Vereinfachung, um schnelle Erfolgserlebnisse zu haben, aber ... ... Dreijährige fahren aus dem gleichen Grund auf BobbyCars rum :bae:  

Man kann das erstmal nicht direkt verhindern: Der Canvas hat erst dann eine "echte" Breite, wenn er angezeigt wird (vorher hat er Breite -1). Aber ... in der Grafikfenster-Klasse, die du gepostet hattest, war die Größe ja ohnehin konstant 1000x1000 - man könnte das jetzt entsprechend direkt zurückgeben, aber ... vielleicht gibt es eine elegantere Lösung, wenn man weiß, wo das aufgerufen wird (und wo stattdessen, später das Grafikfenster sichtbar werden soll) - oder anders gefragt: Für was brauchst du die Breite, wenn du es dann nicht anzeigen willst?  ???:L


----------



## Underworld (19. Nov 2009)

Marco13 hat gesagt.:


> Ich hätte mich (NOCH!?!) deutlicher von dieser Grafikfenster-Klasse distanzieren sollen. Sie ist eine Vereinfachung, um schnelle Erfolgserlebnisse zu haben, aber ... ... Dreijährige fahren aus dem gleichen Grund auf BobbyCars rum :bae:
> 
> Man kann das erstmal nicht direkt verhindern: Der Canvas hat erst dann eine "echte" Breite, wenn er angezeigt wird (vorher hat er Breite -1). Aber ... in der Grafikfenster-Klasse, die du gepostet hattest, war die Größe ja ohnehin konstant 1000x1000 - man könnte das jetzt entsprechend direkt zurückgeben, aber ... vielleicht gibt es eine elegantere Lösung, wenn man weiß, wo das aufgerufen wird (und wo stattdessen, später das Grafikfenster sichtbar werden soll) - oder anders gefragt: Für was brauchst du die Breite, wenn du es dann nicht anzeigen willst?  ???:L



ich habe mein Spieloberfläche mitlerweile variabler gestaltet.

Wenn ich die breite verändere hat dies einerseits Einfluss auf das "ZeichenGitter" und auf die X und Kreise. Das alles habe ich mitlerweile mit der breite ausgedrückt.

Außerdem ist mein Grafikfenster nun immer quadratisch aufgebaut. Das macht das ganze leichter ^^

EDIT: Naja, die ganze Grafikfenster sache werde ich früher oder später eh verlassen. Aber vorerst häng ich noch ein bisschen an ihr


----------



## Underworld (25. Nov 2009)

Hi,
nächstes Problem. Ich bin grad dabei einen kleinen "Botgegner" zu schreiben. Insgesamt will ich das erstmal recht simpel aufbauen, indem ich die Felder einfach über Zufallszahlen belege 

Der Code sieht vereinfacht so aus

```
public class KI{

public Tictactoe spiel;
private Spielengine engine;

public KI(int starter)
{
spiel = new Tictactoe(starter);
}


public void setzeBotSpielstein(){
int spalte =  1+ (int)(3* Math.random() );
int zeile = 1+ (int)(3* Math.random() );

while(engine.feldBelegt(spalte-1,zeile-1)!=false)
{
spalte =  1+ (int)(3* Math.random() );
zeile = 1+ (int)(3* Math.random() );

}
spiel.setzeSpielstein(spalte,zeile);
}
}
```

Leider gibt BlueJ mir hier einen Fehler aus. 
Und zwar: "NulllpointerException: null"

Was macht macht mein Programn?
Es erstellt im Konstruktor die Klasse "Tictactoe". Das ist die Klasse die alle anderen Klassen steuert.

Über Referenzen kann ich ja auch auf die Methoden der Klasse Tictactoe zugreifen,
aber jetzt möchte ich auf eine methode zugreifen, die nicht aus der Klasse Tictactoe ist, sondern aus einer Klasse, die die Klasse Tictactoe erstellt.

In meinem Fall wäre dass die Klasse Spielengine, jedoch habe ich keine Ahnung wie ich das ausführen/ Coden soll.

Ich hoffe ihr versteht was ich meine. Bei Fragen/ Unklarheit versuche ich gerne, mein Problem noch genauer zu schildern


----------



## Marco13 (25. Nov 2009)

Ob die KI das TicTacToe erstelllen sollte?

Jedenfalls ist "engine==null", weil du keine Spielengine erstellst....


----------



## max40 (25. Nov 2009)

Geht es um diesen Aufruf?  
	
	
	
	





```
engine.feldBelegt(spalte-1,zeile-1)
```
Möglichkeit1: Du erzeugst deine Engin in der KI klasse und übergibst die dem Tictactoe
Möglichkeit2: Du hast eine get Methode in Tictactoe die dir die engine zurückgibt, und damit kannst du die Methode aufrufen
Möglichkeit3: Du machst dir eine Methode in Tictactoe die deine 2 Parmaeter emfpfängt und die dann 
	
	
	
	





```
engine.feldBelegt()
```
aufruft

EDIT:
Möglichkeit4: Wie Marco andeutete, dein Aufbau überlegen, Tiactactoe hat glaub ich eigentlich nix in KI zu suchen


----------



## Underworld (25. Nov 2009)

Marco13 hat gesagt.:


> Ob die KI das TicTacToe erstelllen sollte?
> 
> Jedenfalls ist "engine==null", weil du keine Spielengine erstellst....



Hi, 
vielen Dank für die schnellen Antworten.

Du hast recht, die KI sollte TicTacToe eigentlich nicht erstellen. Ich sollte lieber TicTacToe weiterhin alles steuern lassen und nur die Werte von der KI abrufen lassen.

Das ganze hatte ich auch so vorgehabt, nur wollte ich die KI erstmal testen bevor ich das dann so einbaue!

zu max40:
Wie könnte ich deine erste Möglichkeit realisieren? Ich weiß leider nicht, wie ich die Enginge TicTacToe übergeben soll ^^


----------



## max40 (25. Nov 2009)

```
class Tictactoe{

    private Spielengine  _engine;

    public Tictactoe(int starter, Spielengine  engine){
        this._engine = engine;
    }

}
```


```
public class KI{
 
  public Tictactoe spiel;
  private Spielengine engine;
 
  public KI(int starter){
     engine = new Spielengine  ();
     spiel = new Tictactoe(starter, engine);
  }

// ... der Rest von deinem Code
```


----------



## Underworld (25. Nov 2009)

Marco13 hat gesagt.:


> Ob die KI das TicTacToe erstelllen sollte?
> 
> Jedenfalls ist "engine==null", weil du keine Spielengine erstellst....



Ach hier muss ich nochmal einhaken. Da verstehe ich nicht ganz was Java macht.

Ich erstelle erst die Klasse KI, die erstellt die Klasse Tictactoe, die Klasse Tictactoe müsste wiederrum aber wieder die Klassen Spielengine, Oberfläche und Zeichen erstellen.

Dem ist anscheinend aber nicht so, warum werden diese Klassen nicht miterstellt?


----------



## Marco13 (25. Nov 2009)

Also, bei dem das du gepostet hattest, gab es in der KI eine
private Spielengine engine;

Und der wurde nirgendwo ein Wert zugeweisen. (Wenn in der TicTacToe auch eine 
private Spielengine engine;
existiert, kriegt die KI da erstmal nichts davon mit. Wenn die einge gemeinsame Instanz haben sollen, muss diese in der einen oder anderen Richtung weitergereicht werden...)


----------



## Underworld (25. Nov 2009)

Marco13 hat gesagt.:


> Also, bei dem das du gepostet hattest, gab es in der KI eine
> private Spielengine engine;
> 
> Und der wurde nirgendwo ein Wert zugeweisen. (Wenn in der TicTacToe auch eine
> ...



Achso, ja, das klärt das ganze dann auf


----------



## Underworld (25. Nov 2009)

Hi,
die nächste Frage.

Ich werde, dass jetzt einfach so aufziehen wie ichs mir am Anfang gedacht habe und Marco13 es auch vorschlägt.

der Code

```
public class Tictactoe{
public KI bot;
public Spielengine engine;

public class Tictactoe(){
bot = new KI();
engine = new Spielengine();
}
public void setSpielstein(int spalte,int zeile){
...
}}

public class KI{
public void berechneeinpaarSachen(){
...
engine.führeEineMethodeausEngineaus();
int a = ..;
int b = ...;
Tictactoe.setSpielstein(a,b);

}
}
```

Das ganze Programm soll nur über Tictactoe gesteuert werden...

Die Frage ist jetzt, darf ich in der Klasse KI einfach so die Referenz 
engine.führEineMethodeausEngineaus();
ausführen? 
Und die andere Frage bei: Tictactoe.setSpielstein(a,b);
das darf ich ja auch nicht so machen (glaub ich zumindest). Ich habe ja noch kein Objekt erstellt, aber das möchte ich auch nicht.

Außerdem, noch ein Problem. Wenn ich in der Klasse "Tictactoe" bin und aus der Klasse "KI" Werte entnehmen möchte, sollte ich das ja über return-Werte machen.


```
public class KI{
public void setzeBotSpielstein(int spalte, int zeile){
return spalte;
return zeile;
}
}
```

Hier hätte ich nun das Problem, dass ich 2 Rückgabe Werte hätte. Das geht ja leider nicht. Wie müsste ich dieses Problem lösen?
Mir fällt spontan ein:


```
public class KI{
int spalte;
int zeile;
public void setzeBotSpielstein(int spalte, int zeile){
this.spalte = spalte;
this.zeile = zeile;
}

public int returnSpalte(){
return spalte;
}

public int returnZeile(){
return zeile;
}
}
```

Ich glaube aber nicht, dass diese Lösung gut ist. Gibt es für sowas besseres?


----------



## Marco13 (25. Nov 2009)

Was hab' ich denn vorgeschlagen? (Nur wenn ich einen Sachverhalte beschreibe ist das nicht unbedingt ein Vorschlag).

Niemand weiß genau, was bei dir die Klassen "Spieleengine" und "TicTacToe" und "KI" für Funktionen haben. Ob es eine Klasse "Player" gibt, weiß man auch nicht. Man könnte sich vorstellen, dass irgendeine zentrale Stelle das Spielbrett und zwei Spieler verwaltet, und sich von beiden Spielern abwechselnd einen Zug abholt, und den auf dem Spielbrett ausführt. (DAS war jetzt ein Vorschlag - aber auch nur ein unverbindlicher - das kann man ggf. auch anders machen).

Aber zur KI noch ein etwas "verbindlicherer" Vorschlag: So eine KI muss in den meisten Fällen Züge ausführen und rückgängig machen können. Genaugenommen braucht eine "gute" (und für TicTacToe im wahrsten Sinne des Wortes _perfekte_) KI nur folgende Möglichkeiten:
- Einen Zug ausführen
- Den Spielstand bewerten (erkennen, ob man gewonnen oder verloren hat)
- Einen Zug rückgängig machen
Damit kann man die bekanntesten Verfahren (Sirchwort: MinMax und AlphaBeta-Suche) schon implementieren. D.h. es könnte vorteilhaft sein, sich dafür etwas ... "sauberes" zu überlegen. Praktisch wäre eine Klasse, die einen Zug speichert (also nur ein x und ein y (und ggf. eine Spieler-ID) enthält) - praktisch, aber notwendig nicht unbedingt.


----------



## Underworld (28. Nov 2009)

so, ich bin eigentlich fertig. Alles weitere sind nur noch spielereien.

Jetzt habe ich nur noch ein Problem. Wie kann man das Programm ausführbar machen?

Mein Problem kann ich jetzt auch nicht genauer beschreiben, weil ich einfach keine Ahnung davon habe.
Ich habe mir schon eine Main erstellt:

```
public class Tictactoe {

       public static Tictactoe spiel;
    public static void main(String[] args) {

        spiel = new Tictactoe();
            }
.
.
.
```

So weit so gut, aber ich habe keine Ahnung wie ich mein Programm nun außerhalb von BlueJ öffnen soll.
Mein Ziel ist es, dass ich soetwas wie eine "Exe" anklicken muss und TIC TAC Toe dann gestartet wird.

Tut mir leid, dass ich dass so schwammige Wörter verwenden. Mir fehlt hier einfach das Fachvokabular...

lg Flo


----------



## javimka (28. Nov 2009)

http://www.bluej.org/tutorial/blueJ-tutorial-deutsch.pdf
In Kapitel 8 ist beschrieben, wie du eine ausführbare Jar-Datei erstellen kannst. Mach keine Exe, für Java gibt es jar.

Ansonsten gibt es hier noch einen super FAQ Beitrag:
http://www.java-forum.org/spezialthemen/18384-6-varianten-java-programme-starten-jar-bat-exe-cd.html


----------



## Underworld (28. Nov 2009)

danke, werd ich mir mal anschaun!


----------



## Underworld (28. Nov 2009)

Hi,
mit BlueJ habe ich ein jar Archiv erstellt, jedoch kann ich es nicht aufrufen.

Habe Windows Vista 64 Bit und die aktuelle version von Java installiert...

Woran könnte es denn scheitern?
Wenn ihr noch mehr Informationen braucht, bitte fragen, ich weiß nicht was gebraucht wird!

EDIT: Ich habe das Problem gefunden,
Java öffnet irgendwie nur grafische Anwendungen.

Die Test Konsole, wo ich meine Werte eingebe usw, wird nicht mitgeladen. Kann ich die irgendwie mitladen?
Hier ist die Klasse mit der ich die texteingabe generiere:


```
import java.util.Scanner;
public class Eingabe
{
      public static String gibString(String promt)
    {
        Scanner scan = new Scanner(System.in);
        System.out.print(promt);
        return scan.nextLine();
    }
}
```


----------



## javimka (28. Nov 2009)

Ist die "Test Konsole" die normale Konsole von Windows?
Dann müsstest du dein jar entweder von dieser Konsole aus starten oder du könntest eine bat-Datei schreiben, die die Konsole öffnet und sofort die jar startet. Der Inhalt der bat könnte so aussehen:
[c]java -jar TicTacToe.jar[/c]


----------



## Underworld (28. Nov 2009)

javimka hat gesagt.:


> Ist die "Test Konsole" die normale Konsole von Windows?
> Dann müsstest du dein jar entweder von dieser Konsole aus starten oder du könntest eine bat-Datei schreiben, die die Konsole öffnet und sofort die jar startet. Der Inhalt der bat könnte so aussehen:
> [c]java -jar TicTacToe.jar[/c]


hi,

ups, warum habe ich die Test-konsole genannt? ???:L
Das ist natürlich keine Testkonsole sondern lediglich die Java/BlueJ konsole wo auch Sachenreinkommen wie:
"System.out.println("Dieser Text steht jetzt in der Konsole");

leider habe ich keine Ahnung, ob das die Konsole von Windows ist...


----------



## javimka (28. Nov 2009)

Sie haben bestimmt dieselbe Funktionalität in Bezug auf dein Programm. Ehrlich gesagt, kenne ich BlueJ nicht, aber ich gehe davon aus, dass es nicht viel anders ist als bei anderen IDEs.
Die BlueJ Konsole ist doch bestimmt Bestandteil von BlueJ, die kannst du nicht einfach "mitnehmen". Aber wenn du es mit einer Bat-Datei in der Windows Konsole öffnest, gehen alle Input/Outputs über die Konsole, so wie vorher bei BlueJ.


----------



## Underworld (28. Nov 2009)

javimka hat gesagt.:


> Sie haben bestimmt dieselbe Funktionalität in Bezug auf dein Programm. Ehrlich gesagt, kenne ich BlueJ nicht, aber ich gehe davon aus, dass es nicht viel anders ist als bei anderen IDEs.
> Die BlueJ Konsole ist doch bestimmt Bestandteil von BlueJ, die kannst du nicht einfach "mitnehmen". Aber wenn du es mit einer Bat-Datei in der Windows Konsole öffnest, gehen alle Input/Outputs über die Konsole, so wie vorher bei BlueJ.



Hm,
in der cmd steht jetzt da:
C:\Users\EigeneDateien>
ich hab in eigene Dateien meine tictactoe.jar reinspeichert
jetzt müsste ich doch nur noch eingeben
"C:\User\EigeneDateien>" java -jar tictactoe.jar
Hier kommt dann aber:
"Der Befehl "java" ist entweder falsch geschrieben oder konnte nicht gefunden werden"

Was mache ich denn falsch? :autsch:


----------



## javimka (28. Nov 2009)

Du musst java zu deinen Umgebungsvariabeln hinzufügen (Du verwendest Windows oder?). 
System -> Erweitert -> Umgebungsvariablen
dort sollte eine Variable namens path existieren. Diese musst du bearbeiten und zu hinterst ein ; eintippen und dann den Pfad zu deiner java.exe angeben. Diese wird wahrscheinlich unter C:\Programme\Java\jdk1.6.0_14\bin zu finden sein.


----------



## Underworld (28. Nov 2009)

super, funktioniert!
danke

Aber ich hab was neues gefunden, ich hab im Internet nach "Konsole in Java" gesucht und da gibts ein paar Skripte, die sich eine eigene Konsole über awt basteln! Vielleicht kann ich das bei mir einbinden


----------



## javimka (28. Nov 2009)

klar kannst du das machen, aber wenn du schon eine GUI schreibst, kannst du auch gleich ein benutzerfreundliches Interface programmieren


----------

