Lazarus/Schleifen und Lazarus/Spielen mit dem Zufall: Unterschied zwischen den Seiten

Aus ZUM-Unterrichten
< Lazarus(Unterschied zwischen Seiten)
main>Peterdauscher
 
main>Peterdauscher
Keine Bearbeitungszusammenfassung
 
Zeile 1: Zeile 1:
{{Lazarus-Buch}}
{{Lazarus-Buch}}


== Zählschleifen ==
Bisher haben wir Zahlenwerte immer entweder fest im Programm vorgegeben (etwa a:=42),
Mit Hilfe von Alternativen (if-then-else) konnten wir Programme so steuern, dass bestimmte Anweisungen nur unter ganz bestimmten Bedingungen ausgeführt wurden, andernfalls nicht. Allerdings wurde die gleiche Anweisung (bei ein und demselben Knopfdruck) immer nur ein einziges Mal ausgeführt.
vom Benutzer während der Eingabe erfragt (etwa mit <tt>ReadFrom(...)</tt>) oder aber irgendwie aus bereits bekannten Werten ausgerechnet (z.B. <tt>a:=sqrt(c)</tt>). Für viele Anwendungen – vor allem für die, die ein bisschen Spaß machen – wäre es jedoch nett, zufällige Zahlen zu haben. Das gilt z.B. für Glücksspiele genauso wie für Geschicklichkeitsspiele.


Bei vielen Dingen ist es jedoch sinnvoll, wenn Dinge mehrfach ausgeführt werden. Nicht umsonst heißt es: "Ein Computer ist unglaublich dumm, aber sehr sehr fleißig". So könnte eine sehr einfache Aufgabe an den Computer lauten, er solle die Zahlen von 1 bis 10 nacheinander in das Memo-Feld <tt>Memo1</tt> schreiben. Natürlich könnten wir den Befehl <tt>WriteLnTo(Memo1,1)</tt> zehn mal untereinander kopieren und dann die Zahlen zwischen den Klammern verändern. Aber das wäre sehr sehr lästige -- und schlimmer noch -- langweilige Arbeit.
Für solche Fragen ist der Befehl <tt>random</tt> nützlich. Ohne Klammer hinter dem Befehl (also etwa <tt>x:=random;</tt>) “würfelt” der Befehl eine (reelle) Zufallszahl im Bereich zwischen 0 und 1. Damit ist es mit ein bisschen Mathematik nicht schwierig, auch natürliche Zufallszahlen in beliebigen Zahlenbereichen zu basteln. Allerdings nimmt Lazarus einem einen Teil dieser Arbeit ab, wenn man eine Zahl in Klammern hinter den Befehl schreibt (also etwa <tt>k:=random(bereich);</tt>). Der Computer würfelt dann eine Zufallszahl zwischen 0 und <tt>bereich-1</tt>.


Viel bequemer ist es dagegen, wenn wir dem Computer sagen:


