Weitere Aufgaben
Der Hamster steht im Tal und will einen vor sich liegenden Berg erklimmen. Leider weiß er nicht, nach wie vielen Schritten der Berg beginnt, und ebenso wenig, wie hoch der Berg ist. Auf dem Gipfel befindet sich ein Gipfel-Korn.
![]() |
![]() |
| Hoher Berg | Mittelhoher Berg |
Schreibe ein Programm, welches den Hamster einen beliebig weit entfernten und beliebig hohen Berg erklimmen lässt.
Fortgeschritten: Der Hamster wird immer erfahrener im Bergsteigen: Er kann nun auch Berge ersteigen, die nicht immer konstant nach oben führen ($100\%$ Steigung), sondern die zwischendurch Plateaus haben können.
Die Aufgabe lässt sich in zwei Teilaufgaben aufspalten, die hintereinander gelöst werden müssen:
void main()
{
// 1. Zum Berg laufen
// 2. Berg erklimmen
}
Für Teilaufgabe 2. könntest du dir noch eine Prozedur erklimmeStufe definieren.
Für beide Teilaufgaben 1. und 2. benötigst du eine while-Schleife.
Überlege dir bei Teilaufgabe 2, welche Schleifenbedingung du wählen kannst. Du könntest z.B. prüfen, ob das Gipel-Korn noch nicht erreicht wurde (und in diesem Fall weiterklettern).
void main()
{
// 1. Zum Berg laufen
while (vornFrei())
{
vor();
}
// 2. Berg erklimmen
while (!kornDa())
{
erklimmeStufe();
}
}
void erklimmeStufe()
{
linksUm();
vor();
rechtsUm();
vor();
}
void rechtsUm()
{
linksUm();
linksUm();
linksUm();
}
Der Hamster soll ein komplettes Kornfeld abgrasen und seine Beute am Startpunkt ablegen. Auf jeder Kachel befindet sich maximal ein Korn.


Verwende eine while-Schleife mit der Bedingung vornFrei(). Der Unterschied zur Laufhamster-Aufgabe ist nun lediglich, dass der Hamster vor dem Vorwärtsschritt noch prüfen muss, ob er sich auf einem Korn befindet und dieses gegebenenfalls essen muss. An dieser Stelle muss also eine if-else-Fallunterscheidung in den Rumpf der while-Schleife geschachtelt werden.
Die grobe Struktur des Programms sieht wie folgt aus. Die Zeilen mit // TODO müssen noch ersetzt werden durch passende Befehle.
void main()
{
while (vornFrei())
{
if (kornDa())
{
// TODO
}
// TODO
}
// TODO
}
// Abgras-Hamster v1
// -----------------
// Dieses Programm laesst den Hamster eine Reihe ab-
// grasen. Auf jedem Feld wird ein Korn aufgenommen,
// sofern sich dort eines befindet. Auf dem Start-
// feld werden abschliessend alle Koerner abgelegt.
void main()
{
// 1. Alle Koerner einsammeln
while (vornFrei())
{
vor();
// Nimm ein Korn nur dann, falls vorhanden
sicheresNimm();
}
// 2. Nun zurueck zum Reihenanfang.
kehrt();
while (vornFrei())
{
vor();
}
// 3. Beute ablegen
while (!maulLeer())
{
gib();
}
}
// Mit "sicher" ist gemeint, dass nur dann ein Korn
// aufgenommen wird, wenn eines vorhanden ist. Dies
// verhindert also einen Programmabsturz bei Ausführung
// eines `nimm`-Befehls bei Abwesenheit eines Korns.
void sicheresNimm()
{
if (kornDa())
{
nimm();
}
}
void kehrt()
{
linksUm();
linksUm();
}
void rechtsUm()
{
linksUm();
linksUm();
linksUm();
}
Wieder soll der Hamster ein komplettes Kornfeld abgrasen. Diesmal soll er auf jeder Kachel jedoch alle Körner einsammeln (statt nur bis zu ein Korn, wie bei der letzten Aufgabe).


