Die Webseiten der Fachschaft Informatik am ERG Saalfeld
OOP am Beispiel von "Türme von Hanoi" mit Turtle
Es soll hier das Spiel "Türme von Hanoi" als Animation mit turtle, also im Grafikmodus programmiert werden. Als Vorlage dient
die Umsetzung in Python im Textmodus.
Vorbereitung
Die Turtle kennt die Anweisung "setpos", die für mich dasselbe leistet
wie print_at bzw. gotoxy bei Pascal. Es geht in der Vorbereitung darum heraus zu finden,
wo liegt der Koordinatenursprung und welcher Bereich steht zur Verfügung. Dazu habe ich ein kleines Programm erstellt auf einer extra Seite dargestellt.
Für die linke obere Ecke ergibt sich ungefähr (-350 | 300).
Für die rechte untere Ecke ergibt sich ungefähr (350 | -300).
Die Darstellung der Scheiben
Die Darstellung der Scheiben (und des Bodens) ist aufwendiger als im Textmodus und deshalb habe ich auch diesen Schritt auf eine extra Seite
ausgelagert. Dort wird Folgendes erstellt:
my_disc_farbe = ["white", "crimson", "brown", "peru", "goldenrod", "green", "lime green", "cadet blue", "blue"]
my_disc_breite = [160, 20, 40, 60, 80, 100, 120, 140, 160]
Dabei ist die Scheibe (disc) mit der Nummer 0 die Scheibe zum Löschen.
Klassendefinitionen
Scheibe
Die Scheiben haben eine Farbe. Die ist in "my_disc_farbe" definiert.
Die Scheiben haben eine Breite. Die ist in "my_disc_breite" definiert. Damit ergibt sich für die Klasse Scheibe:
class Scheibe():
def __init__(self, nummer_scheibe):
Scheibe.farbe = my_disc_farbe[nummer_scheibe]
Scheibe.breite = my_disc_breite[nummer_scheibe]
Jede Scheibe soll sich selbst darstellen können, also zeichnen und auch wieder löschen. Um die Scheibe zu zeichnen,
muss die Turtle ein Rechteck mit der entsprechenden Breite zeichnen und der vorgegebenen Farbe füllen. Die beiden Gleichungen
zur Berechnung der Koordinaten werden auf einer extra Seite hergeleitet. Diese sind:
pos_x = 250 * stab - 520 - self.breite / 2
pos_y = 25 * scheiben_nr_auf_stab - 75
Die Methode "zeichnen" für die Scheibe sieht damit so aus:
def zeichnen(self, stab, scheiben_nr_auf_stab):
pos_x = 250 * stab - 520 - self.breite / 2
pos_y = 25 * scheiben_nr_auf_stab - 75
my_turtle.color(self.farbe)
my_turtle.penup()
my_turtle.setpos(pos_x,pos_y)
my_turtle.pendown()
my_turtle.begin_fill()
my_turtle.forward(self.breite)
my_turtle.left(90)
my_turtle.forward(23)
my_turtle.left(90)
my_turtle.forward(self.breite)
my_turtle.left(90)
my_turtle.forward(23)
my_turtle.left(90)
my_turtle.end_fill()
Die Methode "loeschen" funktioniert genauso wie das zeichnen, nur das eben mit einer weißen Scheibe mit der größten Breite, also my_disc[0],
gezeichnet wird. Die Methode "loeschen" sieht damit so aus:
def loeschen(self, stab, scheiben_nr_auf_stab):
pos_x = 250 * stab - 520 - my_disc_breite[0] / 2
pos_y = 25 * scheiben_nr_auf_stab - 75
my_turtle.color(my_disc_farbe[0])
my_turtle.penup()
my_turtle.setpos(pos_x,pos_y)
my_turtle.pendown()
my_turtle.begin_fill()
my_turtle.forward(my_disc_breite[0])
my_turtle.left(90)
my_turtle.forward(23)
my_turtle.left(90)
my_turtle.forward(my_disc_breite[0])
my_turtle.left(90)
my_turtle.forward(23)
my_turtle.left(90)
my_turtle.end_fill()
zusammengefasst: die Klassendefinition für Scheibe sieht so aus:
class Scheibe():
def __init__(self, nummer_scheibe):
Scheibe.farbe = my_disc_farbe[nummer_scheibe]
Scheibe.breite = my_disc_breite[nummer_scheibe]
def zeichnen(self, stab, scheiben_nr_auf_stab):
pos_x = 250 * stab - 520 - self.breite / 2
pos_y = 25 * scheiben_nr_auf_stab - 75
my_turtle.color(self.farbe)
my_turtle.penup()
my_turtle.setpos(pos_x,pos_y)
my_turtle.pendown()
my_turtle.begin_fill()
my_turtle.forward(self.breite)
my_turtle.left(90)
my_turtle.forward(23)
my_turtle.left(90)
my_turtle.forward(self.breite)
my_turtle.left(90)
my_turtle.forward(23)
my_turtle.left(90)
my_turtle.end_fill()
def loeschen(self, stab, scheiben_nr_auf_stab):
pos_x = 250 * stab - 520 - my_disc_breite[0] / 2
pos_y = 25 * scheiben_nr_auf_stab - 75
my_turtle.color(my_disc_farbe[0])
my_turtle.penup()
my_turtle.setpos(pos_x,pos_y)
my_turtle.pendown()
my_turtle.begin_fill()
my_turtle.forward(my_disc_breite[0])
my_turtle.left(90)
my_turtle.forward(23)
my_turtle.left(90)
my_turtle.forward(my_disc_breite[0])
my_turtle.left(90)
my_turtle.forward(23)
my_turtle.left(90)
my_turtle.end_fill()
Die Klassendefinition für Stab zeichnet ja nicht (wohlgemerkt von Stab() - nicht für StabX() ), also kann die direkt von
dem Programm im Textmodus übernommen werden,
class Stab():
def __init__(self,nr):
self.anzahl = 0
self.nummer = nr # z.B.: stab_a = 1, stab_b = 2, stab_c = 3
self.scheiben = [] # Liste von Scheiben, die auf diesem Stab sind
def scheibe_aufnehmen(self, nummer_scheibe):
self.scheiben.append(nummer_scheibe)
self.anzahl += 1 # Anzahl um 1 erhöhen
hilf = Scheibe(nummer_scheibe)
stab_nr = self.nummer
scheiben_nr_auf_stab = self.anzahl
hilf.zeichnen(stab_nr, scheiben_nr_auf_stab)
def scheibe_abgeben(self):
aktuelle_scheibe = self.scheiben.pop() # Rückgabe ist Nummer der Scheibe (int)
stab_nr = self.nummer
scheiben_nr_auf_stab = self.anzahl
hilf = Scheibe(scheiben_nr_auf_stab)
hilf.loeschen(stab_nr, scheiben_nr_auf_stab)
self.anzahl -= 1 # Anzahl um 1 verkleinert
return aktuelle_scheibe # das ist die Nummer der Scheibe / my_disc
genauso wie die rekursive Prozedur "bewege".
def bewege (anzahl,stab_a,stab_b,stab_c):
if anzahl > 0:
bewege(anzahl-1,stab_a,stab_c,stab_b)
aktuelle_disc = stab_a.scheibe_abgeben()
stab_c.scheibe_aufnehmen(aktuelle_disc)
time.sleep(5/10) # sonst ist das Programm viel zu schnell
bewege(anzahl-1,stab_b,stab_a,stab_c)
Auch das Hauptprogramm kann fast vollständig übernommen werden (übernommen heißt hier kopiert werden).
Allerdings geht nicht die Ausgabe "Bin fertig" - bräuchte man auch nicht, weil der Cursor ja nicht positioniert werden muss
und auch die Anzahl der Bewegungen (dort mit print_at) kann so nicht ausgegeben werden. Dafür verwenden wir hier die Turtle-Funktion ...
Hier das vollständige Programm. Und hier als PDF-Datei. Hier das gezippte Python-Programm "turtle-hanoi.py" zum Download.
Das Programm wird z.B. so aufgerufen: python turtle-hanoi.py 5 dabei muss die Anzahl der Scheiben (von 1 bis 8) als Parameter übergeben werden.
zurück
© ERG Saalfeld - HD. Kirmse 13.05.2023
|