Datentyp mit 3 Zuständen

Hag2bard

Bekanntes Mitglied
Hallo,

Ich wollte mich mal an einem TicTacToe wagen.
Dazu möchte ich 3 Arrays erstellen die jeweils eine Reihe (waagerecht) darstellen.
Nun soll getestet werden ob Spieler 1, Spieler 2 oder keiner einen Stein in ein gewisses Feld gesetzt hat. Also ein X, ein O oder keine Belegung.
Bei der Suche nach einem Datentyp mit 3 Zuständen stieß ich auf verschiedene Lösungen. Entweder int mit -1, 0, 1.
Oder Boolean mit null, false, true.
Oder enum.

Die Lösung mit Boolean finde ich eigentlich ganz gut. Allerdings habe ich gelesen dass enum eine gute Lösung sein sollen.
Nun hab ich mich tot gegoogelt und keine Idee wie die Syntax für enum sind.
Rausgefunden hab ich bisher folgendes:

[CODE lang="java" title="enum"]package calculator;

public enum mapping {
NONE, //keine Belegung
X, //Spieler X
O //Spieler O
}
[/CODE]

Aber wie nutze ich das nun?

Danke im Voraus
 
Enums werden üblicherweise mit dem ersten Buchstaben gross geschrieben, so wie auch Klassen.

Du kannst die Enums dann in einem Array benutzen:

Mapping[] reihe = new Mapping[ 3 ];
 
Aber wie nutze ich das nun?
Naja, als `mapping.NONE`, `mapping.X` oder `mapping.O`.
Du kannst Variablen deklarieren mit Typ `mapping`:
Java:
public void meineMethode() {
  // Variable `feld` vom Typ `mapping` deklarieren und z.B. mit `mapping.NONE` initialisieren.
  mapping feld = mapping.NONE;
  // wenn Spieler X feld belegt hat:
  feld = mapping.X;
  // oder halt für Spieler O:
  feld = mapping.O;
}
Ist halt genau dasselbe, wie jeder andere Datentyp, nur, dass die Inkarnationen/Werte dieses Datentyps nur seine Enumliterale sein können (inklusive null, da enums auch Referenztypen sind).
 
Entschuldigung, es fehlte noch das Befüllen des Arrays:
[CODE lang="java" title="Array Befüllen"]java.util.Arrays.fill(reihe, Mapping.NONE);[/CODE]
 
Vielen Dank für die Antworten.
Danke auch für den Tipp mit den Konventionen.
Zum Thema Spielfeld-Objekt: Danke für die Kritik, ich möchte von Anfang an alles richtig machen. Nach welcher Begrifflichkeit kann ich denn googlen? Ich hab noch nie was von einem Spielfeld-Objekt gehört.

LG
 
Aber wie soll ich dies realisieren.
Meine Idee wäre eine eigene Klasse mit einer Methode, die 3 enum Arrays beinhaltet in dem die Zustände gespeichert werden. Und dazu noch eine Methode, die mir das Spielfeld in der Konsole ausgibt
 
Grundsätzlich gibt es ganz verschiedene Möglichkeiten, TicTacToe zu realisieren. Man kann es schnell runtertippen, was bei einem (Konsolen)Spiel dieser Größe sicher ausreichend wäre, oder man nutzt das Spiel als kleines Übungsobjekt, um z. B. etwas in die objektorientierte Modellierung einzusteigen. Das Ergebnis ist dann zwar völlig over engineered, aber das wäre in dem Fall durchaus erwünscht.

Für mich wäre also erstmal die Frage, was Du mit dem Spiel bezweckst, welchen Weg Du einschlagen möchtest?
 
Ich möchte nicht einfach nur ein TicTacToe programmieren um es programmiert zu haben, sondern das Programmieren professionell erlernen. Also sehr gerne over engineered.
Aber bevor ich mir einen fertigen Quellcode klaue, möchte ich es selber hinkriegen.
 
