So, ich habe mir mal kräftig Gedanken gemacht und nochmal den Ursprungspost durchgelesen. Damit ich mich nicht völlig vergallopiere, hier mal ein paar grundlegende Anmerkungen dazu:
Wenn es um eine reine Schleifenprogrammierung geht, dann kann man ein komplexes Labyrinth vollständig vergessen. Das Zurechtfinden in einem Labyrinth inkl. Backtrackings ist schon ordentliche Programmierung und geht über ein simples Schleifenkonstrukt weit hinaus. Einfachste Formationen, wie z.B. diese Spirale können auch mit einer Schleife aufgelöst werden, aber bereits hier sind Variablen angebracht (wenn auch noch nicht zwingend notwendig). Ich habe mir das Niki-Programm gezogen und in der Hilfe gelesen, daß Variablen darin nicht verwendet werden können. Da du von einem "Lehrer" geschrieben hast, gehe ich mal davon aus, daß die Aufgabe ca. Schulniveau hat. Was bedeutet, daß vollständiges Backtracking wohl rausfällt.
Das grundlegende Problem ist, daß wir eine Komplettübersicht über das Labyrinth haben (durch die Draufsicht), der Roboter jedoch nicht. Somit würde der Roboter theoretisch eine Art künstliches Gedächtnis benötigen, um sich seinen Weg durch ein richtiges Labyrinth zu merken (ganz abgesehen von den Tatsachen, daß Labyrinth nicht gleich Labyrinth ist und es auch mehrere verschiedene Methoden gibt, um Labyrinthe zu knacken) und so etwas zu programmieren ist - abhängig von der Aufgabenstellung - nicht unbedingt trivial und innerhalb der Niki-Umgebung aufgrund der fehlenden Variablen nicht umsetzbar.
Also gehe ich jetzt mal von zwei möglichen Aufgabenstellungen aus:
1. Der Roboter soll schleifengesteuert einfach das gesamte Feld abfahren, alles einsammeln, was er findet und dann das Zeug an einem bestimmten Punkt abliefern.
2. Der Roboter soll einen bestimmten, durch Wände begrenzten Weg abfahren können, der Rest analog zu 1.
Das allererste, was ich bei so einer Entwicklung mache, ist, mir erstens Gedanken zu machen, was genau das Problem ist und welche Möglichkeiten mir zur Verfügung stehen. Ich gehe mal exemplarisch Aufgabe 1 durch.
Was habe ich also?
Ich habe:
- eine Arena, die am Rand begrenzt ist und innerhalb derer sich der Roboter bewegt.
- einen Roboter mit sehr eingeschränktem Befehlssatz und ziemlich eingeschränkten Sensoren.
- ein Feld (rechts unten), auf dem die "Beute" hinterher abzuliefern ist.
- die Anforderung, daß alle Einzelfelder der Arena angefahren, untersucht und leergegrast werden müssen.
Nicht gerade viel. Vielleicht fällt auf, daß von einer
Anfangsposition des Roboters keine Rede ist, die nehme ich also nicht als gegeben hin.
Was ich also brauche ist:
- eine ordentliche Anfangsposition
- ein Muster, wie ich die Arena durchlaufen will
- eine Möglichkeit, zum Zielfeld zu kommen
Damit lässt sich schon mal ein bißchen Rumpfcode schreiben:
Code:
PROGRAM Variante1;
PROCEDURE drehe_rechts;
BEGIN
drehe_links;
drehe_links;
drehe_links;
END;
PROCEDURE drehe_um;
BEGIN
drehe_links;
drehe_links;
END;
BEGIN
END.
Nichts weltbewegendes. Ich kenne deine Unit "dema" nicht, aber da dürfte wohl ähnliches drin stehen.
Erstmal will ich die Anfangsposition festlegen. Ich möchte, daß der Roboter grundsätzlich links unten steht und nach Norden schaut, bevor er anfängt, die Arena abzulaufen. Und genau das mache ich auch so. Ich bringe den Roboter nach links,
Code:
WHILE NOT westwaerts DO drehe_links;
WHILE vorne_frei DO vor;
dann nach unten
Code:
drehe_links;
WHILE vorne_frei DO vor;
und drehe ihn schließlich so, daß er wieder nach Norden schaut.
Das Ganze wird in eine Prozedur verpackt, die ich dann aufrufen kann und die mir jederzeit dafür sorgt, daß der Roboter nach links unten gebracht wird, egal wo er steht/stand und welche Ausrichtung er hat/te:
Code:
PROCEDURE Niki_nach_links_unten;
BEGIN
WHILE NOT westwaerts DO drehe_links;
WHILE vorne_frei DO vor;
drehe_links;
WHILE vorne_frei DO vor;
drehe_um;
END;
Da es um Schleifenkonstrukte geht, hast du hier schon mal die ersten drei Schleifen:
1. Den Roboter drehen, bis er nach Westen schaut.
2. Vorwärts, bis es nicht mehr weiter geht.
3. Nochmal vorwärts, bis es nicht mehr geht.
Bei allen drei Schleifen ist auch schön die Abbruchbedingung zu sehen. "Mache etwas
bis". Alternativ dazu gibt es auch "Mache etwas
solange".
Ok, weiter geht's. Mit Hilfe von Niki_nach_links_unten kann ich jetzt also immer von einer festen Ausgangsposition ausgehen und dementsprechend den Weg durch die Arena planen. Am einfachsten erscheint es mir, so vorzugehen:
- Von Süden nach Norden fahren bis zum Anschlag.
- Umdrehen (und dabei eine Reihe weiter nach rechts rutschen).
- Von Norden nach Süden fahren bis zum Anschlag.
- Umdrehen (und dabei eine Reihe weiter nach rechts rutschen).
- Das Ganze so oft wiederholen, bis es nicht mehr geht.
Das Schwammigste an diesen ganzen Formulierungen ist die Abbruchbedingung "bis es nicht mehr geht". Woran lässt sich erkennen, daß "es nicht mehr geht"?
Wenn ich mir einfach die Arena betrachte und den Weg anschaue, den der Roboter zurück legen würde, so käme er am Schluß rechts oben raus mit einer Nordausrichtung. Das ist das letzte Feld, das er erreichen kann. Aber genau durch diese Charakteristiken kann ich dieses Feld erkennen:
- Ausrichtung des Roboters nach Norden
- Er kann nicht mehr weiter nach Norden fahren
- Zur Rechten des Roboters ist eine Wand.
Das schwammige "bis es nicht mehr geht" kann ich also auflösen in
Code:
... nordwaerts AND NOT vorne_frei AND NOT rechts_frei
Jetzt kann ich schon anfangen die große Schleife zu formulieren, die da lautete "Mache das alles, bis es nicht mehr geht":
Code:
REAPEAT
BEGIN
END
UNTIL nordwaerts AND NOT vorne_frei AND NOT rechts_frei;
Jetzt füge ich alles mal ein bißchen in das Programm ein, welches dann so aussieht:
Code:
PROGRAM Variante1;
PROCEDURE drehe_rechts;
BEGIN
drehe_links;
drehe_links;
drehe_links;
END;
PROCEDURE drehe_um;
BEGIN
drehe_links;
drehe_links;
END;
PROCEDURE Niki_nach_links_unten;
BEGIN
WHILE NOT westwaerts DO drehe_links;
WHILE vorne_frei DO vor;
drehe_links;
WHILE vorne_frei DO vor;
drehe_um;
END;
BEGIN
Niki_nach_links_unten;
REPEAT
BEGIN
END
UNTIL nordwaerts AND NOT vorne_frei AND NOT rechts_frei;
Niki_nach_Links_unten;
END.
Das zweite Niki_nach_links_unten ist drin, damit ich nach getaner Arbeit den Roboter wieder "nach Hause" schicken kann.
So. Was sollte der Roboter machen, solange er unterwegs ist? Genau. Alles aufsammeln.
Code:
IF Platz_belegt THEN nimm_auf;
Aber Moment! Durch diese Anweisung nimmt der Roboter genau
einmal etwas von dem Feld auf, auf dem er steht. Er soll aber alles aufheben. Das lässt sich auch so formulieren: "Solange etwas da ist, nimm es auf". Und da ist schon wieder das magische Wort "solange", mit dem sich eine Schleifenbedingung formulieren lässt:
Code:
WHILE Platz_belegt DO nimm_auf;
Wenn das Feld abgegrast ist, dann soll der Roboter ein Feld vorfahren. Aber was ist, wenn er den Rand erreicht (entweder den Nord- oder den Südrand)? Dann kann er ja nicht mehr weiter vorwärts. Als entweder kann er fahren oder nicht. Zwei Möglichkeiten. Das schreit geradezu nach einem IF...THEN...ELSE:
Code:
IF vorne_frei THEN vor
ELSE
ELSE... ja, else was? Wenn er nicht vorwärts fahren kann, dann soll er eine kleine Kurve fahren. Davon gibt es zwei, zum einen, wenn er an den Nordrand stößt, zum anderen beim Südrand.
Hier mal die Formulierung für die Kehre, wenn der Roboter an den Nordrand gestoßen ist:
Code:
drehe_rechts;
vor;
drehe_rechts;
Für den Südrand sieht es ähnlich aus und der Ordnung halber packe ich diese beiden Vorgänge in eigene Prozeduren:
Code:
PROCEDURE Kehre_rechtsrum;
BEGIN
drehe_rechts;
vor;
drehe_rechts;
END;
PROCEDURE Kehre_linksrum;
BEGIN
drehe_links;
vor;
drehe_links;
END;
Prima. Wenn der Roboter also nicht mehr weiter nach vorne fahren kann, dann muß ich nur schauen, ob er von Norden nach Süden unterwegs war oder umgekehrt und muß die entsprechende Kehre durchführen:
Code:
IF nordwaerts THEN Kehre_rechtsrum
ELSE Kehre_linksrum;
Und damit habe ich schon meine Hauptarbeitsschleife:
Code:
REPEAT
BEGIN
WHILE Platz_belegt DO nimm_auf;
IF vorne_frei THEN vor
ELSE
IF nordwaerts THEN Kehre_rechtsrum
ELSE Kehre_linksrum;
END
UNTIL nordwaerts AND NOT vorne_frei AND NOT rechts_frei;
Wenn der Roboter seine Arbeit getan hat, ist er mit Nordausrichtung in der rechten oberen Ecke. Seine Beute soll er aber rechts unten abladen. Daher lasse ich ihn noch da hin fahren, bevor aller Schotter abgeworfen wird:
Code:
drehe_um;
WHILE vorne_frei DO vor;
WHILE hat_Vorrat DO gib_ab;
Fertig.
Das komplette Programm sieht dann so aus:
Code:
PROGRAM Variante1;
PROCEDURE drehe_rechts;
BEGIN
drehe_links;
drehe_links;
drehe_links;
END;
PROCEDURE drehe_um;
BEGIN
drehe_links;
drehe_links;
END;
PROCEDURE Niki_nach_links_unten;
BEGIN
WHILE NOT westwaerts DO drehe_links;
WHILE vorne_frei DO vor;
drehe_links;
WHILE vorne_frei DO vor;
drehe_um;
END;
PROCEDURE Kehre_rechtsrum;
BEGIN
drehe_rechts;
vor;
drehe_rechts;
END;
PROCEDURE Kehre_linksrum;
BEGIN
drehe_links;
vor;
drehe_links;
END;
BEGIN
Niki_nach_links_unten;
REPEAT
BEGIN
WHILE Platz_belegt DO nimm_auf;
IF vorne_frei THEN vor
ELSE
IF nordwaerts THEN Kehre_rechtsrum
ELSE Kehre_linksrum;
END
UNTIL nordwaerts AND NOT vorne_frei AND NOT rechts_frei;
drehe_um;
WHILE vorne_frei DO vor;
WHILE hat_Vorrat DO gib_ab;
Niki_nach_links_unten;
END.
Ich hoffe, ich konnte dir damit etwas mehr Verständnis für Programmentwicklung und Schleifenkonstrukte geben. Variante 2 mit der Spirale kannst du dir ja selber ausknobeln.
