Ampel-Simulation

Bitte aktiviere JavaScript!
Hallo,
ich will die Schaltung einer Ampel simulieren:
Java:
public class Ampel{
    
    
    private boolean rot;
    private boolean gelb;
    private boolean grün;
    
    
    Ampel(){
        rot=true;
    }
    
     public void schalten(){
        
        if(rot){
             gelb=true;
            
            return;
        }
        
        if(rot &&  gelb){
            rot=false;
            gelb=false;
            grün=true;
            return;
        }
        if(grün){
            
            gelb=true;
            grün=false;
            return;
        }
    
        if(gelb){
            rot=true;
            gelb=false;
            
            return;
        }   
    }
    
    public String toString(){
    
        
         if(rot)  return "rot";
         else if((rot) && ( gelb)) return "rotgelb";
         else if(grün) return " grün";
         else return "gelb";
    }
}

Wenn ich dann folgenden Test durchführe:
Java:
class Main {

    public static void main(String[] args) {
        
        Ampel test=new Ampel();
        
        System.out.println(test);
        
        test.schalten();
        System.out.println(test);
        
    }
}
..., dann wird aber nur rot ausgeben.
Wo liegt denn der Fehler in meiner Methode?
 
A

Anzeige




Schau mal hier —> (hier klicken)
Durch das erste Schalten wird ja gelb auf true gesetzt. Somit ist jetzt gelb und rot auf true. Deine toString() Methode prüft aber erstmal nur per `if(rot) return "rot";`, ob rot=true ist und steigt dann sofort mit return "rot" aus.
Ändere es vielleicht auf:
Java:
public String toString(){
  if (rot && gelb) return "rotgelb";
  else if (rot) return "rot";
  else if (grün) return "grün";
  return "gelb";
}
 
Dasselbe Problem mit der Reihenfolge der if-Abfragen hast du auch in schalten(). Da fragst du ja auch zuerst nur ab, ob rot=true ist und setzt dann gelb auf true und beendest sofort die Methode.
Generell würde ich die Schaltungslogik anders implementieren. Eher so:
Java:
public class Ampel {
  private static final boolean[][] programm = {
      /* rot, gelb, grün */
      { true, false, false },
      { true, true, false },
      { false, false, true },
      { false, true, false }
  };

  private boolean rot;
  private boolean gelb;
  private boolean grün;
  private int phase;

  public Ampel() {
    setzeSignale();
  }

  private void setzeSignale() {
    boolean[] signale = programm[phase];
    this.rot = signale[0];
    this.gelb = signale[1];
    this.grün = signale[2];
  }

  public void schalten() {
    phase = (phase + 1) % 4;
    setzeSignale();
  }

  public String toString() {
    if (rot && gelb)
      return "rotgelb";
    else if (rot)
      return "rot";
    else if (grün)
      return "grün";
    return "gelb";
  }
}
 
Danke für deinen Vorschlag. Wenn ich aber bei meiner Programmstruktur bleiben will, sollte ich dann nicht den Fall rot ganz zum Schluss behandeln?
 
Wenn du mehrere Bedingungen hast, und diese Bedingungen Teilmengen voneinander sind (das heißt, `a` ist Teilmenge von `b`, wenn gilt: a => b, also aus `a` folgt `b`), dann musst du die stärkste Bedingung zuerst abfragen. Also (rot && gelb) ist stärker als (rot), ist aber auch Teilmenge von (rot), denn es gilt (rot && gelb) => (rot). Somit musst du (rot && gelb) zuerst abfragen.
Wenn die Bedingungen unabhängig voneinander sind, wie es ja bei (rot), (gelb) und (grün) der Fall ist, dann ist die Reihenfolge egal, weil ja niemals zwei der drei Bedingungen gleichzeitig auftreten können.
 
Ich würde allerdings davon abraten, über die Stärke der Bedingung zu gehen, da damit die Abfragen abhängig von der Ausführungsreihenfolge werden.