Aber bevor ich mir einen fertigen Quellcode klaue, möchte ich es selber hinkriegen.
Fertigen Code hättest Du eh nicht bekommen 😛

Gut, dann vergiss mal für einen Moment die technischen Details und überleg Dir, welche Objekte (bzw. in der Konsequenz Klassen) in einem solchen Spiel auftauchen, und welche Aufgaben diese übernehmen. In der OO geht es hauptsächlich darum, gute Abstraktionen zu finden.

Das Spielfeld hast Du ja schon. Was ist das Spielfeld, welche Aufgabe hat das Spielfeld, ganz grob? Man könnte z. B. sagen, dass das Spielfeld seine Felder, d. h. die Belegung der Felder verwalten soll. Das ist ja mal ein Anfang.

Wenn Du jetzt mit Deinem Spielfeld sprichst und wissen willst, wie die Belegung auf einem Feld ist, wie sagst Du dem Spielfeld welches gemeint ist? Es geht hier nicht um Code/technische Realisierung, sondern einfach um die Frage, wie Du ein Feld adressierst. Ideen?
 
Hallo,

Sorry dass ich jetzt erst antworte.
Wenn ich könnte wie ich wollte, würde ich jetzt schon an einem 2. Minecraft basteln 😀
1. Ich würde eine Klasse anlegen, in der das Spielfeld auf der Konsole gezeichnet wird.
2. Eine Klasse die den Spielablauf regelt, also das 2D Array mit Werten füllt sobald ein Spieler einen Zug macht.
3. Dann in der selben Klasse noch die Gewinnbedingungen regeln.
Das heißt ein paar einfache If Bedingungen. Bei TicTacToe gibt es nicht viele Möglichkeiten zu gewinnen.
In der selben Klasse muss ein Gleichstand geregelt werden.
4. Und eine Klasse für den PC, die je nach dem welche Züge ich mache, den PC Züge machen lässt. Dabei könnte man mit if Bedingungen eine Art KI bauen.
5. Eine Klasse die dem menschlichen Spieler Tipps gibt.


Mehr fällt mir nicht ein.
Schritt 1 wäre gebastel, dass muss ich ausprobieren wie ich das hinbekomme.

Mit dem Spielfeld kommunizieren würde ich, indem ich ein Switch Case Gerüst baue, dem ich für Menschen logische Koordination gebe und welches das 2D abklappert und die Belegung zurück gibt.
 
Das ist doch schon sehr gut. Bei Punkt 2: nicht das 2D-Array, sondern das Spielfeld. Punkte 4 und 5 kannst Du hinten anstellen.

Mit dem Spielfeld kommunizieren würde ich, indem ich ein Switch Case Gerüst baue, dem ich für Menschen logische Koordination gebe und welches das 2D abklappert und die Belegung zurück gibt.
Switch brauchst Du hier nicht. Koordinaten wäre ein weiterer Kandidat für eine Klasse (over-engineered). Außerdem wirst Du irgendwas für das zunächst rein textbasierte UI brauchen.

Sofern Du Code hast, kannst ihn auch hier zur Diskussion stellen, wenn Du willst.
 
Ich möchte eine Methode erstellen, die prüft ob das Spielfeld auf der gewählten y Achse belegt ist. Sie gibt dann true oder False zurück. Als Übergabeparameter bekommt sie einen int Wert 1, 2 oder 3
Die ÜbergabeWerte soll die Methode jeweils um eins dekrementieren, damit sie zum 2D Array (Index ab 0) passen.
Ich möchte aber auch übergeben an welcher y Stelle, falls sie nicht leer ist der erste freie Platz ist.
Dafür, so habe ich gelesen könnte ich auch ein Objekt übergeben.
Aber 1. Ist das Sinnvoll?
2. Welches Objekt soll ich übergeben?
3. Ich bin auf meinem 2d array irgendwie hängen geblieben, wie soll ein Spielfeld aussehen?
4. Oder soll ich einer privaten Variable mithilfe eines Setters den Wert auf der y Achse übergeben?
 
