# Array und Objektorientierung? - TicTacToe Spiel



## Mustard444 (9. Dez 2015)

Hallo,

ich hab hier eine Aufgabe, mit der man ein Tic Tac Toe Spiel programmieren soll. Ich hab auch schon eine Idee, wie das ohne Objektorientierung funktioniert. 
Allerdings wurde mir beigebracht, soll man (wenn möglich) immer objektorientiert programmieren. 

Bei dem Tic Tac Toe Spiel erstell ich mir ein String array, 
z.B. String array [][] = new String [3][3];
Und dann je nachdem was der Nutzer eingegeben hat, wird das Array dann mit einem String Wert gefüllt. Z.B. Gibt der Nutzer für Spalte 1 und für Zeile 2 ein , dann wird array[1][2] = "X" gesetzt. Und so geht das immer weiter.
Aber kann ich mir den array z.B. auch als Objekt erstellen? 
Oder macht das bei der TicTacToe Aufgabe keinen Sinn?

Danke für eure Hilfe und sorry wenn ich es etwas unverständlich erklärt habe.

LG


----------



## JStein52 (9. Dez 2015)

Mache es doch erst mal so. -> Lernerfolge. und dann überlegst du nochmal ob du es auch anders lösen könntest.
Und würde ein boolean array[][] = new boolean[3][3] nicht auch reichen?

Du könntest dir vielleicht eine Klasse Spielfeld erstellen, die wiederum dieses boolean array verwaltet. Dann kannst du dir geeignete Methode ausdenken. In der main-Methode legst du dir dann ein Spielfeld an usw.
Methoden auf Spielfeld wären evtl.
myspielfeld.clean();
myspielfeld.setField(int x, int y);
myspiel.ischGameOver();
myspielfeld.display();

usw....

und spasseshalber könntest du dir auch save- und load- Methoden implementieren. Wenn der Benutzer dann z.B. "Ende" eingibt dann speicherst du das Spielfeld in einer Datei. und beim Start kann man sagen aus welcher Datei man ein Spiel laden und fortsetzen möchte. Nur so als Denkanstoss


----------



## buggy84 (9. Dez 2015)

> Aber kann ich mir den array z.B. auch als Objekt erstellen?



Ist ein Array denn kein Objekt?

http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html


----------



## Dompteur (9. Dez 2015)

JStein52 hat gesagt.:


> Und würde ein boolean array[][] = new boolean[3][3] nicht auch reichen?


Nein, denn bei Tic-Tac-Toe hat jedes Feld 3 Zustände : leer, X, O


----------



## JStein52 (9. Dez 2015)

Ihr redet von verschiedenen arrays. Du meinst die Klasse Array (siehe dein Link), der TO redet aber von "arrays" im herkömmlichen Siin, also z.B. int[] meinIntArray;
Die Theoretiker könnten sich jetzt streiten ob so was ein Objekt ist .

@Dompteur : ok, dann halt ein int[][] spielfeld. Man sollte schon Tic-Tac-Toe kennen


----------



## JStein52 (9. Dez 2015)

Nochmal zum Thema Objekt, Klasse, arrays etc. in Java:

die primitiven Datentypen int, double, boolean etc. sind keine Klassen also sind einfache Variablen und auch arrays  dieses Typs keine Objekte (als Instanz einer Klasse). Etwas anders ist das schon mit String. Das ist tatsächlich eine Klasse und deshalb kann man Variablen dieses Typs (und auch arrays) als Objekte bezeichnen.


----------



## Joose (9. Dez 2015)

JStein52 hat gesagt.:


> die primitiven Datentypen int, double, boolean etc. sind keine Klassen also sind einfache Variablen und auch arrays  dieses Typs keine Objekte (als Instanz einer Klasse)



Du hast recht was die primitiven Datentypen angeht, aber Arrays egal von welchem Typ sind (spezial) Objekte!
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html

Auch in der Java Language Specification ist es so definiert 
http://stackoverflow.com/questions/8781022/is-an-array-an-object-in-java


----------



## JStein52 (9. Dez 2015)

Ja, ich weiss schon. Es gibt ja auch Methoden auf solche arrays. Übrigens auch eine getClass();
@Joose : was ergibt dieser Aufruf eigentlich z.B. für ein int[] ??


----------



## buggy84 (9. Dez 2015)

> die primitiven Datentypen int, double, boolean etc. sind keine Klassen also sind einfache Variablen und auch arrays dieses Typs keine Objekte (als Instanz einer Klasse).



