Automat-Programmierung

FinnJ

Mitglied
Hallo,
erstmal hoffe ich, dass "Java Basics" das richtige Forum für meine Frage ist. Bitte darauf hinweisen, falls dem nicht so ist. Ich programmiere derzeit einen ganz simplen Automaten, der die Methode "zeichenkettePruefen" besitzt, welche für die Zeichenkette "10" true ausgeben soll und für alle anderen Zeichenketten false. Nach meiner Logik müsste der Automat auch funktionieren, da ich keinen Fehler finden kann und schon einiges ausprobiert habe (bin Anfänger, also wahrscheinlich gibt es da schon noch Dinge die ich probieren könnte).
Das ist mein Quellcode:

Java:
[/B]
public class AUTOMAT{
    int zustand;

    AUTOMAT(){
        zustand = 0;
        // System.out.println("Zeichenketten müssen exakt 2 Ziffern enthalten und aus 0 und 1 bestehen");
    }

    public boolean zeichenkettePruefen(String eingabe){
        // zustand = 0;

        for (int i = 0; i < eingabe.length(); i++){
            switch(zustand){
                case 0:
                    switch(eingabe.charAt(0)){
                        case '1':
                        zustand = 1;
                        break;
                        case '0':
                        zustand = 3;
                        break;
                }
               
                case 1:
                    switch(eingabe.charAt(0)){
                        case '1':
                        zustand = 3;
                        break;
                        case '0':
                        zustand = 2;
                        break;
                }
               
                case 2:
                    switch(eingabe.charAt(0)){
                        case '1':
                        zustand = 3;
                        break;
                        case '0':
                        zustand = 3;
                        break;
                }
               
                case 3:
                    switch(eingabe.charAt(0)){
                        case '1':
                        zustand = 3;
                        break;
                        case '0':
                        zustand = 3;
                        break;
                }
            }
            eingabe = eingabe.substring(1);
        }

        if (zustand == 2){
            return true;
        }
        else{
            return false;
        }
    }
}  
[B]

Vielen Dank schonmal im Vorraus!
FinnJ
 
Wenn der String nur aus zwei zeichnen bestehen kann. Dann prüfe das doch einfach mit einem if ob es genau „10“ ist.
Und nicht so kompliziert.
 
Bei dem äußeren Switch (also das Zustand-Switch) gibt es keine break; Anweisungen, deswegen führt er wahrscheinlich immer zu viel Code aus.
 
Bei dem äußeren Switch (also das Zustand-Switch) gibt es keine break; Anweisungen, deswegen führt er wahrscheinlich immer zu viel Code aus.
Da müsste ich also nach
Java:
case 0:
                    switch(eingabe.charAt(0)){
                        case '1':
                        zustand = 1;
                        break;
                        case '0':
                        zustand = 3;
                        break;
                }
jedes mal ein "break;" dazuschreiben? Werde ich direkt versuchen!

UPDATE:

Java:
public class AUTOMAT{
    int zustand;

    AUTOMAT(){
        zustand = 0;
        // System.out.println("Zeichenketten müssen exakt 2 Ziffern enthalten und aus 0 und 1 bestehen");
    }

    public boolean zeichenkettePruefen(String eingabe){
        // zustand = 0;

        for (int i = 0; i < eingabe.length(); i++){
            switch(zustand){
                case 0:
                switch(eingabe.charAt(0)){
                    case '1':
                    zustand = 1;
                    break;
                    case '0':
                    zustand = 3;
                    break;
                }
                break;
                case 1:
                switch(eingabe.charAt(0)){
                    case '1':
                    zustand = 3;
                    break;
                    case '0':
                    zustand = 2;
                    break;
                }
                break;
                case 2:
                switch(eingabe.charAt(0)){
                    case '1':
                    zustand = 3;
                    break;
                        case '0':
                        zustand = 3;
                        break;
                }
                break;
                case 3:
                    switch(eingabe.charAt(0)){
                        case '1':
                        zustand = 3;
                        break;
                        case '0':
                        zustand = 3;
                        break;
                }
                break;
            }
            eingabe = eingabe.substring(1);
        }

        if (eingabe == "10"){
                System.out.println("true");
            }
        else {
            System.out.println("false");
        }
        if (zustand == 2){
            return true;
        }
        else{
            return false;
        }
    }
}

