Entwickler-Ecke

Sonstiges (Delphi) - Getränkeautomat


Lazarusboy - Mo 30.05.11 19:07
Titel: Getränkeautomat
Hallo Leute,
Ich sollte einen getränke Automaten konstruieren, so dass er es einen 50 Cent, 1Euro, Cola, Fanta, Limo und Korrektur Button gibt
Die Getränke kosten alle 1,50€
Wenn der Benutzer zu viel einwirft wird es unten wiedeer hinausgeschmissen ....
Mein Problem, sobald ich auf den 0,50 Euro Button klicke, sagt er mir ich habe 1,50 Euro in der Machine und 0,50 wieder unten raus: SO siehts aus:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
procedure TForm1.Automat (var Zustand:char; Eingabe:char);
begin
EAusgabe.text:=' ';
case Zustand of
'-'case Eingabe of
'F'begin
Ebereit.text:= '0,50 Euro';
Zustand:='F';
end;
'E'begin
EBereit.text:= '1,00 Euro';
Zustand:= 'E';
end;
'C'begin
EAusgabe.text:= ' zu wenig Geld';
Zustand:='-';
end;
'W'begin
EAusgabe.text:= ' zu wenig Geld';
Zustand:='-';
end;
'L'begin
EAusgabe.text:= ' zu wenig Geld';
Zustand:='-';
end;
'K'begin
EAusgabe.text:=' kein Geld';
Zustand:='-';
end;
end;
end;
Case Zustand of
'F'case Eingabe of
'F':begin
Ebereit.text:='1,00 Euro';
Zustand:='E';
end;
'E'begin
EBereit.text:='1,50 Euro';
Zustand:='G';
end;
'C'begin
Ebereit.text:='0,50 Euro';
EAusgabe.text:= ' zu wenig Geld';
Zustand:='F';
end;
'W'begin
Ebereit.text:='0,50 Euro';
EAusgabe.text:= ' zu wenig Geld';
Zustand:='F';
end;
'L'begin
Ebereit.text:='0,50 Euro';
EAusgabe.text:= ' zu wenig Geld';
Zustand:='F';
end;
'K':begin
Ebereit.text:='Bereit';
EAusgabe.text:='0,50 Euro Back';
Zustand:='-';
end;
end;
end;
Case Zustand of
'E'case Eingabe of
'F'begin
EBereit.text:='1,50 Euro';
Zustand:='G';
end;
'E'begin
EBereit.text:= '1,00 Euro';
Zustand:='E';
EAusgabe.text:='1,00 Euro back';
end;
'C'begin
Ebereit.text:='1,00 Euro';
EAusgabe.text:= ' zu wenig Geld';
Zustand:='E';
end;
'W'begin
Ebereit.text:='1,00 Euro';
EAusgabe.text:= ' zu wenig Geld';
Zustand:='E';
end;
'L'begin
Ebereit.text:='1,00 Euro';
EAusgabe.text:= ' zu wenig Geld';
Zustand:='E';
end;
'K':begin
Ebereit.text:='Bereit';
EAusgabe.text:='1,00 Euro back';
Zustand:='-';
end;
end;
end;
Case Zustand of
'G'case Eingabe of
'F'begin
EBereit.text:='1,50 Euro';
EAusgabe.text:='0,50 Euro back';
Zustand:='G';
end;
'E'begin
EBereit.text:='1,50 Euro';
EAusgabe.text:='1,00 Euro back';
Zustand:='G';
end;
'C'begin
Ebereit.text:='Bereit';
EAusgabe.text:= 'Cola';
Zustand:='-';
end;
'W'begin
Ebereit.text:='Bereit';
EAusgabe.text:= 'Fanta';
Zustand:='-';
end;
'L'begin
Ebereit.text:='Bereit';
EAusgabe.text:= 'Limo';
Zustand:='-';
end;
'K':begin
Ebereit.text:='Bereit';
EAusgabe.text:='1,50 Euro back';
Zustand:='-';
end;
end;
end;




end;



procedure TForm1.FormCreate(Sender: TObject);
begin
  Zustand:='-';
end;

procedure TForm1.BKorrekturClick(Sender: TObject);
begin
  Automat(Zustand,'K');
end;

procedure TForm1.B50centClick(Sender: TObject);
begin
Automat(Zustand,'F');
end;

procedure TForm1.B1EuroClick(Sender: TObject);
begin
  Automat(Zustand,'E');
end;

procedure TForm1.BColaClick(Sender: TObject);
begin
  Automat(Zustand,'C');
end;

procedure TForm1.BLimoClick(Sender: TObject);
begin
  Automat(Zustand,'L');
end;

procedure TForm1.BFantaClick(Sender: TObject);
begin
  Automat(Zustand,'W');
end;


HenryHux - Mo 30.05.11 19:16

Kein Wunder, dass dabei Fehler passieren, ist ja nicht besonders einfach da durchzublicken.
Überleg dir am besten mal wie du das mit weniger Code erledigen kannst.
Du könntest eine Variable für den aktuellen Geldstand haben, die sich erhöht wenn man auf ein Geldknopf drückt.
Wenn man dann auf ein Getränk klickt, übergibst du den Preis des Getränkes an eine Prozedur, die dann prüft ob das Geld passt und dann entsprechend handelt.