Und ich hab extra nochmal die docs verlinkt, damit niemand sowas schreibt


----------



## Mustard444 (9. Dez 2015)

Also würdet ihr mir jetzt statt einem String Array zu einem int Array raten? 

Ich steh jetzt gerade aber immernoch auf dem Schlauch.  Bisher hab ich Objekte immer über den Konstruktor erzeugt (alternativ könnte ich es mit den Settern machen) und dann habe ich den Objekten immer konkrete Werte zugeordnet. 
Kleines Beispiel:

```
public class Test {

      private String a ;
      private int zaehler;

      public Test (String a, int zaehler) {
            this.a = a;
            this.zaehler = zaehler;
      }
```

Und dann hab ich eben in einer anderen Klasse mein Objekt erstellt:


```
public class TestStart {
     
      Test test1 = new Test ("Hallo",2);
}
```

Nur wie mach ich das jetzt mit dem Array? Und eigentlich will ich das Array ja erst leer lassen und dann durch den Benutzer befüllen lassen.

Danke euch


----------



## Joose (9. Dez 2015)

buggy84 hat gesagt.:


> Und ich hab extra nochmal die docs verlinkt, ...



Du hast die Dokumentation von der Klasse Arrays verlinkt. Diese Klasse enthält aber nur Methoden welche eben Arrays verwenden.
Für "Array" gibt es keine Klasse.



Mustard444 hat gesagt.:


> Also würdet ihr mir jetzt statt einem String Array zu einem int Array raten



Zu einem String Array.
Der Vorteil du kannst es direkt leer lassen oder eben mit "X" und "O" befüllen.
Bei einem int-Array müsstest du die Zahlen erst wieder auf leer, "X" oder "O" ummappen.



Mustard444 hat gesagt.:


> Ich steh jetzt gerade aber immernoch auf dem Schlauch. ....... Nur wie mach ich das jetzt mit dem Array?



Eine mögliche Variante:

```
public class Spielfeld {
   String[][] fields;
   
   public Spielfeld() {
     fields = new String[][];
   }
   
   public setzeMarkierung(int spalte, int reihe, String markierung) {
     // entsprechendes feld mit Markierung füllen
     // Markierung kann "X" oder "O" sein
   }
   
   ....
}
```

Methoden um zu überprüfen ob wer gewonnen hat musst du dir natürlich noch selber einfallen lassen


----------



## kneitzel (9. Dez 2015)

Hallo,

die objektorientierte Entwicklung hat erst einmal keinen wirklichen Einfluss darauf, wie Du Daten speicherst. Es wird lediglich verändert, wo die Daten gespeichert werden und wie auf diese zugegriffen wird.

Wenn Du also z.B. dem Vorschlag folgst, eine Klasse Spielfeld zu erzeugen, dann würde das Array in diese Klasse wandern. Du hättest dann also ggf. sowas wie

```
public class Spielfeld {
  private int[][] felder = new int[3][3]();
}
```
Was jetzt aber auch anders wird, ist der Zugriff. Du greifst nicht mehr direkt auf das Array zu, sondern Du schreibst alles in die Klasse. Wenn Du also z.B. eine Prüfung brauchst, ob ein Feld leer ist, dann musst Du eine Funktion in die Klasse Spielfeld hinzu nehmen:

```
public boolean istFeldLeer(int x, int y) {
  // Hier fehlt dann noch ein Check ob x und y ok sind.
  return felder[x][y] == 0;
```

Das bringt dann den Vorteil mit sich, dass die genaue Implementierung von Spielfeld erst einmal egal ist für die Nutzung. Wenn Du später meinst, dass ein array nicht gewünscht ist, dann ist das ok. Du musst dann nur die Klasse selbst anpassen. Da niemand von aussen das Innenleben kennt, spielt es keine Rolle.

Ich hoffe, ich konnte damit etwas weiter helfen.

Konrad


----------



## VfL_Freak (9. Dez 2015)

Moin,



Mustard444 hat gesagt.:


> Also würdet ihr mir jetzt statt einem String Array zu einem int Array raten?


Ist streng genommen eigentlich egal, Du musst nur auf den jeweiligen Inhalt entsprechend reagieren!



Mustard444 hat gesagt.:


> Bisher hab ich Objekte immer über den Konstruktor erzeugt (alternativ könnte ich es mit den Settern machen) und dann habe ich den Objekten immer konkrete Werte zugeordnet.