Entweder die if-Abfragen verschachteln oder explizit abfragen. Letzteres halte ich für die geeignetste Variante, denn es handelt sich beim Fall "Rot" und "Rot-Gelb" tatsächlich um zwei verschiedene, voneinander unabhängige Fälle, die nur zufällig das Rot gemeinsam haben. Klar wird es, wenn man andere Bezeichnungen für die Fälle einführt, z. B. Stop, Bereit , Fahren, da tritt das Problem erst gar nicht auf.
 
Mit abhängig/unabhängig und aus a folgt b, meinte ich die reine Aussagenlogik. Denn die Variable/Bedingung rot=true ist nunmal auch in der Bedingung rot=true && gelb=true enthalten.
Aber ich stimme dir zu, dass alles andere besser ist als wie es aktuell umgesetzt ist. :)
 
In einer echten Ampel, sieht es ungefähr so aus:
Java:
public class SqlToTable {

    private int i;
    private String[] s = {"grün", "gelb", "rot", "rot-gelb"};

    public void iS() {
        i = (i + 1) % 4;
    }

    public String cS() {
        return s[i];
    }

    public String nS() {
        iS();
        return cS();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        SqlToTable stt = new SqlToTable();
        for (int i = 0; i <= 11; i++) {
            System.out.println(i + " " + stt.nS());
        }
    }

}
(Nich verwunderlich sein, SqlToTable soll eigentlich Ampel sein)
 
Ok, es passte eher in die Plauderecke... aber sobald andere Personen, Tiere, Verkehrsteilnehmer... auf der Fahrbahn sind oder eine Ampel nicht läuft, ist ohnehin erhöhte Vorsicht geboten.
 
Wobei eine Ampel auch schnell als State-Machine via Enum abgebildet werden kann. Etwa so:

Java:
enum TrafficLightState {
    INITIAL(false, true, false, true) {
        @Override
        public TrafficLightState nextState() {
            return RED;
        }
    },
    RED(true, false, false, false) {
        @Override
        public TrafficLightState nextState() {
            return REDYELLOW;
        }
    },
    REDYELLOW(true, true, false, false) {
        @Override
        public TrafficLightState nextState() {
            return GREEN;
        }
    },
    GREEN(false, false, true, false) {
        @Override
        public TrafficLightState nextState() {
            return YELLOW;
        }
    },
    YELLOW(false, true, false, false) {
        @Override
        public TrafficLightState nextState() {
            return RED;
        }
    };

    private boolean red, yellow, green, blinking;

    private TrafficLightState(boolean red, boolean yellow, boolean green, boolean blinking) {
            this.red = red;
            this.yellow = yellow;
            this.green = green;
            this.blinking = blinking;
    }

    public abstract TrafficLightState nextState();
   
    public String toString() {
        String s = this.name() + ": ";
        s += (red ? "R" : ".");
        s += (yellow ? "Y" : ".");
        s += (green ? "G" : ".") + " ";
        s += (blinking ? "(blinking)" : "(permanent)");
       
        return s;
    }
   
    public static void main(String... args) {
        TrafficLightState state = INITIAL;
        System.out.println(state);
       
        for(int i = 0; i < 100; i++) {
            System.out.println(state = state.nextState());
        }
    }
}
 
Zuletzt bearbeitet:
Ich habe es mir nochmal durch den Kopf gehen lassen und meine Lösung ist leider zu sehr vom konkreten Zustand abhängig. Vielen Dank für euere Vorschläge:)
 
Gab es nicht mal ein Entwurfsmuster, um solche Zustandsautomaten umzusetzen? Eigentlich ein perfektes Beispiel um das mal zu üben.
 
Unser Tutor hat uns auch die gleiche Übung gestellt, daher weiß ich das noch ... Es war aber keine Simulation - wir mussten eine echte Ampel in klein aufbauen. o_O
Ich lehne mich mal etwas aus dem Fenster: Ein (Ampel)-Automat mit nur 3 Zuständen kann nicht durch eine >Typ-1-Grammatik beschrieben werden.
 
A

Anzeige




Vielleicht hilft dir das hier weiter: (klicke hier)
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben