Home Computer Pascal Kurs Site Map counter

Jetzt lerne ich Pascal... Teil 10

Programmentwicklung an einem Beispiel

Bislang haben wir immer einzelne Befehle vorgestellt, doch dadurch können sie natürlich noch nicht programmieren. Anfragen in Newgroups von Anfängern zeigen immer wieder einen miserablen Programmierstill, der dann auch Probleme aufwirft. Am Beispiel eines kleinen Programms das sie auch herunterladen können, will ich versuchen einen Einstieg zu geben. Danach sollten sie noch die letzten fehlenden Dinge ergänzen, doch dazu später mehr.

Die Aufgabe selbst ist sowohl einfach, wie auch interessant. Bei der Fußball WM 2002 habe ich einen Beitrag über Erwachsene gesehen die Fußballer Sammelbildchen sammeln. Aus meiner Kindheit weiß ich noch was das für ein Groschengrab ist. Es eignet sich aber auch hervorragend für eine Simulation, um herauszufinden wie teuer dieses Hobby wird.

Das Problem: Es gibt ein Album in dem Bilder eingeklebt werden. Nennen wir die Anzahl der Bilder die dort Platz haben mal N. N liegt meistens irgendwo zwischen 50 und 100. Dazu kauft man ein Päckchen, bei dem man den Inhalt nicht sehen kann. Es enthält m Bilder die rein zufällig verpackt wurden. M ist typischerweise eine Zahl von 3-5.

Das Problem des Sammlers. Nehmen wir mal an N=50 und m=3. Bei einem leeren Album ist die Welt noch in Ordnung. Alle 3 Bilder sind neu. (In der Realität sind immer 3 verschiedene Bilder in einem Päckchen, doch für unser Modell können auch Dupletten vorkommen, um es programmtechnisch etwas einfacher zu machen). Doch beim zweiten Päckchen gibt es für jedes Bild eine Chance von 3/50, das man es schon hat. Diese wird immer größer und erreicht beim letzten Bild den Wert 49/50, d.h. um das letzte Bild einigermaßen sicher zu erhalten müsste man so um die 17 Päckchen kaufen.

Das Programm das wir schreiben soll dies simulieren. Es soll solange Päckchen kaufen, bis das Album voll ist. Da ein Durchgang nur wenig Aussagekraft hat (Der Zufall regiert), soll der Benutzer angeben können wie oft dies simuliert werden soll und das Programm soll den Mittelwert aus diesen Durchgängen, sowie die kleinste und Größe Anzahl an Päckchen ermitteln.

Schritt 1: Was brauchen wir an Variablen und Konstanten? Nun damit der Benutzer keine unsinnige Daten eintippt, sollte man die Zahl der Bilder pro Päckchen und die Zahl der Bilder pro Album beschränken. Man braucht also je zwei Konstanten für Minimum und Maximum. Weiterhin müssen wir uns die eingegebenen Werte merken, und dazu noch die zu ermittelnden Werte (Mittel, Maximum, Minimum und Anzahl der Päckchen pro Durchlauf). Das führt zu folgenden Konstanten:

const Maxbilder 100; {max. Zahl an Bilder pro Album}
Minbilder 30; {min Zahl an Bilder pro Album}
Minpack 1; {min Zahl an Bildern pro Päckchen}
Maxpack 7;

var Album : array [1..Maxbilder] of Integer;
Albumsize : Integer;
Packsize : Integer;
Packcount : Integer;
Min,Max : Integer;
Mittel : Double;
Laeufe : Integer;
Diese Sektion wächst im allgemeinen bei der Programmerstellung, wenn man merkt, was man alles so braucht. Wenn hier zu viele Variablen stehen dann wird es an der Zeit nachzudenken ob wirklich a l l e global sein müssen. Dies wird eine Aufgabe bei der Verbesserung des Programms sein.

Wichtig ist: Sie sollten sich angewöhnen im Programm alle Werte die konstant sind, als Konstanten zu formulieren, außer es sind triviale Dinge. (Trivial ist z.B., das die Untergrenze von Album hier 1 ist.) Das kann bei größeren Programme dann schon so sein, dass eine Unit mit 30 K Länge nur aus Konstanten und Typen besteht. Bei größeren Programmen sollte man dann das auch auslagern.

Alle Variablennamen sollten sprechend sein, sie sollten aus dem Namen ableiten können wofür die Variable verwendet wird. Für einfache Laufvariablen haben sich Buchstaben eingebürgert, aber ansonsten sollten sie die Namen nicht zu kurz wählen.

Intuitiv kann man das Programm nach dem EVA Prinzip (Eingabe-Verarbeitung-Ausgabe) in 3 Prozeduren gliedern. Die erste die man angehen würde, ist die Eingabe der Daten. Da wir eine Fehlerabfrage über die Konstanten haben, wiederholen wir die Eingabe solange bis sie in einem gültigen Bereich ist.

procedure Eingabe;

begin
repeat
Write('Anzahl an Bildern pro Album: ');
Read(Albumsize);
until Albumsize in [Minbilder..Maxbilder];
WriteLn;
repeat
Write('Anzahl an Bildern pro Päckchen: ');
Read(Packsize);
until Packsize in [Minpack..Maxpack];
WriteLn;
Write('Wieviele Läufe: ');
Read(Laeufe);
end;
Die Repeat Schleife ist ideal für eine solche Abfrage. Es ist zugleich auch eine einfache Fehlerbehandlungsmethode. Auch dies ist ein wichtiger Grundbaustein eines guten Programms. Gehen Sie immer davon aus das zumindest bei der Eingabe von Hand es zu Fehlern kommen kann. Bei Dateien sollte man zumindest überprüfen, ob Dateien die man öffnet, auch existieren. Wie fein sie ihr Programm untergliedern ist Ansichtssache. Eine Prozedur sollte aber ganz auf eine Bildschirmseite passen. Manche Autoren plädieren dazu, alles was sich irgendwo wiederholt, in Unterprogramme zu packen. Also hier z.B.
function Eingabe(const unten,oben : Integer): Integer;

var ergebnis : Integer;

begin
Ergebnis:=-1;
{-1 weil die Readfunktion bei Betätigung von Enter den letzten Wert zurückgibt}
repeat
Write('Anzahl an Bildern pro Album: ');
Read(Ergebnis);
until Albumsize in [unten..oben];
WriteLn;
Eingabe:=Ergebnis;
end;

Ich würde dies bei dem zweimaligen Vorkommen noch nicht machen, doch wenn man solche Codeteile öfters braucht, ist dies sinnvoll. Analog ist eine Ausgabe schnell gebastelt:

procedure Ausgabe;

var Uebrig : Integer;

begin
Uebrig:=Trunc(Mittel*Packsize);
WriteLn;
WriteLn('kleinste Zahl an Päckchen: ',Min:6);
WriteLn('größte Zahl an Päckchen: ',Max:6);
WriteLn('Mittelwert : ',Mittel:6:1);
WriteLn('Überschuss : ',100*(1-(Albumsize/Uebrig)):6:1,' %');
end
Die eigentliche Verarbeitung kann man in einer Prozedur machen. Doch eigentlich sind es zwei Dinge, die man machen muss: Einmal für jedes Album das Kaufen von Päckchen simulieren. Es wird solange wiederholt bis man jede Sammelkarte mindestens einmal hat. Zweitens dies so oft wiederholen, wie der Benutzer es wünscht und dabei sich noch merken was der kleinste und größte Wert war. Das letztere geht so:
procedure Statistik;

var I : Integer;

begin
Max:=-1;
Min:=MaxInt; {Grenzen die niedriger als der kleinste Wert im Wertebereich, bzw. höher als der höchste sind}
for I:=1 to Laeufe do
begin
Simulation;
if Packcount<Min then Min:=Packcount;
if Packcount>Max then Max:=Packcount;
Mittel:=Mittel+1.0*Packcount/Laeufe;
end;
end;
Während man den Simulationsteil unterschiedlich auslegen kann. Ich habe hier einen "Greedy" Algorithmus verwendet, das ist ein schnell eingefallener, aber nicht optimaler Algorithmus. Doch dazu später mehr. Wichtig für das Verständnis sind noch 2 Funktionen:

random(n) liefert wenn n eine ganze Zahl ist als Ergebnis eine Zufallszahl zwischen 0 und n-1 zurück. Um auf 1..n zu kommen müssen wir also noch 1 addieren.
randomize initialisiert. den Zufallszahlengenerator mit einem zufälligen Startwert, ohne diese Instruktion bekäme man bei jedem Programmlauf dasselbe Ergebnis. Es ist üblich ein Programm so zu gliedern das einzelne Funktionen einzelne Aufgaben erledigen. Hier gibt es den Job der Initialisierung und den der Simulation des Füllens eines Albums. Daher gibt es zwei Unterprozeduren.

procedure Simulation;

var Fertig : Boolean;
I,Nr : Integer;

procedure Init;

var I : Integer;

begin
for
I:=1 to Albumsize do Album[I]:=0;
Packcount:=0;
Randomize;
end;

begin
Init;
repeat
for
I:=1 to Packsize do
begin
Nr:=Random(Albumsize)+1;
Album[Nr]:=Album[Nr]+1;
end;
Inc(Packcount);
Fertig:=True;
for I:=1 to Albumsize do
Fertig:=Fertig and (Album[I]>0);
until Fertig;
end
Zuletzt noch das Hauptprogramm, es ruft eigentlich nur die 3 Prozeduren auf:
begin
ClrScr;
Eingabe;
Statistik;
Ausgabe;
end.
So, hier finden Sie das ganze Programm. Aber: es ist nicht perfekt und hält für sie 3 Aufgaben bereit.

Aufgabe 1: Globale Variablen sind verpönt. Schreiben Sie es so um, das es keine globalen Variablen benutzt. Das sollte nach diesem Kurs kein Problem mehr sein.

Aufgabe 2: Wenn Sie das Programm laufen lassen wird es trotz Gigaherz Prozessor nicht das schnellste sein. Warum? Nun bei jedem Päckchen wird die Schleife:

    Fertig:=True;
for I:=1 to Albumsize do
Fertig:=Fertig and (Album[I]>0);
until Fertig;
durchlaufen, um festzustellen ob man alle Bilder eines Päckchens hat. Das macht den Algorithmus langsam. (Warum?). Überlegen Sie sich eine effizientere Lösung, um festzustellen ob das Album schon voll ist. Wenn Sie meinen eine gute Lösung gefunden zu haben, dann können Sie mir diese gerne zu schicken. Ich denke man kann ohne Probleme den Algorithmus hier von einer Ordnung N² zu einer von N bringen, was die Ausführungszeit drastisch reduziert. (Ordnung eines Algorithmus: Wie oft wird jedes Element "angefasst")

Aufgabe 3: In der Realität tauscht man Bilder mit anderen Sammlern. Erweitern sie das Programm so, das 3 Personen Päckchen kaufen und doppelte an andere weitergeben. Das Programm soll Zuende sein, wenn alle 3 Alben voll sind. Wie viel besser ist dies, als das Sammeln alleine ?


Zum Thema Computer ist auch von mir ein Buch erschienen. "Computergeschichte(n)" beinhaltet, das was der Titel aussagt: einzelne Episoden aus der Frühzeit des PC. Es sind Episoden aus den Lebensäufen von Ed Roberts, Bill Gates, Steve Jobs, Stephen Wozniak, Gary Kildall, Adam Osborne, Jack Tramiel und Chuck Peddle und wie sie den PC schufen.

Das Buch wird abgerundet durch eine kurze Erklärung der Computertechnik vor dem PC, sowie einer Zusammenfassung was danach geschah, als die Claims abgesteckt waren. Ich habe versucht ein Buch zu schreiben, dass sie dahingehend von anderen Büchern abhebt, dass es nicht nur Geschichte erzählt sondern auch erklärt warum bestimmte Produkte erfolgreich waren, also auf die Technik eingeht.

Die 2014 erschienene zweite Auflage wurde aktualisiert und leicht erweitert. Die umfangreichste Änderung ist ein 60 Seiten starkes Kapitel über Seymour Cray und die von ihm entworfenen Supercomputer. Bedingt durch Preissenkungen bei Neuauflagen ist es mit 19,90 Euro trotz gestiegenem Umfang um 5 Euro billiger als die erste Auflage. Es ist auch als e-Book für 10,99 Euro erschienen.

Mehr über das Buch auf dieser eigenen Seite.

Sitemap Kontakt Neues Hier werben Bücher vom Autor Buchempfehlungen Top 99