Anders geht es nur per Konstruktor 
Nur "Object myObj = newObject( ...)" ERZEUGT das Objekt!
Mit Settern kannst Du allenfalls Werte eines bereits erzeugten Objektes füllen!

Wenn ich Deine Eingangsfrage richtig verstehe, dann musst Du doch nur ein leeres Arrays erzeugen und mittels irgendwelcher Usereingaben mit Werten füllen ...
Wo genau ist jetzt Dein Problem?

Gruß Klaus


----------



## buggy84 (9. Dez 2015)

> java.util ava.util
> *Class Arrays*
> 
> java.lang.Object
> ...


----------



## Mustard444 (9. Dez 2015)

@Joose sorry wenn meine Frage jetzt dumm rüberkommt, aber warum setzt du die Initialisierung des Arrays in den Konstruktor? 
Deine Methode mit setzeMarkierung verstehe ich glaube ich. Da gibt halt der Benutzer eben die Zeile / Spalte ein, je nachdem ob es Benutzer 1 oder 2 ist habe ich ein X oder O. Und das übergebe ich mir in die Methode. 
Ne Methode zur Überprüfung wer gewonnen hab ich mir schon überlegt, nur die ist wahrscheinlich auch wieder 10 mal um Ecken gedacht.

@kneitzel die Idee mit dem int Array finde ich gut für die Überprüfung, ob die Stelle noch frei ist . Nur dann könnte ich ja nicht wie Joose beschrieben hat von einem String Array ausgehen sondern müsste das dann halt noch umwandeln. Oder kann man sozusagen 2 Arrays nebenher laufen lassen, dass der eine int Array guckt, ob die Stellen frei sind, der String Array eben die Stellen mit X / O / _ füllt? 

@VfL_Freak Du hast mich schonmal richtig verstanden  Mein Problem ist, dass ich irgendwie nicht ganz draufkomme, wie ich jetzt mithilfe von "Object myObj = newObject( ...)" mein Array erstelle. 
Weil wenn ich einfach String array [][] = new String [3][3] schreibe, hab ich zwar ein Array erstellt, aber irgendwie hab ich dann ja überhaupt kein Objekt erstellt. 

Sorry Leute für die dummen Fragen, wie ihr sicherlich merkt steh ich erst noch am Anfang von meiner "Java Karriere".

LG


----------



## Joose (9. Dez 2015)

@buggy84
Methoden gehören nun mal in eine Klasse und jede Klasse leitet von Object ab (sofern der Programmierer keine andere Ableitung angibt, aber auch da wäre die oberste Superklasse Object). Mehr wird da nicht dargestellt in der Dokumentation. Diese Klasse hat aber nichts mit dem (spezial) Objekt Array zu tun.



Mustard444 hat gesagt.:


> @Joose sorry wenn meine Frage jetzt dumm rüberkommt, aber warum setzt du die Initialisierung des Arrays in den Konstruktor?



Du kannst die initialisierung im Konstruktor oder direkt bei der Deklarierung machen, eigentlich egal.
Ich mache grundsätzlich alle Initialisierungen im Konsturktor, da der Konstruktor ja dazu gedacht ist ein Objekt in einem Basiszustand zu initialisieren.
Außerdem habe ich dann alle Initialisierung an einer Stelle. (Sollte es mehrere Konstruktoren geben weiß ich das sie im einen der Konstruktoren vorhanden sein muss)



Mustard444 hat gesagt.:


> Ne Methode zur Überprüfung wer gewonnen hab ich mir schon überlegt, nur die ist wahrscheinlich auch wieder 10 mal um Ecken gedacht.


Egal, solange sie am Ende funktioniert passt es doch erstmal.
Danach kann man immer noch überlegen ob es nicht einfacher geht 
(Immer Schritt für Schritt an die Lösung und optimieren kann man erst dann wenn es überhaupt läuft )



Mustard444 hat gesagt.:


> @kneitzel die Idee mit dem int Array finde ich gut für die Überprüfung, ob die Stelle noch frei ist . Nur dann könnte ich ja nicht wie Joose beschrieben hat von einem String Array ausgehen sondern müsste das dann halt noch umwandeln.


Wie du siehst hat es seine Vor- bzw. Nachteile eine String Array zu nehmen.
Hier musst du für dich entscheiden womit ist es logischer und einfacher für dich.



Mustard444 hat gesagt.:


