TicTacToe - probleme beim Casten

tom.j85

Mitglied
Hallo liebe Community,

habe zu diesem Thema nichts gefunden, wahrscheinlich ist die Lösung einfach...Es geht um TicTacToe (Käsekästchen) in der Konsole. Ich will ein Feld erstellen, das aus einem einzigen char Array besteht. Ich möchte, dass der index des Arrays +1 ein char wird, der dann ausgegeben werden kann. Beim Casten von int zu char geht aber etwas schief: Es kommen bei mir in der Konsole nur eine Zweier und zwei Dreierreihen von Fragezeichen raus. Vielleicht ein Softwareproblem (ich habe Eclipse IDE for Enterprise Java Developers - 2019-12, Java 8 auf Windows 10. Mehr Details gerne auf Anfrage).
Wahrscheinlich aber doch ein Denkfehler. Der Code:

Java:
public class Main {
    public static void main(String[] args) {

        PlayingField field = new PlayingField();
        System.out.println();
        field.showField();

    }
}

class PlayingField {

    char[] field;

    public PlayingField() {
        this.field = createField();
    }

    public char[] createField() {

        char[] field = new char[9];
        int counter = 0;
        for (int i = 0; i < 9; i++) {

            field[i] = (char) counter++;

        }
        return field;

    }

    public void showField() {

        for (int i = 0; i < field.length; i++) {
            if (i % 3 == 0) {
                System.out.println();
            }
            System.out.print(field[i]);
        }

    }

}

Vielen Dank!
 
Ein char kann man zu einem int casten (und umgedreht). Dabei wird aus dem Zeichen aber natürlich ein Wert, der diesem Zeichen entspricht. Diesbezüglich willst Du Dir im Netz evtl. einmal eine ASCII Tabelle ansehen. (Da wird aber nicht ASCII sondern UTF-16 verwendet. Daher auch die genau 4 bytes: Viele Zeichen werden mit 2 Bytes dargestellt aber das reichte nicht, daher gibt es auch Zeichen, für die 4 Bytes benötigt werden.)

Das Zeichen '1' ist somit nicht 1 sondern 49.

Wenn Du da also die Zahlen von 0 bis 9 im Array haben willst, dann kannst Du
a) Einfach Zahlen speichern! Denn das ist ja, was Du eigentlich speichern willst. Bei der Anzeige wird das dann z.B. in einen String umgewandelt. Oder
b) Wenn Du da ein Zeichen abspeichern willst, dann könntest Du z.B. '0' + i rechnen.

Wäre auch ein Hinweis zu Deinem Code: Wozu counter? counter wird wie i immer um 1 erhöht. Somit ist Deine Schleife überkompliziert. Aus
Java:
    public char[] createField() {
        char[] field = new char[9];
        int counter = 0;
        for (int i = 0; i < 9; i++) {
            field[i] = (char) counter++;
        }
        return field;
    }
macht man dann besser ein:
Java:
    public char[] createField() {
        char[] field = new char[9];
        for (int counter = 0; counter < 9; counter++) {
            field[i] = (char) counter;
        }
        return field;
    }

Zumal meine Empfehlung für Anfänger auch immer wieder ist: (Pre-/Post-) Increment oder Decrement werden nur einzeln verwendet und nie innerhalb eines Statements! Also wenn dann statt field[i] = (char) counter++; ein

Java:
field[i] = (char) counter;
counter++;

Ansonsten kommt es leicht zu Verwirrungen, wann was ausgeführt wird. (Ist in Java alles klar geregelt und man sollte es kennen, aber verwenden würde ich es so nicht.)
 
Das ist eine super Antwort und eine sehr wertvolle Info für mich! Und vielen Dank ebenfalls für die Style Tipps. Der counter war dort tatsächlich nur, weil ich rumexperimentiert hatte und dachte es hätte etwas mit der Schleife zu tun haben können. Wenn etwas nicht funktioniert kommt man auf die verrücktesten Ideen.
Ich wollte außerdem Zeichen abspeichern, um dann in einer Methode playerSetsX() einfach auf den char[] zugreifen zu können und das jeweilige Käsekästchen Feld mit X oder O bestücken zu können. Für mich funktioniert jetzt:

Java:
public char[] createField() {

        char[] field = new char[9];
        
        for (int i = 0; i < 9; i++) {

            field[i] = (char)(i + 49);

        }
        return field;

Den Vorschlag
b) Wenn Du da ein Zeichen abspeichern willst, dann könntest Du z.B. '0' + i rechnen.
, verstehe ich allerdings nicht ganz. Wie könnte so ein Code aussehen? Vielen Dank!
 
