Aufgaben zum Praktikum Programmieren PRP1

Werbung
Aufgaben zum Praktikum Programmieren PRP1
Prof. Dr. Thomas Klinker
Department Informations- und Elektrotechnik, HAW Hamburg
11. März 2013
1
Programmieren in C - Teil I,
Praktikumsaufgaben,
Prof. Dr. Thomas Klinker
1
Aufgabe 1a:
Geben Sie das Programm auf der nächsten Seite ein, bringen Sie es zum laufen und testen Sie es.
Aufgabe 1b:
Schreiben Sie ein Programm (ganz ähnlich dem in Aufgabe 1a), welches die Höhe h und den Radius r
eines Zylinders einliest und dann die gesamte Oberfläche und das Volumen des Zylinders berechnet.
Aufgabe 1c:
Schreiben Sie ein Programm, welches für eine positive ganze Zahl vom Typ long die Quersumme
berechnet. Die Quersumme von 1339 bespielsweise ist 16.
Programmieren in C - Teil I,
Praktikumsaufgaben,
Prof. Dr. Thomas Klinker
/********************************************************************
Autor:
Datum:
Dateiname:
klk
03.03.03
aufg01a1.cpp
Kurzbeschreibung: Kugelradius einlesen,
Oberfläche und Volumen berechnen,
auf ein Zeichen warten.
Änderungen:
Name
Datum
Kurzbeschreibung
-----------------------------------------------------------------klk
04.03.03
... Beseitigung des Fehlers ....
*********************************************************************/
#include <stdio.h>
#include <math.h>
/* für pow(x, y) */
int main(void)
{
const float pi = 3.1415927;
float radius, oberflaeche, volumen;
printf("Kugelradius in Metern: "); scanf("%f", &radius);
oberflaeche = 4 * pi * radius * radius;
printf("Oberfläche in Quadratmetern: %f\n", oberflaeche);
volumen = (4.0/3) * pi * pow(radius, 3);
printf("Volumen in Kubikmetern: %f\n", volumen);
return 0;
}
2
Programmieren in C - Teil I,
Praktikumsaufgaben,
Prof. Dr. Thomas Klinker
3
Aufgabe 2a:
Schreiben Sie ein Programm, das eine Folge von reellen Zahlen vom Typ float einliest. Das Ende
der Zahlenfolge wird erkannt durch das erste Zeichen, welches keine Zahl (also z.B. ein Buchstabe)
ist.
Das Programm soll dann für die eingelesenen Zahlen folgende Größen berechnen:
1. Die Anzahl der eingelesenen Zahlen,
2. die Summe der eingelesenen Zahlen,
3. das Maximum der eingelesenen Zahlen,
4. das Minimum der eingelesenen Zahlen,
5. den Mittelwert der eingelesenen Zahlen,
6. die Standardabweichung der eingelesenen Zahlen.
Die eingelesenen Zahlen seien mit xi (i = 1, . . . , n) bezeichnet. Der Mittelwert ist dann definiert
durch:
n
P
xi
i=1
x̄ =
.
(1)
n
Für die Standardabweichung gilt:
v
σ=
uP
u n
u (xi − x̄)2
t i=1
n−1
(2)
.
Sie werden feststellen, daß bei der Berechnung der Standardabweichung mit der Formel (2) das Problem auftritt, daß man sich alle eingelesenen Zahlen xi “merken“ (d.h. abspeichern) muß. Man kann
dieses Problem vermeiden, indem man die Standardabweichung mit folgender Formel berechnet
σ=
v
u P
u n 2
x − n · x̄2
u
t i=1 i
n−1
,
(3)
die darüber hinaus für die Bearbeitung von Zahlenfolgen beliebiger Länge geeignet ist.
Aufgabe 2b:
Schreiben Sie ein Programm, das die kartesischen Koordinaten x und y eines Punktes in der Ebene
einliest und sie in Polarkoordinaten r und ϕ (00 < ϕ ≤ 3600 ) umrechnet. Benutzen Sie für die
Berechnung des Winkels ϕ die atan2(y, x)–Funktion von C. Testen Sie Ihr Programm auch für
x = 0.
Umgekehrt soll das Programm auch die Eingabe von Polarkoordinaten gestatten und diese in
kartesische Koordinaten umrechnen gemäß den Formeln
x = r cos ϕ ,
y = r sin ϕ .
Der Winkel ϕ soll dabei jeweils im Gradmaß (00 < ϕ ≤ 3600 ) ausgegeben (bzw. eingelesen) werden.
Programmieren in C - Teil I,
Praktikumsaufgaben,
Prof. Dr. Thomas Klinker
4
Aufgabe 3a:
In dieser Aufgabe soll ein bekanntes Streichholzspiel realisiert werden. Von einer Anfangsmenge
von Streichhölzern nehmen zwei Spieler abwechselnd eins, zwei oder drei Hölzchen weg. Wer das
letzte Hölzchen nehmen muß, hat verloren. Das Programm soll so gestaltet sein, daß ein Spieler
gegen den Computer spielt.
Der Spieler kann dabei bei jedem seiner Zügen nach Gutdünken wahlweise eins, zwei oder drei
Hölzchen nehmen. Die Züge des Computers seien zunächst in einer ersten Version so realisiert,
daß er zufällig eins, zwei oder drei Hölzchen nimmt. Lediglich wenn nur noch vier Hölzchen oder
weniger übrig geblieben sind, spielt der Computer natürlich so, daß er gewinnt. Bei vier Hölzchen
beispielsweise nimmt er drei, damit der Spieler auf dem letzten Hölzchen sitzen bleibt.
Zufallszahlen kann man in C mit der Funktion int rand(void) generieren. Mit der Anweisung
zahl = rand(); wird der Variable zahl eine Zufallszahl zwischen 0 und 32767 zugewiesen. Damit
bei jedem Programmdurchlauf immer eine neue Folge von Zufallszahlen berechnet wird, muss der
Zufallsgenerator einmal (!) am Anfang des Programms initialisiert werden. Dies geschieht mit der
Funktion srand(...) . Mit
#include <stdlib.h>
#include <time.h>
...
time_t t;
srand((unsigned) time(&t));
// Initialisiert den Zufallsgenerator
// am Anfang des Prgramms (!)
...
zahl = (rand() % 3) + 1;
...
// Erzeugt Zufallszahl zwischen 1 und 3
könnte man somit beispielsweise Zufallszahlen zwischen 1 und 3 erzeugen. Achten Sie darauf, daß
auch der Spieler immer nur eins, zwei oder drei Hölzchen nehmen darf, nicht mehr und nicht
weniger.
Wenn Ihr Programm läuft, denken Sie nun einmal darüber nach, wie eine optimale Strategie für
den Computer aussieht. Der Computer soll also in einer verbesserten Version Ihres Programms von
Beginn an stehts den optimalen Zug ausführen. Er soll also immer so ziehen, daß er, wenn er die
Chance zu gewinnen hat, diese auch nutzt.
Die Darstellung auf der Console könnte dann z.B. wie folgt aussehen:
Die aktuelle Anzahl der Hoelzchen ist: 13
*
I
I
I
*
I
I
I
*
I
I
I
*
I
I
I
*
I
I
I
*
I
I
I
*
I
I
I
*
I
I
I
*
I
I
I
*
I
I
I
*
I
I
I
*
I
I
I
*
I
I
I
Wieviele Hoelzchen nehmen Sie? (1, 2, 3):
Programmieren in C - Teil I,
Praktikumsaufgaben,
Prof. Dr. Thomas Klinker
5
Aufgabe 3b:
Schreiben Sie ein Programm, das das Pascalsche Dreieck berechnet. Im Pascalschen Dreieck sind
die Binominalkoeffizienten
!
n!
n
(4)
=
m
(n − m)! m!
pyramidenförmig angeordnet.
1
1
1
2
1
1
1
1
1
3
4
5
6
1
3
6
10
15
1
4
1
10
20
5
1
15
6
1
Statt mit Gl. (4) lassen sich die Binominalkoeffizienten für alle n ≥ 0 und m = 0, . . . , n schneller
nach folgenden Formeln berechnen:
n
0
!
n
m
!
=
n
n
!
= 1
=
n−1
m−1
!
+
n−1
m
!
m = 1, . . . , n − 1 .
,
Benutzen Sie diese Formeln und verwenden Sie zur Speicherung der Binominalkoeffizienten ein
zweidimensionales Feld b[n][m], so daß gilt
b[n][m] =
n
m
!
.
(5)
Programmieren in C - Teil I,
Praktikumsaufgaben,
6
Prof. Dr. Thomas Klinker
Aufgabe 4:
Im Jahr 1968 wurde von J. H. Conway an der Universität Cambridge das “game of life“ erfunden und
1970 von M. Gardner im Scientific American einem breiten Publikum vorgestellt. Dabei handelt
es sich um einen Algorithmus, der das Wachstum von fiktiven Lebewesen (Bakterien) simuliert.
Infolge der interessanten Muster, die dabei entstehen, ist das game of life weit über Biologenkreise
hinaus bekannt geworden. Es ist ein Beispiel für einen sogenannten zellulären Automaten.
Schauplatz des game of life ist ein zweidimensionales Gitter aus Zellen, die entweder tot (’ ’) oder
lebendig (’X’) sind. Wie sich eine Zelle weiter entwickelt, hängt von ihren acht Nachbarn ab, und
zwar gelten folgende Regeln:
1. Eine lebende Zelle überlebt in der nächsten Generation, wenn sie zwei oder drei Nachbarn
hat. Sind es weniger bzw. mehr, so stirbt sie an Vereinsamung bzw. Überbevölkerung.
2. Eine tote Zelle wird immer dann in der nächsten Generation zum Leben erweckt, wenn sie
genau drei lebendige Nachbarn hat, ansonsten bleibt sie tot.
Die Zeit verstreicht dabei in diskreten Schritten, d.h. jede Zelle verharrt in ihrem zuvor eingenommenen Zustand, bis gewissermaßen bei einem Gongschlag alle gleichzeitig in den neuen Zustand
übergehen. Anders ausgedrückt: Es wird für jede Zelle nachgeschaut, wie ihr Zustand und der ihrer
Nachbarn zu einer bestimmten Zeit n ist und berechnet, wie ihr Zustand zur nächsten Zeit n + 1
sein wird. Hat man dies für alle Zellen getan, so werden alle gleichzeitig auf den neuen Zustand
gesetzt. In der abschliessenden Version sollte Ihr Programm periodische Randbedingungen für das
zweidimensionale Feld benutzen (genauere Erklärung hierzu und Vorschläge zur Realisierung in der
Vorlesung).
Gestalten sie das Programm so, daß man als Ausgangsmuster entweder eins der folgenden fünf
auswählen kann, oder über die Angabe der Koordinaten (Zeile, Spalte) ein eigenes Ausgangsmuster
lebendiger Zellen eingeben kann.
XXX
Blinker
XX
XX
Block
X
X X
X X
X
Bienenstock
XX
X
XX
X X
X
Leuchtfeuer
Gleiter
X
XX
Jede neue Generation soll auf dem Bildschirm ausgegeben werden, wobei die vorhergehende Generation immer durch die aktuelle überschreiben werden soll. Um dieses einfach bewerkstelligen zu
können, werden Ihnen zwei Dateien zur Verfügung gestellt, console.h und console.cpp , die
Sie Ihrem Projekt hinzufügen müssen. Damit verfügen Sie über folgende Funktionen:
bool setCursor(int zeile, int spalte)
/* Funktion, die Cursor auf die angegebene Position (zeile, spalte) setzt.
bool cls()
/* Funktion, die Consolen-Puffer mit aktuellem Attribut löscht
/* und Cursor auf die Home-Position (0,0) setzt (clear screen).
*/
*/
*/
Programmieren in C - Teil I,
Praktikumsaufgaben,
void cursorOff()
/* Funktion, die den Cursor unsichtbar macht.
Prof. Dr. Thomas Klinker
7
*/
void cursorOn()
/* Funktion, die den Cursor wieder sichtbar macht. */
DWORD cursorSize(DWORD size)
/* Funktion, die die CursorGröße setzen kann (in Prozent).
*/
Wählen sie für das game of life ein Feld der Größe: 22 Zeilen und 78 Spalten. Über dem Feld
sollte die Nummer der aktuellen Generation angezeigt werden. Auf diese Weise wird die Größe
des Bildschirms gut ausgenutzt. Die Größe des Konsolen-Fensters kann allerdings auch geändert
werden. (Weitere Hinweise in der Vorlesung).
Das fortlaufende Anzeigen immer neuer Generationen kann wahweise durch das Drücken einer Taste
erfolgen oder automatisch durch die folgende Schleifenkonstruktion
while(!_kbhit())
{
statement;
...
}
// Weitermachen, bis irgendeine Taste gedrueckt wird
Hierbei werden die neuen Generationen automatisch angezeigt, bis irgendeine Taste gedrückt wird.
Damit die Generationen nicht zu schell nacheinander angezeigt werden, verwenden Sie bei obiger Schleifenkonstruktion die Funktion Sleep(n) (deklariert im Headerfile <windows.h>), die eine
Verzögerung des Programmablaufs um n Millesekunden bewirkt.
Wer noch Lust hat, mit dem Programm etwas zu spielen, kann folgende Anfangskonfiguration
eingeben, die als Gleiterkanone bezeichnet wird.
6
7
8
9
0
1
X
2
X X
3
X
XX
X
4 XX
X
XX
XXXX
X
5 XX
X
XX
XXXX
X
6
X X
X X
XX
7
X
XXXX
XX
8
XXXX
9
X
0
123456789012345678901234567890123456789012345678901234567890123456789
Die Gleiterkanone wurde 1970 entdeckt von R. W. Gosper, der damals Student am Massachusetts
Institut of Technologie (MIT) war, und sich unbedingt den 50-Dollar-Preis verdienen wollte, den
Programmieren in C - Teil I,
Praktikumsaufgaben,
Prof. Dr. Thomas Klinker
8
Conway ausgelobt hatte. Den Preis sollte der erhalten, der als erster beweisen würde, daß eine
Ausgangsstellung unbegrenzt wachsen kann. Gospers Gleiterkanone spuckt jeweils nach 30 Zeitschritten einen neuen Gleiter aus, wobei sie selbst in den Ausgangszustand zurückkehrt. Auf der
Basis der Gleiterkanone lassen sich logische Gatter, also NOT-, AND- und OR-Gatter und damit
auch Rechner konzipieren.
Herunterladen