Ok ich habe also eine Instanz der Enum Klasse erstellt. Was fang ich damit an?
Somit habe ich doch letztendlich die 3 Werte, mit denen ich das 2D Array fülle, oder nicht?
P.s. instanz einer Klasse ist ein Objekt oder?
Braucht meine enum Klasse noch einen Konstruktor oder Methoden?

Edit: Achso das Objekt ist ja letztendlich mein Spielfeld mit einem 2D Mapping Array oder?
 
Das würde bedeuten, dass Du irgendwas mit new hingeschrieben hast.

Das erlaubt der Compiler nicht.

Die enum-Member sind bereits Instanzen, die einzigen erlaubten Instanzen.

Du solltest an der Genauigkeit Deiner Formulierung arbeiten.
Aber das habe ich doch wenn ich das hier eintippe
Java:
Mapping[][] spielfeld = new Mapping[3][3];

Wenn ich eine Instanz einer Klasse erzeuge, dann habe ich ein Objekt erzeugt?
Gerne korrigiert mich in meinen Aussagen
 
Zuletzt bearbeitet:
Wenn ich eine Instanz einer Klasse erzeuge, dann habe ich ein Objekt erzeugt?
Gerne korrigiert mich in meinen Aussagen
Du erzeugst hier ein Array, das Platz für 3x3 Referenzen auf Mapping-Instanzen bietet. Nach dieser Anweisung sind alle Werte null. Die einzelne Mapping-Instanz erzeugst Du nicht, die gibt es schon.

Wenn Du ein wenig mehr über die Hintergründe wissen willst: https://www.java-forum.org/thema/von-datentypen-und-mehrdimensionalen-arrays.189506/
 
