Lazarus/Die Unit LazIOStuff und Lazarus/Schleifen: Unterschied zwischen den Seiten

Aus ZUM-Unterrichten
< Lazarus(Unterschied zwischen Seiten)
K (12 Versionen importiert)
 
main>Peterdauscher
 
Zeile 1: Zeile 1:
{{Lazarus-Buch}}
{{Lazarus-Buch}}


== Wozu die Unit LazIOStuff ==
== Zählschleifen ==
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.


<tt>LazIOStuff</tt> ist eine Lazarus-Unit, die eine Reihe von Befehlen zur vereinfachten Ein- und Ausgabe zur Verfügung stellt. Man kann sich fragen, weshalb man überhaupt eine solche Unit schreibt, wo doch Lazarus von sich aus doch schon jede Menge Möglichkeiten zur Ein- und Ausgabe von Werten hat. Und weshalb man innerhalb eines Online-Lehrbuchs diese Unit benutzt.
Wir starten ein neues Lazarus-Projekt und betrachten ein mehrzeiliges Eingabe-Feld, ein so genanntes Memo-Feld (TMemo). Wir wollen, dass dem Memo-Feld <tt>Memo1</tt> beim Druck auf den Knopf <tt>Button1</tt> jeweils eine Zeile mit de, Wort "Hallo" hinzugefügt wird.


Der Hauptgrund besteht darin, dass es beim Lernen einer Programmiersprache angenehm ist, wenn man sich auf die wesentlichen Dinge konzentrieren kann. Vereinfachte Befehle für Ein- und Ausgabe sollen genau dabei helfen. So haben wir z.B. in den vergangenen Kapiteln gesehen, dass wir immer wieder den Inhalt von Edit-Feldern zu Integer- oder Real-Zahlen übersetzen mussten. In den folgenden Kapiteln wollen wir Ergebnisse in Memo-Felder ausgeben, das sind Komponenten mit mehreren Textzeilen.
Dafür ändern wir die Prozedur <tt>TForm1.Button1Click(Sender: TObject); </tt> wie folgt. (Es ist nur die entscheidende Prozedur vermerkt, den Rest kennst Du mittlerweile).
Das alles würde auch relativ leicht in Lazarus direkt funktionieren, jedoch würde der Programmcode etwas unübersichtlich, und das kann dem Lernen dann doch abträglich sein.


== Download und Einbinden ==
{{kasten_blau|<source  line start="33" highlight="3" lang="pascal">
Die zugehörige Datei kann hier heruntergeladen werden [http://sourceforge.net/projects/laziostuff/files/laziostuff.pas/download laziostuff.pas]. Die Pascal-Datei muss in das Verzeichnis kopiert werden, in der sich das Lazarus-Projekt befindet, in das es eingebunden werden soll. Das Einbinden selbst erfolgt durch Hinzufügen von <tt>LazIOStuff</tt> in die Zeile <tt>uses ...</tt>
procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add('Hallo');
end;   
</source>}}




== Die von LazIOStuff bereitgestellten Befehle ==
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 das Wort "Hallo" 10 mal untereinander in das Memo-Feld <tt>Memo1</tt> schreiben.


{| class ="wikitable toptextcells"
Natürlich könnten wir den Befehl <tt>Memo1.Lines.Add('Hallo');</tt> zehn mal untereinander kopieren. Aber das wäre sehr sehr lästige -- und schlimmer noch -- langweilige Arbeit.
! Befehl
Viel bequemer ist es dagegen, wenn wir dem Computer sagen:
! Bedeutung
|-
| WriteTo(Komponente, Wert, [Gesamtanzahl Zeichen, Nachkommastellen]) || Schreibt einen Wert (vom Typ String, Integer oder Double) in eine Komponente.<br /> Das kann entweder eine Edit-Komponente oder eine mehrzeilige Memo-Komponente sein. <br />Bei Edit-Komponenten wird der darin befindliche Inhalt einfach ersetzt, bei Memo-Komponenten jedoch hinter den bisherigen Inhalt angehängt. <br/> Bei Integer-Werten kann zusätzlich angegeben werden, wie viele Zeichen die Ausgabe insgesamt haben soll (rechtsbündige Zahlen). <br/> Bei Double-Zahlen kann man zusätzlich dazu wiederum noch einstellen, mit wie vielen Nachkommastellen die Zahl angezeigt wird.
|-  
| WriteLnTo(Komponente, Wert, [Gesamtanzahl Zeichen, Nachkommastellen]) || Funktioniert ähnlich wie WriteTo, mit einem wesentlichen Unterschied: <br/> Diese Funktion bezieht sich ausschließlich auf die mehrzeiligen Memo-Komponenten. <br/>Nach der Ausgabe verursacht sie gezielt einen Zeilenumbruch.<br/> WriteLnTo kann man auch ganz ohne Klammern verwenden; dann erzeugt es einfach nur einen Zeilenumbruch.
|-
| ReadFrom(Edit-Komponente, Wert) || Liest aus einer Edit-Komponente einen Wert (entsprechend des Datentyps) aus. Möglich sind Zeichenketten (Strings), Integer- und Double-Werte.
|-  
| Clear(Komponente) ||Löscht den Inhalt der entsprechenden Komponente.
|-
|}


Das folgende Beispiel demonstriert die verschiedenen Befehle der Unit LazIOStuff und benötigt die Komponenten <tt>Button1, Edit1 und Memo1</tt>.
"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 das Wort "Hallo" in das Memo-Feld." Genau dies tut das folgende Programm.  


{{blau|<source  line highlight="6,24,31-40" lang="pascal">
{{kasten_blau|<source  line start="33" highlight="3-4" lang="pascal">
unit lazio_testumgebung;
procedure TForm1.Button1Click(Sender: TObject);
{$mode objfpc}{$H+}
begin
interface
for zaehler:=1 to 10
do Memo1.Lines.Add('Hallo');
end;                    
</source>}}


uses
Allerdings musst Du noch bei der Liste der Variablen die Variable <tt>zaehler</tt> als Integer-Variable deklarieren:
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, LazIOStuff;
<tt>zaehler : integer;</tt>
Wenn Du nicht jedes Mal wieder zur Variablenliste springen willst, kannst Du die Variable auch direkt in der Prozedur vor dem <tt>begin</tt> deklarieren. Dann allerdings kennt Lazarus diese Variable tatsächlich nur innerhalb dieser Prozedur. Beim nächsten Beispiel ist dies so gemacht.


type
Dieses Beispiel zeigt, wie bei jedem Zählschritt auch mehrere Anweisungen ausgeführt werden können: die muss man hier wieder mit <tt>begin</tt> und <tt>end</tt> zu einem Anweisungsblock gruppieren:
  { TForm1 }
{{kasten_blau|<source  line start="33" highlight="5-8" lang="pascal">
procedure TForm1.Button1Click(Sender: TObject);
var zaehler : integer;
begin
for zaehler:=1 to 10
do begin
  Memo1.Lines.Add('Hallo');
  Memo1.Lines.Add('=========='); 
  end;
end;                   
</source>}}


  TForm1 = class(TForm)
Und ganz wichtig: Die Variable <tt>zaehler</tt> kann im Programm auch verwendet werden. Zum Beispiel, um die "Hallo-Welt"-Ausrufe durchzunummerieren. Da die Nummer und das "Hallo" durchaus in eine Zeile passen, kann man beide dem "+"-Zeichen verbinden und in ein- und dasselbe "Add" hineinschreiben:
    Button1: TButton;
    Edit1: TEdit;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;


var
{{kasten_blau|<source  line start="33" highlight="7" lang="pascal">
  Form1: TForm1;
procedure TForm1.Button1Click(Sender: TObject);
  zahl : integer;
var zaehler : integer;
begin
Memo1.Lines.Clear;
for zaehler:=1 to 10
do begin
  Memo1.Lines.Add(IntToStr(zaehler)+' Hallo');
  Memo1.Lines.Add('===============');
  end;
end; 
</source>}}         


implementation
Außerdem sorgt bei diesem Beispiel die Zeile <tt>Memo1.Lines.Clear;</tt> dafür, dass das Feld vor dem Beschreiben gesäubert wird und das (vielleicht lästigte) <tt>Memo1</tt> verschwindet.


{$R *.lfm}
== Schleifen mit Eingangsbedingung (while-Schleifen)==
{ TForm1 }
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  highlight="5,9" line start="33"  lang="pascal">
procedure TForm1.Button1Click(Sender: TObject);
procedure TForm1.Button1Click(Sender: TObject);
var zaehler, summe : integer;
begin
Memo1.Lines.Clear;
zaehler:=0;
summe:=0;
while summe<1000
do begin
  zaehler:=zaehler+1;
  summe:=summe+zaehler;
  Memo1.Lines.Add(IntToStr(zaehler)+':'+IntToStr(summe));
  end;
end;               
</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 37 bzw. 41).
'''Wichtige Anmerkung''':
Angenommen, man würde in Zeile 38 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 highlight="6,12" line start="30" lang="pascal">procedure TForm1.Button1Click(Sender: TObject);
begin
begin
ReadFrom(Edit1,zahl);
Clear(Memo1);
Clear(Memo1);
WriteLnTo(Memo1,'Es geht los!');
zaehler:=0;
WriteLnTo(Memo1,zahl);
summe:=0;
WriteLnTo(Memo1,zahl,10);
  repeat
WriteLnTo(Memo1,' wurde eingegeben. Und die Hälfte davon ist:');
  zaehler:=zaehler+1;
WriteLnTo(Memo1,zahl/2,20,5);
  summe:=summe+zaehler;
end;
  WriteTo(Memo1,zaehler);
 
  WriteTo(Memo1,':');
end.
  WriteLnTo(Memo1,summe);
  until summe>1000;
end;   
</source>}}
</source>}}


