@Tyroun: `time` wird importiert aber nirgends verwendet.
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).
Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.
`stab` ist ein schlechter Name für ein `Hanoi`-Objekt, denn das beschreibt ja nicht *einen* Stab, sondern *drei* Stäbe.
Grunddatentypen haben in Namen nichts zu suchen. Man ändert so etwas zu oft, so dass man die Namen dann entweder überall anpassen muss, oder irreführende Namen im Code hat.
Bei der `Stack`-Klasse machen die `it()`-Methode (was soll das bedeuten?) und die `push1()`-Methode keinen Sinn. Die werden auch nirgends verwendet.
Die Scheibe-Klasse macht keinen Sinn. Da sind einfach nur zwei Funktionen in eine Klasse gesteckt worden die überhaupt gar keinen Zustand verwaltet. Es wird ja auch nie irgendwo im Programm ein Objekt vom Typ `Scheibe` erstellt. `self` wird nicht verwendet und beim Aufrufen übergibst Du aus irgendwelchen Gründen ein `Hanoi`-Objekt. Was dagegen fehlt ist `canvas`. Das kommt einfach aus dem Nichts, muss aber eigentlich als Argument übergeben werden.
Die beiden Funktionen sind auch redundant, denn `create_ini()` ist eigentlich `create()` mit i=0.
In der `Hanoi.__init__` wird `i` an 1 gebunden und nie verändert. Den Namen kann man sich also sparen und die 1 an der Stelle einsetzen wo `i` verwendet wird.
Dann gibt es da `self.n` und `m` wobei das eine rauf und das andere runtergezählt wird. Manuell, in einer ``while``-Schleife. `self.n` wird ausserhalb der `__init__()` nicht mehr verwendet. Das ist alles ziemlich unsinnig. `m` fängt effektiv bei 1 an. Aber vor dieser verqueren Schleife wird der gleiche Code der für jedes `m` aufgerufen einmal mit 0 aufgerufen. Was soll diese extra Zeile wenn man doch einfach `m` bei 0 anfangen lassen können?
Das hier:
Code: Alles auswählen
self.staebe[ursprung].push(create_scheibe(canvas, 0))
i = 1
m = 1
self.n = anzahl
while self.n > i:
self.staebe[ursprung].push(create_scheibe(canvas, m))
m += 1
self.n -= 1
ist effektiv einfach nur das hier:
Code: Alles auswählen
for m in range(anzahl): # TODO `m` ist ein besch…dener Name!
self.staebe[ursprung].push(create_scheibe(canvas, m))
`scheiben_umstapeln()` ist ein unpassender Name, denn da wird *eine* Scheibe bewegt, nicht mehrere.
Zwischenstand (ungetestet):
Code: Alles auswählen
#!/usr/bin/env python3
import tkinter as tk
class Stack:
def __init__(self):
self.elemente = []
def push(self, element):
self.elemente.append(element)
def pop(self):
return self.elemente.pop()
def create_scheibe(canvas, i): # TODO Besserer Name für `i`.
return canvas.create_rectangle(
10 + (10 * i),
400 - (20 * i),
150 - (10 * i),
380 - (20 * i),
fill="blue",
)
class Hanoi:
def __init__(self, canvas, anzahl, ursprung, hilf, ziel):
self.staebe = {ursprung: Stack(), hilf: Stack(), ziel: Stack()}
for m in range(anzahl): # TODO `m` ist ein besch…dener Name!
self.staebe[ursprung].push(create_scheibe(canvas, m))
def stab_umstapeln(self, anzahl, ursprung, hilf, ziel):
if anzahl >= 1:
self.stab_umstapeln(anzahl - 1, ursprung, ziel, hilf)
self.scheibe_umstapeln(ursprung, ziel)
self.stab_umstapeln(anzahl - 1, hilf, ursprung, ziel)
def scheibe_umstapeln(self, ursprung, ziel):
self.staebe[ziel].push(self.staebe[ursprung].pop())
def main():
window = tk.Tk()
window.title("Türme von Hanoi")
canvas = tk.Canvas(window, bg="#f0e0b0", width=600, height=400)
canvas.pack()
scheibenanzahl = 8
staebe = Hanoi(canvas, scheibenanzahl, "A", "B", "C")
staebe.stab_umstapeln(scheibenanzahl, "A", "B", "C")
window.mainloop()
if __name__ == "__main__":
main()
Letztlich ist das ganze mit einem ereignisbasierten GUI-Rahmenwerk nicht so einfach wie Du Dir das vielleicht vorstellst. Auf der einen Seite hast Du einen rekursiven Algorithmus der in einem Aufruf komplett durchlaufen möchte. Auf der anderen Seite ein GUI-Rahmenwerk das nach jedem Schritt die Kontrolle zurück haben muss um den Schritt darstellen zu können.
Die beiden naheliegendsten Möglichkeiten die mir da einfallen würden, wären die Informationen zu den Bewegungen vor der Animation alle als Daten erzeugen. Oder die rekursive Lösung zu einer rekursiven Generatorfunktion machen, welche die Informationen zu den Schritten generiert.
Oder Du verwendest etwas anderes zur Visualisierung. `pygame` beispielsweise.