Ich wollte mich mal an einem TicTacToe wagen.
Ich habe so etwas auch einmal für die Konsole gemacht. Man kann 3 verschiedene Spielstärken de CPU einstellen.
1621209669635.png
Hier die verwendeten Variablen und der Algorithmus. Wenn dich der komplette Code interessiert dann gib Bescheid.
[CODE lang="java" title="TicTacToe" highlight="18-26"]public class TicTacToe {
// define random object
private static Random random = new Random(System.currentTimeMillis());
// define input object
private final static Scanner input = new Scanner(System.in);
// define board's dimension
private final static int BOARD_DIM = 3;
// create char array board with 3 x 3 positions
private static char board[] = new char[BOARD_DIM * BOARD_DIM];
// define board's used characters
private final static char PLAYER = 'x';
private final static char CPU = 'o';
private final static char EMPTY = ' ';
private final static int NOT_FOUND = -1;
private static int level = 1;

public static void main(String[] args) {
resetBoard();
level = inputNumber("KI-Staerke waehlen [1-3]", 1, 3);
char player = getBeginner();
while (!isBoardFull()) {
if (doMove(player))
break;
player = getNextPlayer(player);
}
System.out.println("ENDE");
}[/CODE]
 
Danke für das gute Informationsmaterial. besonders spannend fande ich die Belegung des Speichers bei mehrdimensionalen Arrays.

Ich werde jetzt mal versuchen mein Grundgerüst zu bauen und dann poste ich den Code. Dann kann man ja nochmal schauen, was sich optimieren lässt.
 
Ich habe gerade ein Problem dabei ein 2D Array in einer anderen Klasse zu nutzen.
Ich dachte dies würde mit Getter und Setter funktionieren aber IntelliJ bringt mir immer wieder die Fehlermeldung:

Cannot resolve symbol 'getMap1' (in Zeile 12 Klasse GameLogic)
Und in der Klasse GameLogic meckert er dann später wenn ich mit dem Array arbeiten möchte.
Wenn ich den Zugriffsmodifikator des 2D Arrays auf public stelle, habe ich das selbe Problem.
Wenn ich den Zugriffsmodifikator des 2D Array auf public static stelle und die Klasse ConsoleOutput importiere, dann funktioniert es.

Mein Code:

[CODE lang="java" title="Klasse GameLogic"]package de.hagbard.tictactoe;

public class GameLogic {
private int temp;
public int getTemp() {
return temp;
} //getter temp
public void setTemp(int temp) {
this.temp = temp;
} //setter temp
ConsoleOutput co = new ConsoleOutput(); //Instanz der Klasse ConsoleOutput
co.getMap1(); //Getter Methode aufrufen[/CODE]

[CODE lang="java" title="Klasse ConsoleOutput"]package de.hagbard.tictactoe;



public class ConsoleOutput {
private EMap[][] map1 = new EMap[3][3];
public EMap[][] getMap1() {
return map1;
}
public void setMap1(EMap[][] map1) {
this.map1 = map1;
}[/CODE]
 
Oh man das hätte ich wissen müssen, dankeschön

Mit einer Fehlermeldung wie unreachable code hätte ich wahrscheinlich mehr anfangen können
 
Oh man das hätte ich wissen müssen, dankeschön

Mit einer Fehlermeldung wie unreachable code hätte ich wahrscheinlich mehr anfangen können
Die Meldung wäre dann aber falsch gewesen, denn der Code ist nicht unreachable 🙂

Mich wundert allerdings die Meldung von IntelliJ, der Compiler wirft eine wesentlich schönere Meldung raus: "error: <identifier> expected"
 
Im Internet gibt es Glaubenskriege zwischen den IDE Benutzern. Ich bin auch noch nicht sicher, welche IDE ich benutzen soll.
Völlig egal, so lange es nicht Eclipse ist 🙂

Kleiner Scherz. Du kannst natürlich auch Eclipse verwenden. Mit dieser IDE, so ist zumindest mein Eindruck, haben aber wesentlich mehr Leute ein Problem als mit anderen. Kann natürlich auch einfach an der Masse der User liegen. Viele mögen IntelliJ, mir persönlich liegt NetBeans besser; war halt meine erste IDE. Schau Dir die Teile einfach an und such Dir aus, was Dir zusagt.
 
Hallo nochmal,
ich habe meinen Code nun deutlich mehr ausgebaut, alles in Methoden aufgeteilt, welche von der Main() aus aufgerufen werden.
Ich habe eine Klasse namens GameLogic, welche das Spielfeld erstellt (In der Klasse selbst, nicht in einer Methode).
In der KlasseGameLogic habe ich ebenso eine Methode die das Array mit den Werten NONE füllt (aus meiner EMap(früher Mapping)).
Für das Spielfeld habe ich einen Getter und einen Setter gebaut.
Ich erstelle in der Main eine Instanz der Klasse GameLogic (somit müsste mein SpielFeld erstellt worden sein)
Anschließend rufe ich die Methode zum befüllen des Arrays auf. (Methode befindet sich in der Klasse GameLogic)
Nun (habe vorher schon die Klasse ConsoleOutput instanziiert) rufe ich die Methode output() auf, die mir das befüllte Array zuerst mit einem getter aus der Klasse GameLogic holt und anschließend ausgibt).
Aber das Problem ist, er gibt nicht NONE aus, sondern NULL.
Das heißt das mit dem Getter hat nicht funktioniert.

Hier der Code

[CODE lang="java" title="Main Klasse"]package de.hagbard.tictactoe;

public class Main {
public static void main(String[] args) {
GameLogic gl = new GameLogic(); //Instanz der Klasse erstellt wegen Datentypen
ConsoleOutput co = new ConsoleOutput(); //Instanz erstellt da benötigt
KI ki = new KI(); //Instanz der Klasse KI erstellt - noch nicht benötigt
gl.fillArray(); //Array füllen
co.output(); //Array ausgeben
co.choosePlayer(); //Ausgabe Spielfigur wählen
gl.choosePlayer(); //Spielfigur auswählen
gl.rndStartPlayer(); //Zufalliger Anfanger True = X False = O
System.out.println("Programmende");
}
}[/CODE]

[CODE lang="java" title="Klasse GameLogic"]package de.hagbard.tictactoe;
import java.util.Scanner;
import java.util.Random;

public class GameLogic {
Scanner usr = new Scanner(System.in);
private boolean firstPlayer = true;
public String user = ""; //???Lieber in EMap casten?
private int temp=0;
public int getTemp() {
return temp;
} //getter temp
public void setTemp(int temp) {
this.temp = temp;
} //setter temp
private EMap [][] map1 = new EMap[3][3]; //Spielfeld
public void fillArray(){ //Methode Spielfeld mit NONE füllen
for (int j=0; j<3; j++) {
for (int i = 0; i < 3; i++) {
map1[j] = EMap.NONE;
}
}
}
public EMap[][] getMap1() { //Getter Spielfeld
return map1;
}
public void setMap1(EMap[][] map1) { //Setter Spielfeld
this.map1 = map1;
}
public void choosePlayer(){ //In String user wird X oder O gespeichert
user = usr.next(); // X = True O = False (siehe rndStartPlayer())
if (!user.equals("O")&&!user.equals("X")){
System.out.println("Gültigen Buchstaben eingeben!");
ConsoleOutput co = new ConsoleOutput();
co.choosePlayer();
choosePlayer();
}
}






public boolean isFull(int row){
for (int i=0; i<3; i++){
if (map1[row]!=EMap.X && map1[row]!=EMap.O){
setTemp (i);
return false;
}
}
return true;
}

public void playMove(int row, EMap map){
if (!isFull(row)){
map1[row][getTemp()]=map;
}
}

public void rndStartPlayer(){
Random sp = new Random(); //Random Objekt erzeugt (was an Konstruktor übergeben??)
this.firstPlayer=sp.nextBoolean(); //X = True O = False

}
}[/CODE]


[CODE lang="java" title="Klasse ConsoleOutput"]package de.hagbard.tictactoe;



public class ConsoleOutput {
EMap[][] map1 = new EMap[3][3]; //Array innerhalb der Klasse erstellt
public void output() {
GameLogic gl = new GameLogic();
map1 = gl.getMap1(); //Array synchronisiert
for (int j = 0; j < 3; j++) { //Ausgabe des Spielfeldes UNFERTIG
for (int i = 0; i < 3; i++) {
System.out.println(map1[j]);
}
}
}
public void choosePlayer(){
System.out.println("Möchten Sie Spieler X oder Spieler O sein?");
}
}[/CODE]

Also das mit dem Array verstehe ich immer noch nicht.
Muss ich nun in der Klasse ConsoleOutput erstmal ein neues Spielfeld erstellen, welches dann die Adresse (mit Hilfe des Getters) vom Spielfeld aus der Klasse GameLogic übernimmt? Genau so habe ich es nämlich gemacht.
Aber meine Konsolenausgabe sagt mir was anderes.


Also wenn ich mir mal die Adressen von map1 ausgeben lasse, einmal in der Klasse GameLogic, dann vor dem Getter in der Klasse ConsoleOutput und einmal nach dem Getter kommt folgendes raus:

[[Lde.hagbard.tictactoe.EMap;@b4c966a
[[Lde.hagbard.tictactoe.EMap;@7cc355be
[[Lde.hagbard.tictactoe.EMap;@6e8cf4c6
 
Zuletzt bearbeitet:
Du darfst in ConsoleOutput nicht alles neu erstellen. Vielmehr musst Du z. B. die GameLogic-Instanz dem Konstruktor von ConsoleOutput einfach mitgeben und in einer Instanzvariablen speichern. Danach kannst Du in output() diese Instanz verwenden.
 
Also das heißt ich mach folgendes:

ConsoleOutput co = new ConsoleOutput(map1);

Und


EMap map1;
public ConsoleOutput(EMap map1) { this.map1=map1;
}
 
Zuletzt bearbeitet:
Also das heißt ich mach folgendes:

ConsoleOutput co = new ConsoleOutput(map1);

Und


EMap map1;
public ConsoleOutput(EMap map1) { this.map1=map1;
}
Eher etwas wie ConsoleOutput co = new ConsoleOutput(gl); mit public ConsoleOutput(GameLogic logic)

Du solltes übrigens nicht davor zurückscheuen Variablenbezeichner auszuschreiben, also consoleOutput und gameLogic anstatt co und gl. Abkürzungen lassen sich in der Regel nicht so gut lesen und irgendwann blickst du nicht mehr durch.
 
Damit wir uns richtig verstehen, ich erstelle in der Main Methode eine Instanz der Klasse GameLogic
Java:
GameLogic gl = new Gamelogic();
(Bleiben wir für den Beispiel Fall mal bei gl)
Und in der Main Methode erstelle ich eine Instanz der Klasse ConsoleOutput und übergebe dem Konstruktor gl
Java:
ConsoleOutput co = new ConsoleOutput(gl);


Der Konstruktor sieht dann so aus:

Java:
public ConsoleOutput(GameLogic logic){
}

Ist das so korrekt?
Kann ich es auch so machen, dass die Klasse ConsoleOutput von der Klasse GameLogic erbt oder ist das komplett Käse?
 
Also deklariere ich die Instanzvariable z.b so:
EMap map1=logic;
Nein.

Java:
public class ConsoleOutput {
    private GameLogic logic;

    public ConsoleOutput(GameLogic logic) {
        this.logic = logic; // mit Parameter logic übergebene Referenz in Instanzvariable this.logic speichern. 
        // das this ist hier nur notwendig, weil Parameter und Instanzvariable den gleichen Namen haben
    }

    public void output() {
        EMap map = logic.getMap1();  // hier Instanzvariable logic verwenden, um eine "Karte" abzurufen.
        for (int j = 0; j < 3; j++) {   //Ausgabe des Spielfeldes    UNFERTIG
            for (int i = 0; i < 3; i++) {
                System.out.println(map[j][i]);
            }
        }
    }
    public void choosePlayer(){
        System.out.println("Möchten Sie Spieler X oder Spieler O sein?");
    }
}
 
Vielen Dank für die Hilfe, so hat es jetzt funktioniert.
Aber rein von Meinem Verständniss her, würde ich es gerne nochmal für mich erklären. Ich hoffe ich liege damit richtig.

Mein ursprünglicher Fehler war, dass ich in der Klasse ConsoleOutput eine neue Instanz der Klasse GameLogic erstellt habe, welche wiederrum ein neues Spielfeld angelegt hat.
Vorher allerdings hat schon die Main Methode eine Instanz der Klasse GameLogic erstellt und somit auch das Spielfeld.
 
Vielen Dank für die Hilfe, so hat es jetzt funktioniert.
Aber rein von Meinem Verständniss her, würde ich es gerne nochmal für mich erklären. Ich hoffe ich liege damit richtig.

Mein ursprünglicher Fehler war, dass ich in der Klasse ConsoleOutput eine neue Instanz der Klasse GameLogic erstellt habe, welche wiederrum ein neues Spielfeld angelegt hat.
Vorher allerdings hat schon die Main Methode eine Instanz der Klasse GameLogic erstellt und somit auch das Spielfeld.
Ja, du hattest dann zweimal Spielfeld und GameLogic, die beide völlig unabhängig voneinander existiert haben.
 
Vielen Dank, also mit diesem Forum kann man echt viel Lernen.
Das ist ganz gut wenn ich mir jetzt schon so viele Grundkentnisse wie möglich aneigne, im August geht meine Ausbildung los 🙂
 

Zurück
Oben