Habe es jetzt so versucht, hat leider nicht geholfen :/ Es kann aber auch sein, dass ich das falsch verstanden habe ^^
 
Zuletzt bearbeitet:
Wenn der String nur aus zwei zeichnen bestehen kann. Dann prüfe das doch einfach mit einem if ob es genau „10“ ist.
Und nicht so kompliziert.
Stimmt, das könnte ich mal versuchen

UPDATE:
Java:
if (eingabe == "10"){
                return true;
            }
            else {
                return false;
            }

Es kommt wirklich "10" beim Programm an, denn ich habe den Code mal mit dieser if-Abfrage ersetzt um das zu überprüfen, leider weiß ich nicht genau wie ich das sonst überprüfen könnte, da ich ja durch das "charAt(0)" und das "substring(1)" die Zeichenkette kürze.
 
Zuletzt bearbeitet:
da gibt es ja nur 4 möglichkeiten
du willst und brauchst ja nur die eine
Ja, ich wollte nur kurz überprüfen, ob ich es schaffe einen Automaten zu programmieren, deshalb habe ich diese möglichst simple Anweisung eingefügt. Das wird vom Automaten ja auch nicht direkt verlangt nur ich wollte das nicht auch noch coden, dass der Automat nur derartige Zeichenketten annimmt und habe eher den "Hauptteil" des Programms testen wollen
 
Was genau macht dein Automat denn grade falsch? Gibt er das falsche Ergebnis aus oder kommt eine Exception?
Der Automat gibt mir gerade immer false aus, auch wenn ich "10" eingebe, er kommt irgendwie nie in den zustand 2 bzw. bleibt er dort nicht. Mir ist gerade eingefallen ist könnte das dokumentieren und nach jeder zustandsänderung mir mit System.out.println ausgeben lassen in welchen zustand er gewechselt ist. Werde ich nach dem Essen mal probieren und dann erzählen auf was für ein ergebnis ich kam.
 
Probier's mal mit dem debugger, anstatt irgendwelcher SysOut Ausgaben ... damit zu arbeiten üben kann man nicht früh genug beginnen
 
Ach, jetzt sehe ich das Problem. 🙂
Du machst am Ende der For-Schleife immer eingabe = eingabe.substring(1); und die For-Schleife überprüft Anhand der Länge, ob sie noch weiterlaufen soll oder fertig ist. Beim zweiten Durchlauf ist die Länge von eingabe dann 1 und die For-Schleife, die jetzt auch bei 1 ist, denkt, sie ist fertig.

PS: Ich glaube trotzdem noch, dass da die breaks fehlen.
 
Also bitte immer vernünftig einrücken! Die switch Anweisungen lassen sich so ja nur seh schwer lesen! Also am Besten eine IDE nutzen, die das direkt für dich erledigt. Der Code aus #5 sieht dann derzeit so aus:
Java:
    public boolean zeichenkettePruefen(String eingabe){
        // zustand = 0;

        for (int i = 0; i < eingabe.length(); i++){
            switch(zustand){
                case 0:
                    switch(eingabe.charAt(0)){
                        case '1':
                            zustand = 1;
                            break;
                        case '0':
                            zustand = 3;
                            break;
                    }
                    break;
                case 1:
                    switch(eingabe.charAt(0)){
                        case '1':
                            zustand = 3;
                            break;
                        case '0':
                            zustand = 2;
                            break;
                    }
                    break;
                case 2:
                    switch(eingabe.charAt(0)){
                        case '1':
                            zustand = 3;
                            break;
                        case '0':
                            zustand = 3;
                            break;
                    }
                    break;
                case 3:
                    switch(eingabe.charAt(0)){
                        case '1':
                            zustand = 3;
                            break;
                        case '0':
                            zustand = 3;
                            break;
                    }
                    break;
            }
            eingabe = eingabe.substring(1);
        }

        if (eingabe == "10"){
            System.out.println("true");
        }
        else {
            System.out.println("false");
        }
        if (zustand == 2){
            return true;
        }
        else{
            return false;
        }
    }
 