lg


Lazarusboy - Mo 30.05.11 19:32

Ich würde trotzdem gerne wissen was ich da falsch gemacht habe,
ich habe festgestellt, dass sobald ich einmal 50 cent button drücke,das Projekt feststell, dass nun Zustand 'f' herrscht, und noch einmal 50 Cent dazumacht und nun feststellt dass Zustand 'e' herrscht und nun wieder 50 cent dazu macht usw....#
was kann ich dagegen machen, damit nicht alle case verknüpft sind.


Yogu - Mo 30.05.11 20:21

Wenn ich deinen Code soweit überblicke, sieht das in etwa so aus:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
case Zustand of
  'a':
  begin
    case Eingabe of 
      'a': blah;
      'b': blah;
    end;
  end;
end;

case Zustand of
  'b':
  begin
    case Eingabe of 
      'a': blah;
      'b': blah;
    end;
  end;
end;

Du hast also für jeden Zustand ein eigenes case-Konstrukt. Du solltest auf jeden Fall mal deinen Code richtig einrücken, so ähnlich wie ich es oben getan habe, und dann die Zweige der äußersten case-Abfrage in einer einzigen vereinigen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
case Zustand of
  'a':
  begin
    case Eingabe of 
      'a': blah;
      'b': blah;
    end;
  end;

  'b':
  begin
    case Eingabe of 
      'a': blah;
      'b': blah;
    end;
  end;
end;

Dann wird auch abgebrochen, sobald er Zweig für 'a' durchgeführt wurde.


Ist es eigentlich eine Informatikleherer-Krankheit, erstens Zustände als char zu speichern und zweitens eine riesige Zustand-wechsle-dich-Funktion zu basteln, die Geld wechseln, Kaffe kochen, Wohnungen saugen und Kartoffeln anbauen kann, je nach dem, welchen Parameter (wohlgemerkt vom Typ char) man ihr übergibt? Kenn ich von meinem Lehrer.


Jann1k - Mo 30.05.11 22:07

Zitat:
Ist es eigentlich eine Informatikleherer-Krankheit, erstens Zustände als char zu speichern und zweitens eine riesige Zustand-wechsle-dich-Funktion zu basteln, die Geld wechseln, Kaffe kochen, Wohnungen saugen und Kartoffeln anbauen kann, je nach dem, welchen Parameter (wohlgemerkt vom Typ char) man ihr übergibt? Kenn ich von meinem Lehrer.


Also wenn man vorher endliche Automaten o.ä. im Unterricht durchgesprochen hat, ergibt das doch Sinn.


Yogu - Di 31.05.11 15:32

Moderiert von user profile iconNarses: Komplett-Zitat des letzten Beitrags entfernt.

Das haben wir in der Tat, aber ich sehe trotzdem keinen Sinn darin, einzelne Zeichen als Zustandsindikatoren zu verwenden. Und ein Getränkeautomat hat normalerweise auch nicht einen Knopf, den man in eine bestimmte Richtung oder unterschiedlich tief drücken kann, sondern einfach mehrere davon.


>M@steR< - Di 31.05.11 15:53

Gelöscht


Jann1k - Di 31.05.11 16:26

Zitat:
Das haben wir in der Tat, aber ich sehe trotzdem keinen Sinn darin, einzelne Zeichen als Zustandsindikatoren zu verwenden.


Da gebe ich dir recht, das kann man besser machen.

Zitat:
Und ein Getränkeautomat hat normalerweise auch nicht einen Knopf, den man in eine bestimmte Richtung oder unterschiedlich tief drücken kann, sondern einfach mehrere davon.


Aber ein endlicher Automat hat aber eben nur genau eine Zustandsüberführungsfunktion.


beastofchaos - Di 31.05.11 16:28

Jep bei meinem Informatiklehrer ist das auch so ungefähr :P

@Lazarusboy - Tipp für dich, deinen Lehrer missachtend: sag doch z.B. einfach, bei OnClick auf Cola:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
begin
  Kosten := 1,50;
  if Kosten > Bezahlt then
    Edit1.Text := 'Sie haben zu wenig bezahlt !'
  else
    begin
    Rückgabe := Bezahlt - Kosten;
    Edit1.Text := 'Sie erhalten eine leckere Cola und ' + FloatToStr(Rückgabe) + ' € als Rückgeld !';
    end;
  // hier evtl. einige variablen wieder auf Null setzen für den nächsten Durchlauf oder so ;) 
end;


Das wäre die Prozedur für das eine Click-Ereignis. Wenn du mehrere Buttons (Cola, Fanta, Sprite) machst, dann nimmst du für alle eine Prozedur (ButtonClick(Sender: TObject)) und fragst per case-Schleife, welcher Button gedrpckt ist:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure TMainForm.ButtonClick(Sender: TObject);
var
  Kosten, Rückgabe: Integer;
