Kleines Rechenquizprogramm
-
- Beiträge: 4
- Registriert: Di 28. Sep 2021, 15:47
Kleines Rechenquizprogramm
Hallo Leute, ich habe mir ein kleines Rechenquiz programmiert, bei dem die Rechenarten und die Zahlen per Zufall ausgegeben werden. Der Anwender muss dann jeweils nur das richtige Ergebnis eingeben. Meine Frage ist jetzt nur, wie bekomme ich das hin, dass den Rechenarten Minus und Geteilt die erste Zahl immer größer ist?
program rechenquiz;
uses crt;
var x,y,z,rechenart : integer;
weiter : char;
// Addition
procedure plus;
begin
randomize;
x := random(100);
y := random(100);
write(x,' + ',y,' = ');
readln(z);
if z = x+y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x+y);
end;
// Subtraktion
procedure minus;
begin
randomize;
x := random(100);
y := random(100);
if x > y then
write(x,' - ',y,' = ');
readln(z);
if z = x-y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x-y);
end;
// Multiplikation
procedure mal;
begin
randomize;
x := random(100);
y := random(10);
if x > y then
write(x,' * ',y,' = ');
readln(z);
if z = x*y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x*y);
end;
// Division
procedure geteilt;
begin
randomize;
x := random(100);
y := random(10);
if x > y then
write(x,' / ',y,' = ');
readln(z);
if z = x div y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x div y);
end;
procedure eingabe;
begin
repeat
case rechenart of
0: plus;
1: minus;
2: mal;
3: geteilt;
end;
randomize;
rechenart := random(4);
writeln;
write('weiter j/n : ');
read(weiter);
writeln;
until weiter = 'n';
end;
begin
clrscr;
writeln('Das ist ein Rechenquizprogramm');
writeln('------------------------------');
writeln;
eingabe;
readln;
end.
Danke schon mal im Voraus,
Dietmar Erler
program rechenquiz;
uses crt;
var x,y,z,rechenart : integer;
weiter : char;
// Addition
procedure plus;
begin
randomize;
x := random(100);
y := random(100);
write(x,' + ',y,' = ');
readln(z);
if z = x+y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x+y);
end;
// Subtraktion
procedure minus;
begin
randomize;
x := random(100);
y := random(100);
if x > y then
write(x,' - ',y,' = ');
readln(z);
if z = x-y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x-y);
end;
// Multiplikation
procedure mal;
begin
randomize;
x := random(100);
y := random(10);
if x > y then
write(x,' * ',y,' = ');
readln(z);
if z = x*y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x*y);
end;
// Division
procedure geteilt;
begin
randomize;
x := random(100);
y := random(10);
if x > y then
write(x,' / ',y,' = ');
readln(z);
if z = x div y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x div y);
end;
procedure eingabe;
begin
repeat
case rechenart of
0: plus;
1: minus;
2: mal;
3: geteilt;
end;
randomize;
rechenart := random(4);
writeln;
write('weiter j/n : ');
read(weiter);
writeln;
until weiter = 'n';
end;
begin
clrscr;
writeln('Das ist ein Rechenquizprogramm');
writeln('------------------------------');
writeln;
eingabe;
readln;
end.
Danke schon mal im Voraus,
Dietmar Erler
Re: Kleines Rechenquizprogramm
Einfach die Zahlen vertauschen. Schreibe dir eine Prozedur dafür, weil das öfter vorkommt. Übergib die zwei Zahlen als var Parameter, damit die aufrufende Routine die vertauschten Zahlen wirklich empfängt.engeldimo123 hat geschrieben: Di 28. Sep 2021, 16:14 wie bekomme ich das hin, dass den Rechenarten Minus und Geteilt die erste Zahl immer größer ist?
Code: Alles auswählen
procedure Vertauschen(var a, b: Integer);
Rufe diese Prozedur immer dann auf, wenn die erste Zahl kleiner ist als die zweite und du das anders haben willst.
Code: Alles auswählen
// Subtraktion
procedure minus;
begin
//randomize; // Es reicht, wenn das nur 1x zu Programmbeginn aufgerufen wird.
x := random(100);
y := random(100);
if x < y then
Vertauschen(x, y);
write(x,' - ',y,' = ');
readln(z);
if z = x-y then
writeln('Richtig gerechnet!')
else
writeln('Leider falsch, richtig ist ',x-y);
end;
Code: Alles auswählen
procedure eingabe;
begin
repeat
case rechenart of
0: plus;
1: minus;
2: mal;
3: geteilt;
end;
randomize;
rechenart := random(4);
writeln;
write('weiter j/n : ');
read(weiter);
writeln;
until weiter = 'n';
end;
-
- Beiträge: 4
- Registriert: Di 28. Sep 2021, 15:47
Re: Kleines Rechenquizprogramm
Hallo,
danke dir für die kleine Hilfestellung. Also ich habe mir die Prozedur hier geschrieben:
Und dann habe ich noch bei der Pozededur eingabe die Random-Funktion vor die Case-Anweisung geschrieben, so vermeide ich, dass die erste Rechenart immer Plus ist. So scheint es jetzt gut zu funktionieren:
danke dir für die kleine Hilfestellung. Also ich habe mir die Prozedur hier geschrieben:
Code: Alles auswählen
procedure vertauschen(a,b : integer);
begin
a := random(100);
b := random(100);
if a < b then
begin
x := b;
y := a;
end;
end;
Code: Alles auswählen
program rechenquiz;
uses crt;
var x,y,z,rechenart : integer;
weiter : char;
procedure vertauschen(a,b : integer);
begin
a := random(100);
b := random(100);
if a < b then
begin
x := b;
y := a;
end;
end;
// Addition
procedure plus;
begin
x := random(100);
y := random(100);
write(x,' + ',y,' = ');
readln(z);
if z = x+y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x+y);
end;
// Multiplikation
procedure mal;
begin
x := random(100);
y := random(10);
if x < y then
write(x,' * ',y,' = ');
readln(z);
if z = x*y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x*y);
end;
// Subtraktion
procedure minus;
begin
x := random(100);
y := random(100);
if x < y then
vertauschen(x,y);
write(x,' - ',y,' = ');
readln(z);
if z = x-y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x-y);
end;
// Division
procedure geteilt;
begin
x := random(100);
y := random(100);
if x > y then
vertauschen(x,y);
write(x,' / ',y,' = ');
readln(z);
if z = x div y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x div y);
end;
procedure eingabe;
begin
repeat
rechenart := random(4);
case rechenart of
0: plus;
1: minus;
2: mal;
3: geteilt;
end;
writeln;
write('weiter j/n : ');
read(weiter);
writeln;
until weiter = 'n';
end;
begin
clrscr;
randomize;
writeln('Dies ist ein kleines Rechenquiz mit den 4 Grundrechenarten');
writeln('-> Gib bei der Division nur die ganze Zahl ohne Rest ein');
writeln('----------------------------------------------------------');
writeln;
eingabe;
readln;
end.
Re: Kleines Rechenquizprogramm
Ja, das mit der Case-Anweisung hast du jetzt richtig.
Aber die Vertauschen-Prozedur ist nicht gut. Wenn sie der Compiler akzeptiert, dann liegt das nur daran, dass du mit globalen Variablen arbeitest, was das alles sehr undurchsichtig macht. Und wenn sie überhaupt funktioniert, dann liegt das daran, dass du mit Zufallszahlen arbeitest und dadurch die Ergebnisse nicht gut prüfen kannst.
Das Hauptproblem mit Vertauschen ist, dass sie zwar zwei Zahlen a, b als Eingabeargumente verwendet, aber die vertauschten Zahlen nicht zurückliefert. Es funktioniert (wenn überhaupt) nur, weil du in der Prozedur auf globale Variablen zurückgreifst und dort das Ergebnis ablegst. Die Prozedur muss aber immer funktionieren, egal was es sonst noch für Variablen und Prozeduren gibt.
Jetzt nochmal, etwas ausführlicher: Die Prozedur erhält zwei Zahlen, a und b, als Eingabe, vertauscht sie und muss in a und b die vertauschten Zahlen an die aufrufenden Prozedur zurückgeben, also was vorher a war, ist nun b, und umgekehrt. Damit die Prozedur überhaupt Werte an die aufrufende Prozedur zurückgeben kann, müssen die Argumente als "var", also "variabel" oder "veränderbar" deklariert sein. Eine Beispiel-Programm mit einer etwas anderen Prozedur:
x ist zunächst 0 und wird dann an die Prozedur EinsAddieren übergeben. In dieser Prozedur wird die Eingangsvariable, die hier "a" heißt, aber das tut nichts zur Sache, sie kann irgendwie heißen, eingelesen, um 1 erhöht und, weil es ein "var"-Parameter ist, ans hauptprogramm zurückgegeben. Die zweite WriteLn-Anweisung gibt daher den Wert 1 aus.
Um den Effekt des "var" zu verstehen, entferne es einmal testhalber, also deklariere procedure EinsAddieren(a: Integer) (ohne var). Nun gibt die zweite WriteLn-Anweisung den Wert 0 aus - weil EinsAddieren wegen des fehlenden "var" das Rechenergebnis nicht zurückgeben konnte.
Genauso machst du es mit der Vertauschen-Prozedur: procedure Vertauschen(var a: Integer; var b: Integer), oder einfacher Vertauschen(var a,b: Integer) - wir haben nun zwei Parameter, beide als "var" deklariert, die in der Prozedur verändert werden, und die aufrufende Prozedur kann mit den veränderten Werten weiterarbeiten.
Zum Vertauschen selbst brauchst du eine Hilfsvariable, nennen wir sie c. Diese brauchen wir nur innerhalb der Vertauschen-Prozedur, deshalb wird sie genau dort deklariert - nicht außerhalb als globale Variable, denn wenn du irgendwo anders noch eine globale Variable c bräuchtest, dann würdest du deren Wert durch die Vertauschungs-aktion verändern. Wichtige Regel: Globale Variablen soviel wie möglich vermeiden.
Mit dieser Hilfsvariablen c führen wir nun die Vertauschung durch: In c merken wir uns den aktuellen Wert von a. Dann schreiben wir in a den Wert von b hinein. Der erste Parameter, der a heißt, hat nun den Wert von b. Dadurch geht zwar der ursprüngliche Wert von a verloren, aber wir haben ihn ja vorher in c zwischengespeichert. Und zum Schluss schreiben wir den Wert von c - den ehemaligen Wert von a - in die Variable b. Der zweite Parameter, der b heißt, hat nun den Wert von a - die Werte sind vertauscht.
Als Code geht das so - bitte versuche, das unbedingt zu verstehen:
Wenn die Vertauschen-Prozedur verlassen wird, existiert die Hilfsvariable c dann nicht mehr. Man kann von nirgendwo mehr auf c zurückgreifen, aber das ist der Sinn von lokalen Variablen
Wie man das nun anwendet erläutere ich an deiner Prozedur Minus:
Du ziehst zwei Zufallszahlen, x und y. Wenn x kleiner als y ist, dann werden die beiden vertauscht - x ist nun größer als y. Du gibts die Rechenaufgabe aus, lässt den Benutzer das Ergebnis eingeben und meldest, ob es richtig ist. So soll es sein.
Obwohl: ganz zufrieden bin ich damit nicht. Es ist nämlich so, dass du die Werte x, y und z nirgendwo im Hauptprogramm benötigst. Daher solltest du gleich die oben erwähnte Regel anwenden und sie nicht als globale Variablen deklarieren, sondern lokal in der Minus-Prozedur (und natürlich genauso in den anderen Rechenprozeduren):
Nun brauchst du den "var" Block gleich zu Beginn des Programms nicht mehr!
Bei der Eingabeprozedur ist es genauso. Die Variablen "rechenart" und "weiter" werden nur hier verwendet und sollten nicht global, sondern nur lokal existieren - jede Variable zuviel ist ein möglicher schwer zu findender Fehler!
Wie schon gesagt, solltest du Randomize nur 1x zu Beginn des Programms aufrufen. Das Hauptprogramm sieht nun so aus:
Aber die Vertauschen-Prozedur ist nicht gut. Wenn sie der Compiler akzeptiert, dann liegt das nur daran, dass du mit globalen Variablen arbeitest, was das alles sehr undurchsichtig macht. Und wenn sie überhaupt funktioniert, dann liegt das daran, dass du mit Zufallszahlen arbeitest und dadurch die Ergebnisse nicht gut prüfen kannst.
Das Hauptproblem mit Vertauschen ist, dass sie zwar zwei Zahlen a, b als Eingabeargumente verwendet, aber die vertauschten Zahlen nicht zurückliefert. Es funktioniert (wenn überhaupt) nur, weil du in der Prozedur auf globale Variablen zurückgreifst und dort das Ergebnis ablegst. Die Prozedur muss aber immer funktionieren, egal was es sonst noch für Variablen und Prozeduren gibt.
Jetzt nochmal, etwas ausführlicher: Die Prozedur erhält zwei Zahlen, a und b, als Eingabe, vertauscht sie und muss in a und b die vertauschten Zahlen an die aufrufenden Prozedur zurückgeben, also was vorher a war, ist nun b, und umgekehrt. Damit die Prozedur überhaupt Werte an die aufrufende Prozedur zurückgeben kann, müssen die Argumente als "var", also "variabel" oder "veränderbar" deklariert sein. Eine Beispiel-Programm mit einer etwas anderen Prozedur:
Code: Alles auswählen
program Test;
procedure EinsAddieren(var a: Integer);
begin
a := a + 1;
end;
var
x: Integer;
begin
x := 0;
WriteLn(x);
EinsAddieren(x);
WriteLn(x);
end.
Um den Effekt des "var" zu verstehen, entferne es einmal testhalber, also deklariere procedure EinsAddieren(a: Integer) (ohne var). Nun gibt die zweite WriteLn-Anweisung den Wert 0 aus - weil EinsAddieren wegen des fehlenden "var" das Rechenergebnis nicht zurückgeben konnte.
Genauso machst du es mit der Vertauschen-Prozedur: procedure Vertauschen(var a: Integer; var b: Integer), oder einfacher Vertauschen(var a,b: Integer) - wir haben nun zwei Parameter, beide als "var" deklariert, die in der Prozedur verändert werden, und die aufrufende Prozedur kann mit den veränderten Werten weiterarbeiten.
Zum Vertauschen selbst brauchst du eine Hilfsvariable, nennen wir sie c. Diese brauchen wir nur innerhalb der Vertauschen-Prozedur, deshalb wird sie genau dort deklariert - nicht außerhalb als globale Variable, denn wenn du irgendwo anders noch eine globale Variable c bräuchtest, dann würdest du deren Wert durch die Vertauschungs-aktion verändern. Wichtige Regel: Globale Variablen soviel wie möglich vermeiden.
Mit dieser Hilfsvariablen c führen wir nun die Vertauschung durch: In c merken wir uns den aktuellen Wert von a. Dann schreiben wir in a den Wert von b hinein. Der erste Parameter, der a heißt, hat nun den Wert von b. Dadurch geht zwar der ursprüngliche Wert von a verloren, aber wir haben ihn ja vorher in c zwischengespeichert. Und zum Schluss schreiben wir den Wert von c - den ehemaligen Wert von a - in die Variable b. Der zweite Parameter, der b heißt, hat nun den Wert von a - die Werte sind vertauscht.
Als Code geht das so - bitte versuche, das unbedingt zu verstehen:
Code: Alles auswählen
procedure Vertauschen(var a, b: Integer),
var
c: Integer;
begin
c := a;
a := b;
b := c;
end;
Wie man das nun anwendet erläutere ich an deiner Prozedur Minus:
Code: Alles auswählen
procedure Minus;
begin
x := random(100);
y := random(100);
if x < y then
Vertauschen(x, y);
write(x,' - ',y,' = ');
readln(z);
if z = x-y then
writeln('Richtig gerechnet!')
else
writeln('Leider falsch, richtig ist ',x-y);
end;
Obwohl: ganz zufrieden bin ich damit nicht. Es ist nämlich so, dass du die Werte x, y und z nirgendwo im Hauptprogramm benötigst. Daher solltest du gleich die oben erwähnte Regel anwenden und sie nicht als globale Variablen deklarieren, sondern lokal in der Minus-Prozedur (und natürlich genauso in den anderen Rechenprozeduren):
Code: Alles auswählen
procedure Minus;
var
x, y, z: Integer;
begin
x := random(100);
y := random(100);
if x < y then
Vertauschen(x, y);
write(x,' - ',y,' = ');
readln(z);
if z = x-y then
writeln('Richtig gerechnet!')
else
writeln('Leider falsch, richtig ist ',x-y);
end;
Bei der Eingabeprozedur ist es genauso. Die Variablen "rechenart" und "weiter" werden nur hier verwendet und sollten nicht global, sondern nur lokal existieren - jede Variable zuviel ist ein möglicher schwer zu findender Fehler!
Code: Alles auswählen
procedure Eingabe;
var
rechenart: Integer;
weiter: char;
begin
repeat
rechenart := random(4);
case rechenart of
0: plus;
1: minus;
2: mal;
3: geteilt;
end;
writeln;
write('weiter j/n : ');
read(weiter);
writeln;
until weiter = 'n';
end;
Code: Alles auswählen
program RechenQuiz;
uses crt;
... (hier alle Rechen-Prozeduren, sowie die Eingabe-Prozedur)
begin
Randomize;
ClearScr;
Writeln('Das ist ein Rechenquizprogramm');
Writeln('------------------------------');
Writeln;
Eingabe;
Readln;
end.
- fliegermichl
- Lazarusforum e. V.
- Beiträge: 1647
- Registriert: Do 9. Jun 2011, 09:42
- OS, Lazarus, FPC: Lazarus Fixes FPC Stable
- CPU-Target: 32/64Bit
- Wohnort: Echzell
Re: Kleines Rechenquizprogramm
und was soll an 4 - 5 = -1 falsch sein?
-
- Beiträge: 761
- Registriert: Di 23. Aug 2016, 14:25
- OS, Lazarus, FPC: Windows 11
- CPU-Target: 64Bit
- Wohnort: Berlin
Re: Kleines Rechenquizprogramm
!!! random(10) ergibt Werte zwischen 0..9
Das heisst bei einer Division kann das dann schief gehen.
Durch 0 teilen erzeugt einen Laufzeitfehler.
Eigentlich wäre wohl random(10)+1 bzw. random(100)+1 eher sinnvoll, dann bekommst Du Werte zwischen 1 und 10 bzw. zwischen 1 und 100.
Das heisst bei einer Division kann das dann schief gehen.
Durch 0 teilen erzeugt einen Laufzeitfehler.
Eigentlich wäre wohl random(10)+1 bzw. random(100)+1 eher sinnvoll, dann bekommst Du Werte zwischen 1 und 10 bzw. zwischen 1 und 100.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
-
- Beiträge: 4
- Registriert: Di 28. Sep 2021, 15:47
Re: Kleines Rechenquizprogramm
Hallo, habe mein kleines Rechenquiz nochmal überarbeitet und so
müsste es jetzt gut funktionieren.
Grüße
Dietmar Erler
müsste es jetzt gut funktionieren.
Code: Alles auswählen
program rechenquiz;
uses crt;
var rechenart : integer;
weiter : char;
procedure vertauschen(var a,b : integer);
var zwischenwert : integer;
begin
zwischenwert := a;
a := b;
b := zwischenwert;
end;
// Addition
procedure plus;
var x,y,z : integer;
begin
x := random(100)+1;
y := random(100)+1;
write(x,' + ',y,' = ');
readln(z);
if z = x+y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x+y);
end;
// Subtraktion
procedure minus;
var x,y,z : integer;
begin
x := random(100)+1;
y := random(100)+1;
if x < y then
vertauschen(x,y);
write(x,' - ',y,' = ');
readln(z);
if z = x-y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x-y);
end;
// Multiplikation
procedure mal;
var x,y,z : integer;
begin
x := random(100)+1;
y := random(10)+1;
if x < y then
write(x,' * ',y,' = ');
readln(z);
if z = x*y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x*y);
end;
// Division
procedure geteilt;
var x,y,z : integer;
begin
x := random(100)+1;
y := random(10)+1;
if x < y then
vertauschen(x,y);
write(x,' / ',y,' = ');
readln(z);
if z = x div y then
writeln('Richtig gerechnet!')
else writeln('Leider falsch, richtig ist ',x div y);
end;
procedure eingabe;
begin
repeat
rechenart := random(4);
case rechenart of
0: plus;
1: minus;
2: mal;
3: geteilt;
end;
writeln;
write('weiter j/n : ');
read(weiter);
writeln;
until weiter = 'n';
end;
begin
clrscr;
writeln('Dies ist ein kleines Rechenquiz mit den 4 Grundrechenarten');
writeln('-> Gib bei der Division nur die ganze Zahl ohne Rest ein');
writeln('----------------------------------------------------------');
writeln;
randomize;
eingabe;
readln;
end.
Grüße
Dietmar Erler
Re: Kleines Rechenquizprogramm
Ich hab's nicht getestet, sieht beim Drüberscrollen aber gut aus. Bis auf die unnötigen globalen variablen rechnenart und weiter - diese werden nur im Inneren der Prozedur Eingabe() benötigt, können also dort lokal deklariert werden.
-
- Beiträge: 153
- Registriert: Sa 30. Jan 2010, 18:17
- OS, Lazarus, FPC: Windows 10 64Bit/ lazarus 3.0 mit FPC 3.2.2 (32Bit + 64bit)
- CPU-Target: 64Bit
- Wohnort: Berlin
Re: Kleines Rechenquizprogramm
Du solltest dir nochmal die "Procedure mal" genauer ansehen. Da wird die Rechenaufgabe nur dann ausgegeben, wenn x < y aber das Ergebnis wird dennoch in jedem Fall abgefragt. Dass erscheint mir falsch. Ich denke mal, dass das "if x < y then" ein Copy-Paste Überbleibsel ist.
Wenn mann jetzt noch ein wenig "optimieren" möchte, könnte mann sich überlegen, die Rechenarten mit nur einer procedure abzubilden. Die Proceduren schauen doch alle sehr ähnlich aus...
Wenn mann jetzt noch ein wenig "optimieren" möchte, könnte mann sich überlegen, die Rechenarten mit nur einer procedure abzubilden. Die Proceduren schauen doch alle sehr ähnlich aus...