Und damit sieht man dann besser: die fehlenden break sind da. Aber das if Statement ist so natürlich Unsinn:
Code:
eingabe == "10"
wird immer false sein. Strings vergelicht man mit equals und nicht mit ==.

Mit == würde nur die Referez verglichen und nicht der Inhalt.

Edit: Das "immer falsch" muss man evtl, konkretisieren. Es ist natürlich nicht falsch, wenn die Referenz gleich ist. Das wäre z.B. der fall, wenn eingabe auch das String Literal "10" enthält oder es (per String.intern) ein String im String Pool wäre. Aber wenn eingabe ein Ergebnis aus substring oder einer User Eingabe ist, dann ist dies nicht der Fall!
 
Zuletzt bearbeitet:
Du versuchst ja eigentlich deine Duale Zahl als String in Dezimal zu wandeln.
Eine „00“ sollte ein „zustand“ = 0 ergeben was es zb. nicht tunt.

Schaue noch mal nach wie man Duale Zahlen in Dezimal umformt-
 
Du versuchst ja eigentlich deine Duale Zahl als String in Dezimal zu wandeln.
Wo erkennst Du das am Automat?

Der Automat hat einen Endstatus 3, zu dem fast alle Wege führen.

Einzige Ausnahmen sind:
"1" -> Status 1
"10" -> Status 2

Der ganze Automat prüft aber am Ende nur ein Status 2 oder nicht, so dass es auf ein eingabe.equals("10") hinaus läuft. Die 10 ist im dualen Sytsem der Wert 2, aber dennochist das keine Umwandlung von Zahlen, denn die "0" ist keine 3 oder die "111" ist keine 3 oder die "1111111111" ist keine 3. Der Zustand ist also nicht der Wert des Strings als duale Zahl. Das trifft nur durch Zufall für die Zustände 1 und 2 zu.
 
Der ganze Automat prüft aber am Ende nur ein Status 2 oder nicht, so dass es auf ein eingabe.equals("10") hinaus läuft. Die 10 ist im dualen Sytsem der Wert 2, aber dennochist das keine Umwandlung von Zahlen, denn die "0" ist keine 3 oder die "111" ist keine 3 oder die "1111111111" ist keine 3. Der Zustand ist also nicht der Wert des Strings als duale Zahl. Das trifft nur durch Zufall für die Zustände 1 und 2 zu.
das ist klar. er wird das aber versucht haben, und hoffte das es so geht mit dem Umwandeln.
sonst hätte er nicht genau 4 erste Cases, und würde am ende nicht auf 2 "10" prüfen.

das der code das nicht macht ist klar.

if (zustand == 2){
 
if (eingabe == "10"){
System.out.println("true");
}
//Strings vergleicht man mit equals nicht mit ==

if (eingabe.equals("10")){
 
Zuletzt bearbeitet:
Aber der Automat funktioniert immer noch nicht. Das Problem ist auch relativ einfach zu erkennen. Das Erkennen wir nur erschwert, da der Code einfach viel zu groß und unübersichtlich ist. Daher mein genereller Tipp:
a) Aufschreiben des Algorithmus
b) Umsetzen des Algorithmus

Dabei:
a) gute Namen verwenden für alle Bezeichner!
b) Keine "magic Numbers" verwenden.

Bei dir ist das große Problem, dass Du die 0 als Magic Number hast und diese an einer Stelle auftaucht, bei der Du dann etwas machst, dass Du nicht machen willst: eingabe.charAt(0)

er wird das aber versucht haben
Das sehe ich nicht so. Es geht einfach nur um einen Automat, der bei der Eingabe von "10" true zurück geben soll:
welche für die Zeichenkette "10" true ausgeben soll

Daher halte ich das für weiter hergoholt. Dass die Zeichenkette "10" in einem Zustand 2 landet, ist dabei zufall und schlicht Ergebnis eines schlecht benannten Zustandes. (Die würde ich halt auch ordentlich benennen).
 