> Oder kann man sozusagen 2 Arrays nebenher laufen lassen, dass der eine int Array guckt, ob die Stellen frei sind, der String Array eben die Stellen mit X / O / _ füllt?


Klar wenn du es programmierst funktioniert es natürlich.
Hierbei muss man aber eben aufpassen das wenn man das eine Array bearbeitet das andere ebenfalls bearbeiten muss damit die beiden Zustände immer synchron bleiben.


----------



## VfL_Freak (9. Dez 2015)

wenngleich ich zwei Arrays in diesem Fall für flüssiger als flüssig halt - also überflüssig halt 
Wenn eine Stelle gefüllt ist, dann sie doch automatisch auch nicht mehr frei (und umgekehrt natürlich) !!

Ob Du das Ganze jetzt als String (mit 'X' / 'O' / '_') nimmst oder als Integer (etwa '1', '2', '3), ist doch völlig egal, solange Dir klar ist was das einzelne zeichen rsp. die einzelne Zahl bedeutet. Ist nur eine Frage der Interpretation!!

Wenn es dann um die Darstellung auf dem Bildschirm geht, kannst Du einfach sagen: wenn die Stelle im Array '2' ist, dann zeichne ein 'O' .......

Gruß Klaus


----------



## kneitzel (9. Dez 2015)

Wie Du das Spielfeld implementierst ist Dir überlassen. Wichtig ist, dass Du die Schnittstellen festlegst und dann einfach eine Implementierung wählst, die mit möglichst wenig Aufwand erledigt werden kann.

Wenn man objektorientiert denkt, dann würde hier wohl weder eine Zahl noch ein String verwendet. Statt dessen gibt das Spielbrett ja eine Belegung durch einen Spieler an. Also wenn ich eine Klasse Spieler habe, dann wäre ein zweidimensionales Array denkbar, das Referenzen auf Spieler speichert.
Leer wären dann die Felder mit null-Referenz.

Die ganzen anderen Dinge wie "0" und "X" oder 1 und 2 sind ja nur Repräsentationen für den Spieler. Dann kann dann durchaus zu einem Spieler gehören also sowas ein Zeichen oder eine Nummer. Und dies kann dann durchaus benutzt werden um dann z.B. anzuzeigen: "Spieler " + spieler.getNr() + " ist an der Reihe!".

Aber dem Spiel ist es vollkommen egal, wie was angezeigt wird. Das kann dann ein "X" sein, aber evtl. ist es auch eine Grafik, die angezeigt wird.

Konrad


----------



## Mustard444 (10. Dez 2015)

Jetzt brauch ich doch nochmal eure Hilfe...
Mein Spieler 1 hat jetzt z.B. an die Stelle des Arrays [0] [0] ein X gesetzt.
Jetzt ist Spieler 2 an der Reihe und gibt z.B. [1] [1] ein. 
Wie kann ich den Spielstand jetzt ausgeben? Einerseits muss das X angezeigt werden und auch der neue eingegebene Wert von Spieler 2, das O. 

Ich weiß gerade überhaupt nicht weiter.
Ich könnte theoretisch mit einer for schleife die eingegebenen Werte von Spieler 1 überprüfen und je nachdem an die Stelle ein X setzen. Aber da wird man ja verrückt und schreibt 500 Zeilen Quellcode.

Gibt es da noch eine andere Lösung?


----------



## Joose (10. Dez 2015)

Bezogen auf ein String[][] als Spielfeld:

Einfach eine Methode schreiben und dein 2d Array durchgehen mit 2 for-Schleifen und jeden Wert ausgeben lassen


```
public void zeigeSpielfeld(String[][] spielfeld) {
   for(int reihe = 0; reihe < spielfeld.length; reihe++) {
     for(int spalte = 0; spalte < spielfeld[reihe].length; spalte++) {
       System.out.print(spielfeld[reihe][spalte]);
     }
     System.out.println("");
   }
}
```


----------



## kneitzel (10. Dez 2015)

Also je nach Anforderungen braucht man einiges an Code. Das ist durchaus normal und wirkliche Applikationen sind entsprechend groß.

In Deinem Fall verstehe ich aber nicht, wo Du meinst so viel Code schreiben zu müssen. Du musst für gewisse Dinge nur eben Funktionen schreiben und dann hast Du halt Aufrufe, die sich wiederholen.

So ergibt sich dann zum einen gut lesbarer Code und man hat auch keinen Code "doppelt". Sowas kann dann wie folgt aussehen (Pseudo-Code):

```
do {
   activePlayer = NextPlayer();
  do {
    Koordinaten koords = EingabeKoordinaten(activePlayer);
  while (spielfeld.koordinatenBelegt(koords);
  spielfeld.koordinateBelegen(koords, activePlayer);
} while (istSpielZuende() == false)
```
Halt so in der Art könnte dann z.B. das Spiel selbst aussehen/ablaufen.

Jede dieser Funktionen muss man dann halt mit Leben füllen. Aber Idee ist, dass immer alles relativ trivial bleibt. Also keine mega langen, komplizierten Funktionen. Statt dessen die Aufgabe immer so unterteilen, dass es zum einen lesbar und zum anderen verständlich bleibt.

Konrad


----------



## Mustard444 (10. Dez 2015)

Ich habe jetzt folgenden Quellcode, ähnlich wie deiner @Joose . Hatte vorhin nur kurz einen Denkfehler drin.

Klasse: TicTacToe



```
import java.util.Scanner;
public class TicTacToe {
  
    private static int zaehler = 1;
    private static String X = "X";
    private static String O = "O";
    static Scanner scanner = new Scanner(System.in);
    static int eingabeGanzzahl;
    static int eingabeGanzzahl2;
  
    static String array [] [] = {{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"}};
    static boolean pruefung [][] = new boolean [3][3];
      
    public static void eingeben() {

        if (zaehler >= 1 && zaehler%2 != 0) {
            System.out.println("Spieler 1 bitte Zeile eingeben (1-3): ");
            eingabeGanzzahl = scanner.nextInt();
            eingabeGanzzahl = eingabeGanzzahl-1;
            System.out.println("Spieler 1 bitte Spalte eingeben (1-3): ");
            eingabeGanzzahl2 = scanner.nextInt();
            eingabeGanzzahl2 = eingabeGanzzahl2-1 ;
        }
        else if (zaehler >= 1 && zaehler %2 == 0) {
            System.out.println("Spieler 2 bitte Zeile eingeben (1-3): ");
            eingabeGanzzahl = scanner.nextInt();
            eingabeGanzzahl = eingabeGanzzahl-1;
            System.out.println("Spieler 2 bitte Spalte eingeben (1-3): ");
            eingabeGanzzahl2 = scanner.nextInt();
            eingabeGanzzahl2 = eingabeGanzzahl2-1 ;
        }
        zaehler++;
        pruefen();
    }
  
    public static void pruefen () {
        if (eingabeGanzzahl < 0 || eingabeGanzzahl >2) {
            System.out.println("Bitte Zahl zwischen 1 und 3 eingeben!!!");
            TicTacToe.eingeben();
        }
            else if (eingabeGanzzahl2 < 0 ||  eingabeGanzzahl >2) {
            System.out.println("Bitte Zahl zwischen 1 und 3 eingeben!!!");
            TicTacToe.eingeben();
            }
        }
      
  
  
    public static void spielstandausgeben1 () {
      
        pruefung [eingabeGanzzahl2] [eingabeGanzzahl] = true;
        array [eingabeGanzzahl2][eingabeGanzzahl] = X;
        System.out.println("\n"+"Neuer Spielstand:"+"\n");
      
        for (int i = 0; i<array.length; i++) {
            for (int j = 0; j<array[i].length;j++) {
                System.out.print( array[j][i]+"\t");
            }
            System.out.println("\n");
        }
    }
```

Dann hab ich noch eine Klasse TicTacToeTest:



```
public class TicTacToeTest {
  
    public static void main (String[] args) {

        System.out.println("*******Willkommen bei Tic Tac Toe *******"+"\n");
        System.out.println("_"+"\t"+"_"+"\t"+"_"+"\n"+"_"+"\t"+"_"+"\t"+"_"+"\n"+"_"+"\t"+"_"+"\t"+"_"+"\n");
        TicTacToe.eingeben();
        TicTacToe.pruefen();
        TicTacToe.spielstandausgeben1();
        System.out.println();
        TicTacToe.eingeben();
      
    }

}
```

Bis hierher funktioniert es. Aber wenn ich es jetzt ausführe, kommt nachdem ich das 1. mal den Spielstand ausgegeben habe folgende Fehlermeldung:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
    at TicTacToe.spielstandausgeben1(TicTacToe.java:63)
    at TicTacToeTest.main(TicTacToeTest.java:10)

Das heißt ja eigentlich, dass ich irgendwie über die Länge meines Arrays hinausgegangen bin oder?
Die Frage ist jetzt aber wo..

Danke für eure Hilfe


----------



## Joose (10. Dez 2015)

Mustard444 hat gesagt.:


> Bis hierher funktioniert es. Aber wenn ich es jetzt ausführe, kommt nachdem ich das 1. mal den Spielstand ausgegeben habe folgende Fehlermeldung:
> 
> Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
> at TicTacToe.spielstandausgeben1(TicTacToe.java:63)
> ...



Naja es wird dir schon die genaue Zeile angezeigt. Sprich du weißt bei welchen Array es passiert und könntest dir entweder "eingabeGanzZahl2" und "eingabeGanzzahl" ausgeben lassen mit welchen du zugreifen willst (dann wirst du sehen mit welchen falschen du zugreifst).
Oder aber du setzt den Debugger deiner IDE ein und gehst die Applikation Schritt für Schritt durch und kontrollierst welche Werte die "eingabeGanzZahl2" und "eingabeGanzzahl" haben

Dein Fehler liegt bei der Ausgabe in der Schleife! Schau dir ganz genau an welchen Index du wofür verwendest!

Kleiner Hinweis:


Mustard444 hat gesagt.:


> ```
> static String array [] [] = {{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"}};
> static boolean pruefung [][] = new boolean [3][3];
> ```



Deine Variable "array" ist kein Array mit der Größe 3x3  sondern eher 9x3
Außerdem schreibe die "[][]" nicht hinter den Namen der Variable sondern hinter den Typ.
Java akzeptiert zwar beides, aber so ist auf den 1.Blick ersichtlich das es sich um ein String[][] handelt.
Bei deinem Code würde man zuerst sehen man hat einen "String" und erst danach sieht man die "[][]" beim Namen.


----------



## VfL_Freak (10. Dez 2015)

Moin,

steht doch da !!! 

*at TicTacToe.spielstandausgeben1(TicTacToe.java:63)
*
Gruß Klaus


----------



## Mustard444 (10. Dez 2015)

Tatsächlich, was für ein dummer Fehler  
Stimmt, jetzt im Nachhinein war das kein 3x3 Array. Die Klammern werd ich jetzt auch immer nach dem Datentyp schreiben, ich hatte mir nur gemerkt, dass Java beides akzeptiert.

Ich weiß, dass der geübte Programmier die Fehlermeldungen auslesen kann, aber ich selber kann es leider nicht so gut.. Der Fehler passiert in der Methode spielstandausgeben1 , aber was heißt das java:63? 
Ich hab erst gedacht, Zeile 63, aber das kann nicht sein. 

Danke euch


----------



## JStein52 (10. Dez 2015)

Aber genau das heisst es ! Poste doch mal den Code-Ausschnitt und markiere die Zeile 63


----------



## Mustard444 (10. Dez 2015)

@JStein52  ich hab jetzt leider meinen Code schon wieder geändert  
Aber ich kann mir merken, dass java:Zahl die Zeile bedeutet, wo der Fehler passiert? 
Vielleicht hab ich vorhin auch nur falsch geschaut.. ich vertrau euch mehr als mir was Java angeht.

Danke


----------



## Joose (10. Dez 2015)

Der Fehler lag bei der Ausgabe in den verschachtelten for-Schleifen


```
static String array [] [] = {{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"},{"_","_","_"}};
......

for (int i = 0; i<array.length; i++) {
   for (int j = 0; j<array[i].length;j++) {
     System.out.print( array[j][i]+"\t");
   }
   System.out.println("\n");
}
```

Du hast ein 9x3 Array gehabt.
Die äußere for-Schleife läuft also von 0-8, die innere von 0-2.
Bei der Ausgabe in der inneren Schleife hast du nun aber die Indexe vertauscht. Somit hast du "irgendwann" auf "array[0][3]" zugreifen wollen was aber nicht möglich ist.

Bei solchen Ausgaben von mehr Dimensionalen Arrays (könnten theoretisch auch mehr als 2 sein) verwendet man meist verschachtelte for-Schleifen.
Die Zählervariablen der for-Schleifen von außen nach innen sind die entsprechende Indexe von links nach rechts.

Sind alle Dimensionen gleich groß gibt es das Problem nicht, hier kann man dann wenn nur eine falsche Ausgabe bekommen.

Nachdem du dein 2d Array angepasst hast sollte der Fehler nicht mehr auftauchen.


----------



## JStein52 (10. Dez 2015)

@Mustard444 : Richtig !!


----------



## Mustard444 (10. Dez 2015)

Ich bin jetzt fast fertig mit dem Programm.

Wenn ein Unentschieden herauskommt, möchte ich noch fragen, ob die Benutzer erneut spielen wollen. 
Wenn sie dann 1 für ja eingeben, soll das Programm neu gestartet werden.
Ich hab gedacht, dass das so geht:


```
System.out.println("Unentschieden! Keiner hat gewonnen! Nochmal spielen?");
            System.out.println("[1] JA"+"\n"+"[2] NEIN");
            eingabe = scanner.nextInt();
            if (eingabe == 1) {
                TicTacToeTest.main(String []args);
            }
            else if (eingabe == 2) {
                System.exit(0);
            }
```

Nur wenn ich das so mache, dann kommt eine "java.lang.NullPointerException" Fehlermeldung.
Ich steh gerade ein bisschen auf dem Schlauch, weil ich gedacht habe, dass man die main Methode einfach mit Klassenname.main(String[]args) aufrufen kann..

Danke für eure Hilfe


----------



## VfL_Freak (10. Dez 2015)

Oh oh oh ... 

Überleg' mal genau, was diese Zeile macht (und was Du dort eigentlich machen willst) ... 

```
TicTacToeTest.main(String []args);
```

Gruß Klaus


----------



## Mustard444 (10. Dez 2015)

Also ich will die main Methode aufrufen. Sodass eben der Code von vorne beginnt. 

Eigentlich dachte ich die Zeile ruft einfach nur die main Methode auf. Die main Methode ist ja auch nur eine normale Methode. 
Anscheinend bin ich gerade irgendwie auf dem Holzweg


----------



## Mustard444 (10. Dez 2015)

Also ich hab jetzt folgendes herausgefunden:

Wenn ich es so schreibe, funktioniert mein Programm:

"TicTacToeTest.main(new String[] {"args"});"

Nur warum ist das so?


----------



## VfL_Freak (10. Dez 2015)

Mustard444 hat gesagt.:


> Also ich will die main Methode aufrufen. Sodass eben der Code von vorne beginnt.
> Eigentlich dachte ich die Zeile ruft einfach nur die main Methode auf. Die main Methode ist ja auch nur eine normale Methode.
> Anscheinend bin ich gerade irgendwie auf dem Holzweg


Aber sowas von .... 


```
TicTacToeTest.main(String []args);
```
(a) die Main-Methode eines Programms kann NICHT innerhalb des Programms aufgerufen werden !!
(b) Dein Parameter "String []args" wäre eine DEKLARATION des Stringarrays !! Dass führt bei einem Methodenaufruf logischerweise zu einem Compilerfehler!

Gruß Klaus


----------



## VfL_Freak (10. Dez 2015)

Mustard444 hat gesagt.:


> Wenn ich es so schreibe, funktioniert mein Programm:
> "TicTacToeTest.main(new String[] {"args"});"


Sehr unwahrscheinlich, dass es das macht, was es soll!
Ok, Du deklarierst jetzt als Übergabe ein neues Array mit dem Inhalt "args"!
Was sollte Das Programm wohl mit diesem String anfangen??

Ich würde um den gesamten Ablauf eine Schleife legen, die bei "nochmal = J" erneut durchlaufen wird oder anderfalls abbricht !!

gruß Klaus


----------



## Mustard444 (10. Dez 2015)

@VfL_Freak  da hattest du (mal wieder) recht, das funktioniert so auch nicht. Zwar fängt es wieder von vorne an, aber mein Array ist immernoch mit Werten befüllt etc. 

Also ich leg z.B. eine while schleife um mein gesamtes Programm in der main Methode. 
Folgendes Problem: Wenn ein Spieler gewinnt, ist das Programm früher zu Ende. Das bedeutet, es gibt noch Methoden Aufrufe in der main Methode, die aber nicht mehr aufgerufen werden, weil ein Spieler schon gewonnen hat.
Wenn das Spiel Unentschieden ausgeht, dann kann ich das am Schluss meiner main Methode implementieren, dass man mit der while Schleife das Programm neu starten kann. Aber wie mache ich das, wenn ein Spieler gewonnen hat? Und ich somit noch nicht am Ende meiner main Methode bin?


----------



## JStein52 (10. Dez 2015)

if (...)
   mache das eine
else
    mache das andere


----------



## Mustard444 (10. Dez 2015)

Also bisher hab ich es weder mit der while Schleife noch mit der If Bedingung geschafft..
Denn wenn ein Spieler gewonnen hat, macht das Programm einfach da weiter, wo es in der main Methode aufgehört hat, obwohl es eigentlic von vorne starten sollte..

ein 
while (test = true) {
Programmcode
}
funktioniert irgendwie nicht

Sorry , dass ich es nicht verstehe was ihr meint.


----------



## VfL_Freak (10. Dez 2015)

Moin,



Mustard444 hat gesagt.:


> funktioniert irgendwie nicht


das ist KEINE Fehlerbeschreibung !!! 



Mustard444 hat gesagt.:


> (test = true)


Überleg' mal genau, was Du damit machst !!!!!

Gruß Klaus


----------



## Mustard444 (10. Dez 2015)

Ich würde es dir gerne genauer beschreiben, aber ich kann es leider nicht. Ich fass einfach nochmal zusammen:
1) Ich möchte , dass mein Programm entweder am Ende des Programmdurchlaufs oder auch in der Mitte des Durchlaufs von vorne beginnt ,wenn der Nutzer dies so eingibt.
2) Die wohl einfachste Lösung ist es, eine große while Schleife um den gesamten Code in der main Methode zu machen.
3) Die while Schleife läuft immer durch, solange der Ausdruck true ergibt.
4) Das bedeutet, wenn ich den Ausdruck in meiner Schleife auf true lasse, läuft der Code von vorne los. Das funktioniert auch, aber nur wenn ich am Ende meines Programmes bin.
5) Wenn ich in der Mitte meines Programmes bin und ich von vorne starten will , bringt es mir nichts, den Ausdruck in der while Schleife auf true zu lassen, weil dann erst noch der nachfolgende Code ausgeführt wird, was ich ja genau nicht will.
6) Andere Idee: Ich könnte theoretisch vor jeden Befehl in der main Methode eine if Bedingung hinsetzen. Sobald der Ausdruck in einer von den vielen if Bedingungen false wird, stoppt das gesamte Programm. Aber ich weiß nicht, ob das eine gute Idee ist bzw ob das funktionieren würde. 