begin
  case Sender of
    BCola:
      Kosten := 1,50;
    BFanta:
      Kosten := 1,00;
    BSprite:
      Kosten := 1,20;
    end;

   Rückgabe := Bezahlt - Kosten;
   Edit1.Text := 'Sie erhalten ein leckeres Getränk und ' + FloatToStr(Rückgabe) + ' € als Rückgeld !'
end;


Genial, ne?


Gruß, Thomas


buster - Mi 01.06.11 12:29

Kein Pädagoge im Saal? :)

Ich schätze mal, die Aufgabe lautete, Lösen Sie das Problem mit Hilfe des im Unterricht besprochenen Algorithmus ...
Es wird dem Lehrer sicher nicht um die (irgendeine) bestmögliche Lösung gehen (mir ist schon klar, dass sowas wesentlich effizienter gelöst werden kann), sondern darum, den vermittelten Stoff irgendwie in einem (mehr oder weniger passenden) Anwendungsbeispiel zu verbasteln... um zu sehen, ob es auch verstanden wurde. Also nicht das Ergebnis zählt, sondern der Weg ist hier das Ziel ;) ...Abweichungen enden da schnell mal in 'Thema verfehlt' und schlechten Noten...

LG, Basti


Xearox - Mi 01.06.11 12:38

Nichts destotrotz würde ich Lazarusboy empfehlen, seinen oben geschrieben Code zu formatieren.
Wie oben auch geschrieben wurde von jemanden, damit man mal einen Überblick erhält.
Weil 3 x end; untereinander ist ziemlich schwer mit Anhieb herauszufinden, welchen End; zu welchem begin gehört.

Vllt. kann dann Lazarusboy in seinem Code selber den Fehler finden.


anubis2k5 - Do 02.06.11 18:25

Hallo Leute!

Ich habe von dieser Materie nicht viel Ahnung, aber wäre das Problem nicht gelöst, wenn man die Schleife einfach mittels "exit;" verlässt?


Yogu - Do 02.06.11 19:19

user profile iconanubis2k5 hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe von dieser Materie nicht viel Ahnung, aber wäre das Problem nicht gelöst, wenn man die Schleife einfach mittels "exit;" verlässt?

In dem Quellcode gibt es keine Schleife, also würde Exit; die Prozedur abbrechen.

Damit wäre möglicherweise das beschriebene Problem gelöst. Den Quelltext verstanden hätte trotzdem niemand, und der nächste Fehler würde nicht lange auf sich warten lassen.


beastofchaos - So 05.06.11 19:00

Genau, da ist von Anfang an keine Hoffnung :P

Nebenbei: "Exit" unterbricht immer die Funktion/Prozedur. "Break" unterbricht die Schleife (was wenn keine da ist?).

Sowas ist aber ein bisschen unbeliebt - schließlich siehst du so nicht bei einem Blick, wo die Prozedur/Funktion endet.
Man nennt das, glaub ich, auch "Spaghetti-Code" :)

Gruß, Thomas


Fiete - Mo 06.06.11 09:51

Moin Lazarusboy,
zu jedem endlichen Automaten gehört ein Zustandsdiagramm, das sich gut programmieren läßt.
Die Planungsarbeit ist die wichtigste!
Vielleicht hilt der Anhang. :les:
Gruß Fiete


Delete - Mo 06.06.11 10:14

user profile iconbeastofchaos hat folgendes geschrieben Zum zitierten Posting springen:
case-Schleife

Wo um Himmels Willen kommt nur die Unsitte her, Verzweigungen als Schleife zu bezeichnen? Man spricht ja auch nicht von einer for-Verzweigung. :twisted:


Regan - Mo 06.06.11 10:18

Kennst du die if-Schleife [http://if-schleife.de/] noch nicht?


beastofchaos - Mo 06.06.11 23:12

okay! Case-Verzweigung, For/While/Repeat-Schleife, If-Abfrage ;)

Also was macht nun "Break", wenn man sich in keiner dieser Arten befinde? Fehlermeldung oder wie "Exit" die Prozedur/Funktion beenden?


Delete - Di 07.06.11 09:08

Was spricht dagegen es einfach mal auszuprobieren? Dein Computer wird schon nicht explodieren:

Delphi-Quelltext
1:
2:
3:
ShowMessage('Vor break');
break;
ShowMessage('Nach break');


beastofchaos - Di 07.06.11 09:26

user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
Was spricht dagegen es einfach mal auszuprobieren? Dein Computer wird schon nicht explodieren:

Delphi-Quelltext
1:
2:
3:
ShowMessage('Vor break');
break;
ShowMessage('Nach break');


Genau das befürchte ich :'( xD


der organist - Di 07.06.11 21:34

wer machts?

EDIT: Ich. Heraus kommt bei F9 folgendes:

[DCC Fehler] UMain.pas(29): E2097 BREAK oder CONTINUE außerhalb der Schleife

schon irgendwie lustig :D

EDIT No2: Dann aus Sinnfreiigkeit das ausgetestet:


Delphi-Quelltext
1:
2:
3:
4:
ShowMessage('Vor Break');
while True do
  break;
ShowMessage('Nach Break');


Wenigstens funktioniert es...