|
|
||||||||||||||||
0. Inhaltsverzeichnis 2. Das Divide-and-Conquer-Prinzip 3. Das Backtracking-Prinzip
3.2 Das Königsberger Brückenproblem 3.3 Das Labyrinth
3.3.2 Probleme 3.3.3 Einordnung in den Unterricht 3.3.4 Stellen der Aufgabe 3.3.5 Analyse und Struktur
3.3.5.2 Möglichkeiten der Reihenfolge der Erkundung des Labyrinths 3.3.5.3 Der rekursive Algorithmus 3.3.5.4 Besonderheiten des Startfeldes 3.3.5.5 Variablen, Parameterübergabe 3.3.5.6 Drei zu erkundende Felder - Schleife oder Einzelaufruf? 3.3.5.7 Die Schleife 3.3.5.8 Die gesamte Prozedur 3.3.5.9 Die Startprozedur 3.3.5.10 Das Programm 3.3.7 Labyrinthe |
||||||||||||||||
3.3 Das Labyrinth3.3.1 Vergleich des Labyrinths mit anderen Backtracking-BeispielenVon den vorn genannten Beispielen für das Backtracking-Verfahren ist die Labyrinth-Problematik besonders geeignet, um in das Thema einzuführen.
Suche einen Weg zu jedem Ausgang Suche alle Wege zu einem Ausgang Suche alle Wege zu allen Ausgängen Suche den kürzesten Weg zu einem Ausgang und mehr
|
||||||||||||||||
3.3.2 Probleme
|
||||||||||||||||
3.3.3 Einordnung in den Unterricht3.3.3.1 VoraussetzungenWie in 3.3.1 beschrieben, ist das Labyrinth-Problem in seinem Kern gut für einen zeitigen Einsatz geeignet, also als erstes Programm mit Backtracking-Prinzip. Die rekursive Programmierung sollte allerdings vorher eingeführt worden sein, um keine Gleichheit zu assoziieren.Weitere notwendige Voraussetzungen sind das zweidimensionale Array und das Einlesen von Dateien. Um die Gesamtaufgabe nicht unnötig komplex zu gestalten, ist es aber denkbar, die Initialisierungsprozedur bereitzustellen. program labyrint;
const LABFILE = 'test.lby';
type TLabElement = (Mauer,
var Laby : array[1..MAXLAENGE,
1..MAXBREITE] of TLabElement;
procedure Schreibe(x, y : shortint);
function Labyrinth: boolean;
{ Initialisierung }
procedure SucheAusgang;
{Main}
Listing: lab_init.pas
|
||||||||||||||||
3.3.3.2 NachnutzungDie Eignung als Prüfungsthema soll hier nicht untersucht werden. Es sei lediglich darauf hingewiesen, dass die vielfältige Abwandelbarkeit Möglichkeiten eröffnet.Mit der Einführung von Schleifen in das Labyrinth läßt sich das Thema Optimierungsstrategien behandeln. Die Ablösung der Pseudografik durch echte Grafik eröffnet ein weites Feld. Das Thema ist auch geeignet, um bei der Einführung neuer Strukturen deren Vorteile darzustellen, z.B.:
|
||||||||||||||||
3.3.4 Stellen der AufgabeWir gehen von einem Labyrinth aus, bei dem Wege und Mauern gleich dick sind. Der Ausgangspunkt liegt im Innern des Labyrinths, die Ziele am Rand. Es ist zu prüfen, ob es einen Weg nach draußen gibt. Wenn es einen gibt, ist er zu beschreiben.Wird die Aufgabe zur Einführung des Backtrackings verwendet, läßt sich das Prinzip erklären, indem die Bildschirmausgabe des fertigen Programms mit einem geeigneten Labyrinth gezeigt wird. Für den Anfang empfiehlt sich ein Labyrinth ohne Schleifen, so dass der Weg nicht protokolliert werden muss. Auch die Ausgänge kann man anfangs verbauen, so dass man sie
2. das gesamte Labyrinth durchlaufen wird. |
||||||||||||||||
3.3.5 Analyse und Lösung3.3.5.1 Die ProgrammstrukturNeben dem Ariadne-Faden gibt es noch andere Möglichkeiten der gegenständlichen Beschreibung der Aufgabe, zum Beispiel folgende:
Beschreibung (Protokoll) Zur Anzeige enthält die Typdeklaration TLabElement neben den Bezeichnern Mauer, Start, Ausgang und Weg noch Gang (erkundeter Weg) und Pfad (Ariadne-Faden). Zur Entwicklung des Algorithmus wählt man einen kleinen Ausschnitt. Bei der Analyse der Erkundung sollte man herausarbeiten, dass der "Roboter" nur die unmittelbare Umgebung erkunden kann und demzufolge auf jedem neu betretenen Feld die gleiche Erkundung ausführen muss. Es ist möglich, dass Schüler eine Repeat-Schleife vorschlagen, welche dann auf jedem Feld durchlaufen wird. Man kann einwenden, dass dann eine Speicherung des Weges erforderlich ist. Gewichtiger ist wohl als Argument, dass durch die vielen Verzweigungen schnell der Überblick verloren geht. Um den Gedanken zur Rekursion zu lenken, sollte man das Bild vom Faden aufgreifen oder das Bild vom Roboter dahingehend weiterentwickeln, dass man erklärt, dass der Roboter sich seine Position sehr einfach merken kann, indem er seinen Platz nicht verläßt. Das Erkunden der nächsten Position überträgt er einfach einem neuen Roboter, damit hat man einen rekursiven Aufruf. |
||||||||||||||||
3.3.5.2 Möglichkeiten der Reihenfolge der Erkundung des LabyrinthsIch kann mir 3 Varianten vorstellen:A Immer an der Wand entlang
B Windrose
C Trial and error Das ist kein Backtracking und soll hier nicht weiter betrachtet werden.
|
||||||||||||||||
3.3.5.3 Der rekursive AlgorithmusDie Erkundung muss folgendes leisten:Variante A (aus 3.3.5.2): Variante B: gleichwertig ist: Die "magere" Variante A hat dann aber immer noch ein Problem bei Schleifen im Labyrinth, deshalb ist auch bei "Immer an der Wand lang" Variante B zu empfehlen. Auf "Pfad" kann man verzichten, es dient lediglich der Visualisierung. |
||||||||||||||||
3.3.5.4 Besonderheiten des StartfeldesDas Startfeld behält in der Ausgabe seine Farbe, hier darf also die Prozedur 'Schreibe' nicht ausgeführt werden. Vor allem muss aber vom Startfeld in alle 4 Richtungen erkundet werden. Deshalb erhält das Startfeld eine eigene Prozedur 'SucheAusgang', aus der dann die Rekursion 'Erkunde' gestartet wird.Hier könnte man auch noch den Fall behandeln, dass das Startfeld am Rand liegt. |
||||||||||||||||
3.3.5.5 Variablen, ParameterübergabeNatürlich benötigt die Prozedur die Koordinaten x,y des zu erkundenden Feldes als Rekursionsparameter. Bei Variante A muss darüber hinaus erkennbar sein, aus welcher Richtung man zu diesem Punkt gelangt ist. Diese kann man in Form eines zweiten Koordinatenpaares übergeben. |
||||||||||||||||
3.3.5.6 Drei zu erkundende Felder - Schleife oder Einzelaufruf?Schüler, die vom Mathematik-Profilkurs das Thema "Drehung in Polarkoordinaten" kennen, wissen vielleicht, dass hier eine Schleife möglich ist. Andere werden sich eher fragen, wozu bei lediglich 3 bis 4 Durchläufen eine Schleife nützlich ist.Argumente für die Schleife:
|
||||||||||||||||
3.3.5.7 Die SchleifeDieprocedure Erkunde(X, Y, NebenX, NebenY : shortint); hat die Aufgabe, die Umgebung des Feldes (X,Y) zu erkunden, wobei der Aufruf aus (NebenX, NebenY) erfolgte. Mit var Temp, i : shortint; stehen 2 Variable bereit. i ist eine Zählvariable, die Variable Temp wird zur Berechnung benötigt. Initialisierung: In Variante A ist keine Initialisierung erforderlich, da die Werte übergeben werden. Dies ist auch der Grund dafür, dass in allen nachfolgenden Beispielen erst zum nächsten Feld gewechselt wird und dieses dann erkundet wird. Variante B: West NebenX := X - 1; NebenY := Y; Schleifentyp: For-To, Var. A: 3, Var. B: 4 Schleifendurchläufe Berechnung von NebenX, NebenY: Wie aus der Tabelle erkennbar ist, lassen sich NebenX und NebenY berechnen, nachdem der alte Wert von NebenX in Temp := NebenX; festgehalten wurde: NebenX := NebenX - (NebenX - X) - (NebenY - Y); NebenY := NebenY + ( Temp - X) - (NebenY - Y); Jedes Nebenfeld ist dann zu erkunden. Erkunde(NebenX,NebenY,X,Y); Ergänzt wird die Prozedur durch einige Befehle zu Darstellungs- und Testzwecken, die natürlich auch entfallen können. WINDROSE, TEST und WARTE sind Konstanten, MeldeGefunden(X,Y) eine nach eigenem Gutdünken gestaltbare Prozedur. |
||||||||||||||||
3.3.5.8 Die gesamte ProzedurDie gesamte Prozedur kann dann folgendermaßen aussehen:procedure Erkunde(X, Y, NebenX, NebenY
: shortint);
Wie in 3.3.5.3 erwähnt, ist die folgende Prozedur gleichwertig: procedure Erkunde(X, Y, AltX, AltY : shortint);
Diese Prozedur enthält außerdem zusätzliche Variablen
und andere Bezeichner zwecks leichterer Verständlichkeit.
|
||||||||||||||||
3.3.5.9 Die StartprozedurWie in 3.3.5.4 dargestellt, braucht das Startfeld eine eigene Prozedur (Dies kann auch das Hauptprogramm sein). Nach 'Erkunde' ergibt sich 'SucheAusgang' problemlos. |
||||||||||||||||
3.3.5.10 Das ProgrammDas Programm sieht dann etwa folgendermaßen aus:program labyrint;
const TEST = true;
type TLabElement = (Mauer,
var Laby : array[1..MAXLAENGE,
1..MAXBREITE] of TLabElement;
procedure Schreibe(X, Y : shortint);
function Labyrinth: boolean;
{ Initialisierung }
procedure MeldeGefunden(X, Y: shortint);
procedure Erkunde(X, Y, AltX, AltY : shortint);
procedure SucheAusgang;
{Main}
Listing: laby1.pas Hinweis: Das Programm ist weitgehend ungesichert gegen fehlerhafte Labfiles.
|
||||||||||||||||
3.3.6 Mögliche WeiterentwicklungenGleich im Anschluss an die Lösung der Grundaufgabe, im späteren Unterricht oder über den Unterrichtsstoff hinausgehend kann an der Aufgabe weitergearbeitet werden.
Im Zusammenhang mit dem Abbruch der Suche nach der Entdeckung des ersten Ausgangs kann man die for-to-Schleife durch eine repeat-Schleife ersetzen. Bei der Suche nach dem kürzesten Weg kann man den Typ TLabElement durch ein Element Knoten ergänzen und so Schleifen vermeiden.
|
||||||||||||||||
3.3.7 LabyrintheHinweis: *.lby sind Textdateien
|
||||||||||||||||
|