Also bitte immer vernünftig einrücken! Die switch Anweisungen lassen sich so ja nur seh schwer lesen! Also am Besten eine IDE nutzen, die das direkt für dich erledigt. Der Code aus #5 sieht dann derzeit so aus:
Java:
    public boolean zeichenkettePruefen(String eingabe){
        // zustand = 0;

        for (int i = 0; i < eingabe.length(); i++){
            switch(zustand){
                case 0:
                    switch(eingabe.charAt(0)){
                        case '1':
                            zustand = 1;
                            break;
                        case '0':
                            zustand = 3;
                            break;
                    }
                    break;
                case 1:
                    switch(eingabe.charAt(0)){
                        case '1':
                            zustand = 3;
                            break;
                        case '0':
                            zustand = 2;
                            break;
                    }
                    break;
                case 2:
                    switch(eingabe.charAt(0)){
                        case '1':
                            zustand = 3;
                            break;
                        case '0':
                            zustand = 3;
                            break;
                    }
                    break;
                case 3:
                    switch(eingabe.charAt(0)){
                        case '1':
                            zustand = 3;
                            break;
                        case '0':
                            zustand = 3;
                            break;
                    }
                    break;
            }
            eingabe = eingabe.substring(1);
        }

        if (eingabe == "10"){
            System.out.println("true");
        }
        else {
            System.out.println("false");
        }
        if (zustand == 2){
            return true;
        }
        else{
            return false;
        }
    }
Habe ich immer wieder gemacht, leider rückt BlueJ sobald ich das "Automatisch Einrücke" das alles sehr unschön ein. :/
 
@FinnJ
erkläre uns doch mal deinen Algorithmus den du machen wolltest.
In kurzen Worten
Der Algorhytmus sollte letztendlich nur überprüfen, ob ich "10" eingebe oder eine andere Zahl. Nur bei der Eingabe "10" sollte er true zurückgeben, ansonsten false. Sollte einfach nur ein Versuch sein einen extrem simplen Automaten zu erstellen, damit ich mich da bisschen "reinfinde".
 
Habe ich immer wieder gemacht, leider rückt BlueJ sobald ich das "Automatisch Einrücke" das alles sehr unschön ein. :/
Ach je - mit BlueJ kenne ich mich nicht aus, ob man das evtl. bsser konfiguriren kann. Eine andere IDE ist nicht verwendbar (IntelliJ, Eclipse, Netbeans)?

Aber das sind nur Nebenschauplätze, so wie dein if zur Kontrolle, das immer false ausgegeben hat.

Das Problem war zuerst, dass er im Switch "durchgefallen" ist. Ohne break führt er den nächsten Abschnitt halt auch aus.
Und dann, dass Du immer nur das erste Zeichen auswertest und nicht das Zeichen, an dessen Stelle Du gerade mit der While-Schleife warst.

Aber diese Nebenschauplätze sind wichtig. Ich würde da ggf. sogar viel mehr Unterteilen und dabei die Namen ordentlich wählen. Ich kann mal eben ein kleines Refactoring machen um Dir das aufzuzeigen, wie es dann besser aussehen könnte. Wichtig ist: Die Fehler hast Du beide verstanden?
 
Ach, jetzt sehe ich das Problem. 🙂
Du machst am Ende der For-Schleife immer eingabe = eingabe.substring(1); und die For-Schleife überprüft Anhand der Länge, ob sie noch weiterlaufen soll oder fertig ist. Beim zweiten Durchlauf ist die Länge von eingabe dann 1 und die For-Schleife, die jetzt auch bei 1 ist, denkt, sie ist fertig.

PS: Ich glaube trotzdem noch, dass da die breaks fehlen.
Da fühl ich mich jetzt bisschen blöd. Daran lags tatsächlich😂 Jetzt funktioniert der Automat einwandfrei
Vielen Dank für eure Hilfe! Euch noch einen schönen Tag
 