Die Ausgabe in der <tt>Memo1</tt>-Komponente nach Eingabe der Zahl "7" in der Komponente <tt>Edit1</tt> ist:
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.
{{blau|<source lang="pascal">Es geht los!
7
        7
wurde eingegeben. Und die Hälfte davon ist:
            3,50000
</source>}}


==Aufgaben==
==Aufgaben==
#Ein Programm soll zwei Edit-Komponenten haben, eine für den Vornamen und eine für den Nachnamen einer Person. Auf Knopfdruck soll dann in einer Memo-Komponente etwa die Ausgabe <br/> <tt>Herzlich willkommen</tt> <br/> <tt>Donald Duck</tt> <br/> erscheinen. Ein weiterer Knopf soll beim Drücken bewirken, dass das Memo-Feld wieder gesäubert wird.
#Ä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.
#Schreibe ein Divisionsprogramm, das in zwei Edit-Feldern zwei Zahlen eingibt. In einem Memo-Feld sollen dann das Ergebnis der ganzzahligen Division, der Rest der ganzzahligen Division, der Quotient als Kommazahl (10 Zeichen gesamt, 3 Nachkommastellen) stehen. <br/> Und selbstverständlich soll der Computer vorher prüfen, ob hier nicht durch Null dividiert werden soll. Sollte der Benutzer das versuchen, soll ein Ausgabe im Memo-Feld erscheinen, die den Benutzer auf seinen Fehler aufmerksam macht.
#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).
#Zeichne in eine Image-Komponente ein Gitter mit Kästchen. Die horizontalen und vertikalen Linien sollen jeweils einen Abstand von 20 Pixeln voneinander haben.
#Eine Image-Komponente soll von unten nach oben mit einem Farbverlauf von dunkelgrau nach hellgrau ausgefüllt werden.
#Versuche, eine Sinuskurve auf dem Bildschirm darzustellen.
#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)).
 
{{Lazarus-Buch}}

Version vom 19. Januar 2014, 10:54 Uhr


Zählschleifen

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.

Wir starten ein neues Lazarus-Projekt und betrachten ein mehrzeiliges Eingabe-Feld, ein so genanntes Memo-Feld (TMemo). Wir wollen, dass dem Memo-Feld Memo1 beim Druck auf den Knopf Button1 jeweils eine Zeile mit de, Wort "Hallo" hinzugefügt wird.