"Es gibt eine Variable <tt>zaehler</tt>. Setze diese Variable zunächst auf 1 und zähle sie dann schrittweise auf 10 hoch. Nach jedem Zählschritt schreibe den Wert der Variable in das Memo-Feld." Genau dies tut das folgende Programm. (Es ist nur die entscheidende Prozedur vermerkt, den Rest kennst Du mittlerweile).
{{kasten_blau|<source  line start=30 highlight="6" lang="pascal">
 
 
{{kasten_blau|<source  line start="30" highlight="5-6" lang="pascal">
procedure TForm1.Button1Click(Sender: TObject);
var zaehler : integer;
begin
Clear(Memo1);
for zaehler := 1 to 10
do WriteLnTo(Memo1,zaehler);
end;                     
</source>}}
 
Auch hier können bei jedem Zählschritt auch mehrere Anweisungen ausgeführt werden; die muss man hier wieder mit <tt>begin</tt> und <tt>end</tt> zu einem Anweisungsblock gruppieren:
{{kasten_blau|<source  line start="30" highlight="5-9" lang="pascal">
procedure TForm1.Button1Click(Sender: TObject);
procedure TForm1.Button1Click(Sender: TObject);
var zaehler : integer;
begin
begin
Clear(Memo1);
Clear(Memo1);
for zaehler := 1 to 10
for i:=1 to 5
do begin
do begin
   WriteTo(Memo1,zaehler);
   zufallszahl:=random(100);
   WriteLnTo(Memo1,'. Runde)
   WriteLnTo(Memo1,zufallszahl);
   end;
   end;
end;                    
end;  
</source>}}
</source>}}


== Schleifen mit Eingangsbedingung (while-Schleifen)==
Startet man ein Programm, das auf Knopfdruck eine Zufallszahl ziehen soll mehrfach, so ist allerdings zunächst die Enttäuschung groß. Denn es ist immer die gleiche Zahl bzw. die gleichen Zahlen, die beim ersten Knopfdruck nach dem Programmstart gezogen werden. So großartig zufällig ist das nun wirklich nicht. Dem kann man jedoch abhelfen, wenn man gleich nach dem Programmstart den Befehl <tt>randomize;</tt> ausführen lässt. Der sorgt dafür, dass die Zufallszahlen tatsächlich bei jedem Programmlauf andere sind.
Nehmen wir an, ein (recht phantasieloser) Lehrer gäbe seinen Schüler die Stillarbeit, so viele aufeinanderfolgende Zahlen zu addieren und die Zwischenergebnisse zu notieren, bis die Summe den Wert 1000 erreicht. Schüler Fritz hat sein Netbook im Ranzen und will das Problem mit Lazarus lösen. Das Problem: Er kann jetzt natürlich auf gut Glück ungefähr raten, bis zu welcher Zahl er die Zahlen addieren muss und dies mit einer for-Schleife tun. Aber es muss doch auch eine andere Möglichkeit geben, nämlich, dass der Computer selbst merkt, wenn das Ergebnis erreicht ist. Tatsächlich gibt es diese Möglichkeit:


{{kasten_blau|<source  line start="30" highlight="6-15" lang="pascal">
{{kasten_blau|<source  line start=30 highlight="4" lang="pascal">
procedure TForm1.Button1Click(Sender: TObject);
procedure TForm1.Button1Click(Sender: TObject);
var zaehler : integer;
    summe : integer;
begin
begin
Clear(Memo1);
Clear(Memo1);
zaehler:=0;
randomize;
summe:=0;
for i:=1 to 5
while summe<1000
do begin
do begin
   zaehler:=zaehler+1;
   zufallszahl:=random(100);
  summe:=summe+zaehler;
   WriteLnTo(Memo1,zufallszahl);
  WriteTo(Memo1,zaehler);
  WriteTo(Memo1,':');
   WriteLnTo(Memo1,summe);
   end;
   end;
end;            
end;        
</source>}}
</source>}}


Man erkennt deutliche Unterschiede: Die Schleife, so heißt es in dem Programm, wird so lange wiederholt, solange die Summe noch einen Wert kleiner als 1000 hat. Das Setzen des Zählers auf 0 am Anfang und das Hochzählen in jedem einzelnen Schritt, muss der Programmierer hier selbst übernehmen (Zeilen 35 bzw. 39).
'''Anmerkung:''' Es schadet nichts, zu wissen, was dieses <tt>randomize</tt> eigentlich tut. Eigentlich kann ein klassischer Computer keine wirklich zufälligen Zahlen erzeugen sondern nur [https://de.wikipedia.org/wiki/Pseudozufall Pseudozufallszahlen]. Diese berechnet man aus einer anfänglich gegebenen Zahl durch Gleichungen, die scheinbar ungeordnete, aber eben nicht wirklich zufällige Zahlen erzeugen. Da die Anfangszahl ohne die Verwendung von <tt>randomize</tt> immer die gleiche ist, ist auch die daraus berechnete Folge von Pseudozufallszahlen immer die gleiche. <tt>randomize</tt> ermittelt jetzt bei jedem Programmlauf eine andere Anfangszahl. Dafür benutzt der Befehl die Zeit der Computeruhr, die "Systemzeit". Die ist bei jedem Programmstart eine andere und sie hängt -- irgendwie dann doch zufällig -- davon ab, wann genau der Benutzer das Programm startet.
 
'''Wichtige Anmerkung''':
Angenommen, man würde in Zeile 36 den anfänglichen Wert der Variable <tt>summe</tt> auf 1000 setzen, so würde der Computer sozusagen gar nicht erst mit der Schleife anfangen, sondern alles zwischen <tt>while</tt> und dem <tt>end</tt> der Schleife überspringen. Denn die Schleife soll ja nur solange ausgeführt werden, solange die Bedingung <tt>summe<1000</tt> erfüllt ist. Und das wäre sie in diesem Fall ja von Anfang an nicht. Deshalb spricht man bei der while-Schleife auch von einer Schleife mit Eingangsbedingung.
 
== Schleifen mit Abbruchbedingung (repeat-until-Schleifen) ==
 
Anders ist es bei Schleifen mit Abbruchsbedingung. Bei denen wird das Innere der Schleife mindestens einmal durchlaufen. Eine solche Schleife ist in Pascal die so genannte Repeat-Until-Schleife. Unser Problem mit dem Aufsummieren von Zahlen bis zur Summe 1000 könnte mit einer solchen Schleife so aussehen:
 
{{kasten_blau|<source  line start="30" highlight="6-14" lang="pascal">procedure TForm1.Button1Click(Sender: TObject);
var zaehler : integer;
    summe : integer;
begin
Clear(Memo1);
zaehler:=0;
summe:=0;
  repeat
  zaehler:=zaehler+1;
  summe:=summe+zaehler;
  WriteTo(Memo1,zaehler);
  WriteTo(Memo1,':');
  WriteLnTo(Memo1,summe);
  until summe>1000;
end;   
</source>}}
 
Das Programm verhält sich haargenau wie das Programm mit der While-Schleife. Solange man nicht die Summe vorher größer oder gleich 1000 wählt. Würde man das tun, würde zumindest ein Summations- und Schreibschritt ausgeführt und erst dann die Schleife abgebrochen.
 
 
==Aufgaben==
#Ändere das einfache Zählprogramm mit for-Schleife so ab, dass man in einem Edit-Feld angeben kann, bis zu welcher Zahl der Computer zählen soll.  
#Karin bekommt 100 Euro geschenkt. Sie legt sie auf der Bank an mit einem Zinssatz von <nowiki>2.3%</nowiki> (Jahreszins). Ein Programm soll ihr sagen, nach wievielen Jahren sich die Summe verdoppelt hat (oder mehr).
#Bei radioaktiven Stoffen spricht man von der Halbwertszeit, das ist die Zeit, nach der ein Stoff nur noch halb soviel strahlt. Schreibe ein Programm, das die Halbwertszeit (in Jahren) vom Benutzer erfragt und dann ausrechnet, nach wievielen Jahren die Strahlung auf ein Hundertstel zurückgegangen ist.
#In grauer Vorzeit (bis zur Erfindung des Taschenrechners) hatte man sogenannte Logarithmentafeln, in denen die Werte der Logarithmusfunktion tabelliert waren, also eine Tabelle mit x und ln x als Spalten. Schreibe ein Programm, das eine solche Tafel ausdruckt (für x-Werte 0.01, 0.02 . . . 1.00).
#Der Mathematiker Leibnitz fand eine Methode, die Zahl π näherungsweise zu berechnen.<br/> Es gilt: <math>\frac{\pi}{4}=1-\frac{1}{3}+\frac{1}{5}-\frac{1}{7}+\frac{1}{9}+\ldots </math><br/> Schreibe ein Programm, das diesen langen Ausdruck bis zum Summanden <math>\frac{1}{401}</math> ausrechnet. Vergleiche die Zahl mit dem Ergebnis Deines Taschenrechners.
#Die Fakultät einer Zahl n (geschrieben als n!) ist definiert als <math> n!= 1 \cdot 2 \cdot 3 \cdot \ldots \cdot n</math> <br /> Schreibe ein Programm, das nach Eingabe einer Zahl n die Fakultät ausrechnet. Was passiert bei großen Werten für n?
#Zwei Würfel werden geworfen. Schreibe ein Programm, dass alle Möglichkeiten ausgibt, wie die beiden Augenzahlen aussehen können (also etwa: (1,1), (1,2), (1,3), ... (6,6)).


== Aufgaben ==
#Schreibe ein Lazarus-Programm zum Würfeln, bei dem nach dem Drücken eines Knopfes in einem Edit-Feld eine Zahl zwischen 1 und 6 erscheint.
#In manchen Würfelspielen wird mit zwei Würfeln gewürfelt. Schreibe ein Programm, das bei jedem Wurf mit zwei (gedachten) Würfeln würfelt und die Zahlen ausgibt; außerdem die Augensumme. Weiterhin soll das Programm ausgeben, wenn es bei einem Wurf ein „Pasch“ gegeben hat (Augenzahl bei beiden Würfeln gleich).
#Fred und George erfinden ein Würfelspiel. Jeder darf 10 mal würfeln (Zahlen zwischen 1 und 6). Es gewinnt, wessen größte Zahl am größen ist. Schreibe ein Programm, das auf Knopfdruck ein solches zehnmaliges Würfeln simuliert und die Werte in ein Memo-Feld schreibt. Außerdem soll es dann noch direkt sagen, welches die größte gewürfelte Zahl war: "Die größte Zahl war ..."
#Schreibe ein (sehr vereinfachtes) Roulette-Rad, das zufällig eine Zahl zwischen 0 und 36 erzeugt. Für die Zahlen zwischen 1 und 36 soll die Maschine ausgeben, ob die Zahl gerade ist (PAIR) oder ungerade (IMPAIR). Wenn sie Null ist, soll die Maschine ZERO ausgeben.
# Kartenlegerin Esmeralda steigt endlich auf moderne Technik um. Sie verwendet seit jeher Skat-Karten. Dort gibt es die “Farben” Kreuz, Pique, Herz und Karo. Außerdem gibt es die Zahlen bzw. Figuren 7, 8, 9, 10, Bube, Dame, König, Ass. <br />Insgesamt gibt es also 4 · 8 = 32 Karten. Schreiben Sie für Esmeralda ein Programm, das eine zuf¨allige Karte erzeugt (also zum Beispiel “Pique 10”). <br />Hinweis: Man kann es sehr umständlich machen und eine Zufallszahl zwischen 1 und 32 ziehen und entsprechend eine bestimmte Karte zuordnen. Es geht aber auch deutlich eleganter.
#Fülle die Bildoberfläche mit 5000 komplett zufällig verteilten und zufällig gefärbten Pixeln.
{{Lazarus-Buch}}
{{Lazarus-Buch}}

Version vom 28. Januar 2013, 07:21 Uhr


Bisher haben wir Zahlenwerte immer entweder fest im Programm vorgegeben (etwa a:=42), vom Benutzer während der Eingabe erfragt (etwa mit ReadFrom(...)) oder aber irgendwie aus bereits bekannten Werten ausgerechnet (z.B. a:=sqrt(c)). Für viele Anwendungen – vor allem für die, die ein bisschen Spaß machen – wäre es jedoch nett, zufällige Zahlen zu haben. Das gilt z.B. für Glücksspiele genauso wie für Geschicklichkeitsspiele.

Für solche Fragen ist der Befehl random nützlich. Ohne Klammer hinter dem Befehl (also etwa x:=random;) “würfelt” der Befehl eine (reelle) Zufallszahl im Bereich zwischen 0 und 1. Damit ist es mit ein bisschen Mathematik nicht schwierig, auch natürliche Zufallszahlen in beliebigen Zahlenbereichen zu basteln. Allerdings nimmt Lazarus einem einen Teil dieser Arbeit ab, wenn man eine Zahl in Klammern hinter den Befehl schreibt (also etwa k:=random(bereich);). Der Computer würfelt dann eine Zufallszahl zwischen 0 und bereich-1.


Vorlage:Kasten blau

Startet man ein Programm, das auf Knopfdruck eine Zufallszahl ziehen soll mehrfach, so ist allerdings zunächst die Enttäuschung groß. Denn es ist immer die gleiche Zahl bzw. die gleichen Zahlen, die beim ersten Knopfdruck nach dem Programmstart gezogen werden. So großartig zufällig ist das nun wirklich nicht. Dem kann man jedoch abhelfen, wenn man gleich nach dem Programmstart den Befehl randomize; ausführen lässt. Der sorgt dafür, dass die Zufallszahlen tatsächlich bei jedem Programmlauf andere sind.

Vorlage:Kasten blau

Anmerkung: Es schadet nichts, zu wissen, was dieses randomize eigentlich tut. Eigentlich kann ein klassischer Computer keine wirklich zufälligen Zahlen erzeugen sondern nur Pseudozufallszahlen. Diese berechnet man aus einer anfänglich gegebenen Zahl durch Gleichungen, die scheinbar ungeordnete, aber eben nicht wirklich zufällige Zahlen erzeugen. Da die Anfangszahl ohne die Verwendung von randomize immer die gleiche ist, ist auch die daraus berechnete Folge von Pseudozufallszahlen immer die gleiche. randomize ermittelt jetzt bei jedem Programmlauf eine andere Anfangszahl. Dafür benutzt der Befehl die Zeit der Computeruhr, die "Systemzeit". Die ist bei jedem Programmstart eine andere und sie hängt -- irgendwie dann doch zufällig -- davon ab, wann genau der Benutzer das Programm startet.

Aufgaben

  1. Schreibe ein Lazarus-Programm zum Würfeln, bei dem nach dem Drücken eines Knopfes in einem Edit-Feld eine Zahl zwischen 1 und 6 erscheint.
  2. In manchen Würfelspielen wird mit zwei Würfeln gewürfelt. Schreibe ein Programm, das bei jedem Wurf mit zwei (gedachten) Würfeln würfelt und die Zahlen ausgibt; außerdem die Augensumme. Weiterhin soll das Programm ausgeben, wenn es bei einem Wurf ein „Pasch“ gegeben hat (Augenzahl bei beiden Würfeln gleich).
  3. Fred und George erfinden ein Würfelspiel. Jeder darf 10 mal würfeln (Zahlen zwischen 1 und 6). Es gewinnt, wessen größte Zahl am größen ist. Schreibe ein Programm, das auf Knopfdruck ein solches zehnmaliges Würfeln simuliert und die Werte in ein Memo-Feld schreibt. Außerdem soll es dann noch direkt sagen, welches die größte gewürfelte Zahl war: "Die größte Zahl war ..."
  4. Schreibe ein (sehr vereinfachtes) Roulette-Rad, das zufällig eine Zahl zwischen 0 und 36 erzeugt. Für die Zahlen zwischen 1 und 36 soll die Maschine ausgeben, ob die Zahl gerade ist (PAIR) oder ungerade (IMPAIR). Wenn sie Null ist, soll die Maschine ZERO ausgeben.
  5. Kartenlegerin Esmeralda steigt endlich auf moderne Technik um. Sie verwendet seit jeher Skat-Karten. Dort gibt es die “Farben” Kreuz, Pique, Herz und Karo. Außerdem gibt es die Zahlen bzw. Figuren 7, 8, 9, 10, Bube, Dame, König, Ass.
    Insgesamt gibt es also 4 · 8 = 32 Karten. Schreiben Sie für Esmeralda ein Programm, das eine zuf¨allige Karte erzeugt (also zum Beispiel “Pique 10”).
    Hinweis: Man kann es sehr umständlich machen und eine Zufallszahl zwischen 1 und 32 ziehen und entsprechend eine bestimmte Karte zuordnen. Es geht aber auch deutlich eleganter.
  6. Fülle die Bildoberfläche mit 5000 komplett zufällig verteilten und zufällig gefärbten Pixeln.