Der Algorhytmus sollte letztendlich nur überprüfen, ob ich "10" eingebe oder eine andere Zahl. Nur bei der Eingabe "10" sollte er true zurückgeben, ansonsten false. Sollte einfach nur ein Versuch sein einen extrem simplen Automaten zu erstellen, damit ich mich da bisschen "reinfinde".
Code:
public boolean zeichenkettePruefen(String eingabe){
    
if (eingabe.equals("10")){
     
             return true;
        }
        else{
            return false;
        }
    }
        }

würde da reichen.
 
Ach je - mit BlueJ kenne ich mich nicht aus, ob man das evtl. bsser konfiguriren kann. Eine andere IDE ist nicht verwendbar (IntelliJ, Eclipse, Netbeans)?

Aber das sind nur Nebenschauplätze, so wie dein if zur Kontrolle, das immer false ausgegeben hat.

Das Problem war zuerst, dass er im Switch "durchgefallen" ist. Ohne break führt er den nächsten Abschnitt halt auch aus.
Und dann, dass Du immer nur das erste Zeichen auswertest und nicht das Zeichen, an dessen Stelle Du gerade mit der While-Schleife warst.

Aber diese Nebenschauplätze sind wichtig. Ich würde da ggf. sogar viel mehr Unterteilen und dabei die Namen ordentlich wählen. Ich kann mal eben ein kleines Refactoring machen um Dir das aufzuzeigen, wie es dann besser aussehen könnte. Wichtig ist: Die Fehler hast Du beide verstanden?
BlueJ haben wir leider in der Schule immer verwendet.. bin auch kein großer Fan davon aber jetzt kurz vorm Abi will ich mir nicht mehr IntelliJ z.B. aneignen weil das ja doch ein paar Unterschiede aufweist.

Ja, habe beide Probleme verstanden! Vielen Dank für die hilfreichen Antworten und noch einen schönen Tag
 
Code:
public boolean zeichenkettePruefen(String eingabe){
   
if (eingabe.equals("10")){
    
             return true;
        }
        else{
            return false;
        }
    }
        }

würde da reichen.
Stimmt, aber ich wollte das als Automat ausführen, weil ich die Theorie eines Automaten verstehen und lernen will, da im Abitur teilweise Aufagben dazu drankommen und ich diese switch-Methode davor nicht wirklich verstanden habe.
 
Da fühl ich mich jetzt bisschen blöd. Daran lags tatsächlich😂 Jetzt funktioniert der Automat einwandfrei
Vielen Dank für eure Hilfe! Euch noch einen schönen Tag
Ach, die Logik war bei Dir, dass Du das erste Zeichen immer weggeommen hast. Statt der ständigen Veränderung der Eingabe hättest Du immer den Index nehmen können. Das ist aus meiner Sicht eher die übliche Vorgehensweise, da Du so weniger verändern musst.

Der versprochene strukturierte Aufbau, wie ich ihn wählen würde (in einem ersten Schritt) wäre sowas:
Java:
/**
 * Automat zur Prüfung der Zeichenkette "10".
 */
public class ZeichenkettePrüfenAutomat {

    public static final char TOKEN_ZERO = '0';
    public static final char TOKEN_ONE = '1';

    private enum State { START, FIRST_CHAR_VALID, VALID, INVALID}

    State state = State.START;

    
    public boolean checkString(String input) {

        for (int index = 0; index < input.length(); index++) {
            handleToken(input.charAt(index));
        }

        return state == State.VALID;
    }

    private void handleToken(char token) {
        switch (state) {

            case START:
                handleTokenAtSTART(token);
                break;

            case FIRST_CHAR_VALID:
                handleTokenAtVALID(token);
                break;

            case VALID:
                handleTokenAtVALID(token);
                break;

            case 3:
                handleTokenAtINVALID(token);
                break;
        }
    }

    private void handleTokenAtSTART(char token) {
        switch (token) {
            case TOKEN_ONE:
                state = State.FIRST_CHAR_VALID;
                break;
            case TOKEN_ZERO:
                state = State.INVALID;
                break;
        }
    }

    private void handleTokenAtFIRST_CHAR_VALID(char token) {
        switch (token) {
            case TOKEN_ONE:
                state = State.INVALID;
                break;
            case TOKEN_ZERO:
                state = State.VALID;
                break;
        }
    }