Verwende zwei ineinander verschachtelte while-Schleifen. Solange vorne frei ist, soll Folgendes getan werden: Solange ein Korn da ist, soll dieses genommen werden.
// Abgras-Hamster v2
// -----------------
// Dieses Programm laesst den Hamster eine Reihe ab-
// grasen. Auf jedem Feld werden alle Koerne auf-
// genommen, die sich dort befinden. Auf dem Start-
// feld werden abschliessend alle Koerner abgelegt.
void main()
{
// 1. Alle Koerner einsammeln
while (vornFrei())
{
vor();
// Nimm in jedem Schritt alle Koerner.
nimmAlle();
}
// 2. Nun zurueck zum Reihenanfang.
kehrt();
while (vornFrei())
{
vor();
}
// 3. Beute ablegen
while (!maulLeer())
{
gib();
}
}
// Diese Prozedur veranlasst das Nehmen so vieler
// Koerner, wie vorhanden sind.
void nimmAlle()
{
while (kornDa())
{
nimm();
}
}
void kehrt()
{
linksUm();
linksUm();
} Wieder soll der Hamster ein komplettes Kornfeld abgrasen. Diesmal jedoch ein beliebig großes Feld!


Es gibt verschiedene Strategien, das Feld abzuräumen. Am effizientesten ist es natürlich, im Slalom nach unten zu wandern. Im Folgenden wird eine naive Strategie vorgestellt, die einfacher zu programmieren ist: Der Hamster nimmt sich immer eine Zeile vor, läuft diese nach rechts und dann zurück nach links, und macht anschließend mit der nächsten Zeile weiter.
-
graseReiheAbDer Hamster muss bei Prozeduraufruf nach Süden hin ausgerichtet sein. Er dreht sich nun nach links und geht bis zum Zeilenende, dabei alle Körner aufnehmend. Dann dreht er sich um und läuft wieder zurück. Abschließend dreht er sich in Richtung Süden.
Der Hamster steht am Ende der Prozedur am gleichen Punkt mit gleicher Blickrichtung wie zu Beginn der Prozedur.
-
nimmAlleAlle Körner auf der aktuellen Kachel fressen
Die main-Prozedur ist nun einfach zu schreiben. Zunächst muss die Standard-Blickrichtung, nämlich Süden, eingenommen werden.
Nun wird die erste Reihe abgegrast (graseReiheAb).
So lange dann noch vorne frei ist, wird 1. nach vorne gegangen und dann 2. eine Reihe abgegrast.
Abschließend müssen wir nur noch zurücklaufen und die Beute ablegen.
// Abgras-Hamster v3
// -----------------
// Dieses Programm laesst den Hamster alle Reihen ab-
// grasen. Auf jedem Feld werden alle Koerne auf-
// genommen, die sich dort befinden. Auf dem Start-
// feld werden abschliessend alle Koerner abgelegt.
void main()
{
// 1. Nach Sueden wenden.
rechtsUm();
// 2. Erste Reihe abgrasen
graseReiheAb();
// 3. Weitere Reihen abgrasen
// Der Hamster soll nun so lange gen Sueden laufen,
// wie es Reihen gibt. Jede Reihe, die er passiert,
// soll er dabei abgrasen.
while (vornFrei())
{
vor(); // Reihe wechseln
graseReiheAb();
}
// 4. Heimweg nach Norden antreten
kehrt();
while (vornFrei())
{
vor();
}
// 5. Beute ablegen
while (!maulLeer())
{
gib();
}
}
// Die Anweisungen dieser Prozedur befanden sich
// urspruenglich (in v1 und v2) in der `main`-Prozedur.
// Da wir nun aber mehrere Reihen abgrasen wollen,
// definieren wir uns diese wiederverwendbare Prozedur.
void graseReiheAb()
{
// (i) Nach Osten wenden
linksUm();
// (ii) Alle Koerner einsammeln
nimmAlle();
while (vornFrei())
{
vor();
// Nimm in jedem Schritt alle Koerner.
nimmAlle();
}
// (iii) Nun zurueck zum Reihenanfang.
kehrt();
while (vornFrei())
{
vor();
}
// (iv) Zurueck nach Sueden drehen
linksUm();
}
// Diese Prozedur veranlasst das Nehmen so vieler
// Koerner, wie vorhanden sind.
void nimmAlle()
{
while (kornDa())
{
nimm();
}
}
void kehrt()
{
linksUm();
linksUm();
}
void rechtsUm()
{
linksUm();
linksUm();
linksUm();
} 