Dafür ändern wir die Prozedur TForm1.Button1Click(Sender: TObject); wie folgt. (Es ist nur die entscheidende Prozedur vermerkt, den Rest kennst Du mittlerweile).

Vorlage:Kasten blau


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 das Wort "Hallo" 10 mal untereinander in das Memo-Feld Memo1 schreiben.

Natürlich könnten wir den Befehl Memo1.Lines.Add('Hallo'); zehn mal untereinander kopieren. Aber das wäre sehr sehr lästige -- und schlimmer noch -- langweilige Arbeit. Viel bequemer ist es dagegen, wenn wir dem Computer sagen:

"Es gibt eine Variable zaehler. Setze diese Variable zunächst auf 1 und zähle sie dann schrittweise auf 10 hoch. Nach jedem Zählschritt schreibe das Wort "Hallo" in das Memo-Feld." Genau dies tut das folgende Programm.

Vorlage:Kasten blau

Allerdings musst Du noch bei der Liste der Variablen die Variable zaehler als Integer-Variable deklarieren: zaehler : integer; Wenn Du nicht jedes Mal wieder zur Variablenliste springen willst, kannst Du die Variable auch direkt in der Prozedur vor dem begin deklarieren. Dann allerdings kennt Lazarus diese Variable tatsächlich nur innerhalb dieser Prozedur. Beim nächsten Beispiel ist dies so gemacht.

Dieses Beispiel zeigt, wie bei jedem Zählschritt auch mehrere Anweisungen ausgeführt werden können: die muss man hier wieder mit begin und end zu einem Anweisungsblock gruppieren: Vorlage:Kasten blau

Und ganz wichtig: Die Variable zaehler kann im Programm auch verwendet werden. Zum Beispiel, um die "Hallo-Welt"-Ausrufe durchzunummerieren. Da die Nummer und das "Hallo" durchaus in eine Zeile passen, kann man beide dem "+"-Zeichen verbinden und in ein- und dasselbe "Add" hineinschreiben:

Vorlage:Kasten blau

Außerdem sorgt bei diesem Beispiel die Zeile Memo1.Lines.Clear; dafür, dass das Feld vor dem Beschreiben gesäubert wird und das (vielleicht lästigte) Memo1 verschwindet.

Schleifen mit Eingangsbedingung (while-Schleifen)

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.

Vorlage:Kasten blau

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 37 bzw. 41).

Wichtige Anmerkung: Angenommen, man würde in Zeile 38 den anfänglichen Wert der Variable summe auf 1000 setzen, so würde der Computer sozusagen gar nicht erst mit der Schleife anfangen, sondern alles zwischen while und dem end der Schleife überspringen. Denn die Schleife soll ja nur solange ausgeführt werden, solange die Bedingung summe<1000 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:

Vorlage:Kasten blau

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

  1. Ä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.
  2. Karin bekommt 100 Euro geschenkt. Sie legt sie auf der Bank an mit einem Zinssatz von 2.3% (Jahreszins). Ein Programm soll ihr sagen, nach wievielen Jahren sich die Summe verdoppelt hat (oder mehr).
  3. Zeichne in eine Image-Komponente ein Gitter mit Kästchen. Die horizontalen und vertikalen Linien sollen jeweils einen Abstand von 20 Pixeln voneinander haben.
  4. Eine Image-Komponente soll von unten nach oben mit einem Farbverlauf von dunkelgrau nach hellgrau ausgefüllt werden.
  5. Versuche, eine Sinuskurve auf dem Bildschirm darzustellen.
  6. 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.
  7. 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).
  8. Der Mathematiker Leibnitz fand eine Methode, die Zahl π näherungsweise zu berechnen.
    Es gilt:
    Schreibe ein Programm, das diesen langen Ausdruck bis zum Summanden ausrechnet. Vergleiche die Zahl mit dem Ergebnis Deines Taschenrechners.
  9. Die Fakultät einer Zahl n (geschrieben als n!) ist definiert als
    Schreibe ein Programm, das nach Eingabe einer Zahl n die Fakultät ausrechnet. Was passiert bei großen Werten für n?
  10. 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)).