    private void handleTokenAtVALID(char token) {
        state = State.INVALID;
    }

    private void handleTokenAtINVALID(char token) {
    }

}

Hier hast Du halt eher leicht überschaubare Methoden. Wobei das ein Zwischenschritt der Umstellung wäre. Die ganzen private Methoden sind ein Zeichen, dass es ein Verhalten ist, das eigentlich nicht in die Klasse des Automaten gehört sondern ja ein Verhalten der Zustände ist. Daher würde das noch in die Enum State wandern.

Das Vorgehen ohne die Veränderung der Eingabe hat dabei vor allem den Grund, dass man dann vieles funktional und mit Streams lösen kann. Dadurch wird der Code dann am Ende nochmal deutlich kürzer und übersichtlicher.

==> Da Dich aber in erster Linie nur eine einfache Umsetzung eines Automaten interessiert würde ich da aber tatsächlich weitere Umstellungen als unnötig ansehen. Die Methoden halte ich aber durchaus für wichtig für einen besseren Überblick.
 
Ach, die Logik war bei Dir, dass Du das erste Zeichen immer weggeommen hast. Statt der ständigen Veränderung der Eingabe hättest Du immer den Index nehmen können. Das ist aus meiner Sicht eher die übliche Vorgehensweise, da Du so weniger verändern musst.

Der versprochene strukturierte Aufbau, wie ich ihn wählen würde (in einem ersten Schritt) wäre sowas:
Java:
/**
 * Automat zur Prüfung der Zeichenkette "10".
 */
public class ZeichenkettePrüfenAutomat {

    public static final char TOKEN_ZERO = '0';
    public static final char TOKEN_ONE = '1';

    private enum State { START, FIRST_CHAR_VALID, VALID, INVALID}

    State state = State.START;

   
    public boolean checkString(String input) {

        for (int index = 0; index < input.length(); index++) {
            handleToken(input.charAt(index));
        }

        return state == State.VALID;
    }

    private void handleToken(char token) {
        switch (state) {

            case START:
                handleTokenAtSTART(token);
                break;

            case FIRST_CHAR_VALID:
                handleTokenAtVALID(token);
                break;

            case VALID:
                handleTokenAtVALID(token);
                break;

            case 3:
                handleTokenAtINVALID(token);
                break;
        }
    }

    private void handleTokenAtSTART(char token) {
        switch (token) {
            case TOKEN_ONE:
                state = State.FIRST_CHAR_VALID;
                break;
            case TOKEN_ZERO:
                state = State.INVALID;
                break;
        }
    }

    private void handleTokenAtFIRST_CHAR_VALID(char token) {
        switch (token) {
            case TOKEN_ONE:
                state = State.INVALID;
                break;
            case TOKEN_ZERO:
                state = State.VALID;
                break;
        }
    }

    private void handleTokenAtVALID(char token) {
        state = State.INVALID;
    }

    private void handleTokenAtINVALID(char token) {
    }

}

Hier hast Du halt eher leicht überschaubare Methoden. Wobei das ein Zwischenschritt der Umstellung wäre. Die ganzen private Methoden sind ein Zeichen, dass es ein Verhalten ist, das eigentlich nicht in die Klasse des Automaten gehört sondern ja ein Verhalten der Zustände ist. Daher würde das noch in die Enum State wandern.

Das Vorgehen ohne die Veränderung der Eingabe hat dabei vor allem den Grund, dass man dann vieles funktional und mit Streams lösen kann. Dadurch wird der Code dann am Ende nochmal deutlich kürzer und übersichtlicher.

==> Da Dich aber in erster Linie nur eine einfache Umsetzung eines Automaten interessiert würde ich da aber tatsächlich weitere Umstellungen als unnötig ansehen. Die Methoden halte ich aber durchaus für wichtig für einen besseren Überblick.
Vielen Dank für die Mühe! Leider bin ich noch nicht so "tief in der Materie" drin, wodurch mir beispielsweise "enum state" nicht geläufig ist. Ansonsten ist der Code selbst für mich allerdings wirklich sehr übersichtlich, ich werden ihn mir als Vorlage nehmen.
 

Zurück
Oben