Jetzt hab ich alles beschrieben, wie mein Wissensstand jetzt gerade ist.


----------



## JStein52 (10. Dez 2015)

Auf diesen Punkt 5) bezog sich mein Hinweis mit if-Abfrage. Du wirst doch irgendeine Bedingung haben anhand der du entscheiden kannst ob du die restlichen Anweisungen noch ausführen willst oder nicht.


----------



## VfL_Freak (10. Dez 2015)

Moin,

grundlegend ist die Idee

```
while (test = true)
{
     Programmcode
}
```
schon richtig, aber du solltest 'test' *vergleichen*, nicht jedesmal neu auf 'true' setzen !!!

Also:

```
while (test == true) // !!!!!
{
     Programmcode
}

// oder besser gleich
while (test ) // was ja soviel heißt wie "solange 'test' true ist !!
{
     Programmcode
}
```

Gruß Klaus


----------



## kneitzel (10. Dez 2015)

Also es gibt ein paar Punkt, die wichtig sind:
a) mach nicht alles statisch - das bringt mehr Probleme mit, als notwendig ist.
b) Nutz mehr Funktionsaufrufe. Wenn Du eine Funktion "spielen" hast, die das eigentlich Spiel beinhaltet, dann kannst Du jederzeit mitten drin ein return nutzen um eben sofort raus zu gehen.
c) Du hast ja wohl auch geschrieben, dass Du da Probleme hattest, wenn Du main erneut aufrufst (was extrem unüblich ist, aber natürlich prinzipiell funktioniert). Dies liegt daran, dass Du keine saubere Initialisierung hast, denn Du hast ja berichtet, dass du dann die Daten des vorherigen Spiels immer noch hattest.

Konrad


----------



## JStein52 (10. Dez 2015)

Klar kann man main aufrufen, dann wird das halt rekursiv. Und die Daten des vorherigen Spiels hast du weil die ja auch static sind. Und wie @kneitzel schreibt hast du keine saubere Initialisierung für deine Daten.
Aber nochmal: du kannst du an irgendwelchen strategischen Stellen im Spielablauf diese Bedingungsvariable für deine Schleife auf einen neuen Wert setzen und diesen innerhalb der Schleife benutzen um festzustellen ob du jetzt den restlichen Code in der Schleife noch ausführen willst oder eben auch nicht.


----------