Also der Cast zwischen char und int geht, weil eben doch ein char eigentlich ein integer ist.

Jetzt hast Du mit der 49 eine "magic mumber". Statt der Zahl kannst Du also einfach '0' schreiben. '0' ist dann hier einfach die 48.
(Und Du hast da dann auch nicht die Zahlen von 0-9 sondern von 1-10. Also das, was ich als i + '1' schreiben würde.)

Also einfach einmal ein Beispielcode:
Java:
    public static void main(String[]args){
        char test1 = '0' + 1;
        char test2 = 48 + 1;
        System.out.println("test1: " + test1);
        System.out.println("test2: " + test2);
        System.out.println("Equal?: " + (test1 == test2));
    }

Also test1 wäre ich es vorgeschlagen habe. test2 ist, wie Du es gemacht hast. Dass es gleich ist, siehst Du zum einen an der Ausgabe und zum anderen habe ich auch einfach mal die Gleichheit ausgegeben.

Der explizite cast ist übrigens nicht notwendig. Das macht Java implizit und das in beide Richtungen. Also ein int wird in ein char gecastet und umgekehrt wird der char in ein int gecastet. sowas ist also nicht notwendig:
Java:
    public static void main(String[]args){
        char test1 = (char)((int)'0' + 1);
        char test2 = (char)(48 + 1);
        System.out.println("test1: " + test1);
        System.out.println("test2: " + test2);
        System.out.println("Equal?: " + (test1 == test2));
    }

Und vielleicht wird es deutlicher, wenn man die Addition erst einmal ganz weglässt:
Java:
    public static void main(String[]args){
        char test1 = '0';
        char test2 = 48;
        System.out.println("test1: " + test1);
        System.out.println("test2: " + test2);
        System.out.println("Equal?: " + (test1 == test2));
    }
Das könnte man ebenso mit int machen:
Java:
    public static void main(String[]args){
        int test1 = '0';
        int test2 = 48;
        System.out.println("test1: " + test1);
        System.out.println("test2: " + test2);
        System.out.println("Equal?: " + (test1 == test2));
    }

Unterschied zwischen den beiden Codes ist natürlich die Ausgabe. Bei char wird '0' ausgegeben (also das Zeichen 0). Bei int wird die Zahl ausgegeben, also die 48.
 
Wenn etwas nicht funktioniert kommt man auf die verrücktesten Ideen.
Verzweiflungstaten 😛

, verstehe ich allerdings nicht ganz. Wie könnte so ein Code aussehen?
field[i] = (char)('0' + i);.

Mit '0' ist nicht der Wert 0 sondern das Zeichen 0 gemeint, das dem Wert 48 entspricht.

Der explizite cast ist übrigens nicht notwendig.
Das stimmt nicht ganz, da ein int 32-Bit und ein char nur 16-Bit groß ist. Dass das in den Beispielen funktioniert hängt damit zusammen, dass der Compiler anhand der Literale erkennt, dass der Wert passt. Sobald Du mit Variablen arbeitest, ist es vorbei.
 
Das stimmt nicht ganz, da ein int 32-Bit und ein char nur 16-Bit groß ist. Dass das in den Beispielen funktioniert hängt damit zusammen, dass der Compiler anhand der Literale erkennt, dass der Wert passt. Sobald Du mit Variablen arbeitest, ist es vorbei.

Oh ja, natürlich.

Frage mich gerade, wie ich da durcheinander gekommen bin. In #2 habe ich ja die 4 Byte erwähnt, die ein UTF-16 char ausmachen können - daher vielleicht. Aber die würden natürlich (ebenso wie z.B. auch in .Net/C#) in 2 chars dargestellt. (String.length gibt daher auch nur die Anzahl der chars in dem String zurück und nicht die Anzahl der Zeichen. Also ein Chinesisches (??) Zeichen, das 4 Bytes benötigt, würde dann 2 char Plätze belegen.

Habe da jetzt sogar mal nach einem Beispiel gesucht ... unter https://stackoverflow.com/questions/27287369/4-byte-unicode-character-in-java zeigt Andrew ein Beispiel das erst einmal ein Zeichen zeigt, aber der String hat die Länge 2.
 

Neue Themen


Zurück
Oben