Mach es doch besser!

Aufgabe

In dieser Aufgabe können Sie es Felix und Marc zeigen!

Schauen Sie sich den Code von den beiden nochmal an (unten auf dieser Seite). Versuchen Sie nachzuvollziehen was passiert. Führen Sie ihn dazu gerne aus.

Bonus: Wenn Sie schon mit Debugging vertraut sind, dann nehme Sie auch gerne den Debugger zur Hand.

1.

Leider ist Marc und Felix ein Fehler beim Schreiben von spielzug() passiert. Etwas in den If-Abfragen stimmt nicht ganz.

Finden Sie den Fehler und korrigieren Sie ihn.

2.

Es ist bad practice Umlaufe zu benutzen. Korrigieren Sie den Code.

3.

Schreiben Sie eine Klasse Turm, die die einzelnen Türme darstellen soll. Folgende Dinge müssen in der Klasse enthalten sein (Lassen Sie sich gerne von dem Code von Marc und Felix inspirieren):

  • __init__(self) erstellt eine leere Liste als Darstellung für den Turm
  • __len__(self) definiert die Anzahl der Steine die auf dem Turm sind
  • __int__(self) gibt die Größe vom obersten Stein des Turms zurück
  • ist_add_stein_korrekt(self, stein: Stein) -> bool überprüft ob der Stein zum Turm hinzugefügt werden darf
  • add(self, stein: Stein) -> bool fügt einen Stein zum Turm hinzu und gibt True zurück, wenn die Eingabe valide ist. Andernfalls geben Sie False zurück.
  • remove(self) -> Stein entfernt den obersten Stein vom Turm und gibt ihn zurück. Wenn der Turm leer ist, dann wird None zurück gegeben.
4.

Ersetzen Sie in dem Code die Darstellung der Türme mit [ Turm(), Turm(), Turm() ].

Passen Sie den Rest des Codes an Ihre Änderungen an.

Zeilen im Code, die geändert werden müssen.
5.

Schreiben Sie eine Funktion in class Spielbrett, die überprüft, ob man Hanoi “gewonnen” hat und geben Sie einen entsprechenden print aus.

Überprüfen Sie dies nach jedem Spielzug.

6.

Schreiben Sie eine Funktion in class Spielbrett, die überprüft, ob ein Spielzug legal ist.

Überprüfen Sie, ob der Spielzug valide ist vor dem Zug.

7.

Schreiben Sie eine Funktion, in der Sie nach dem nächsten Spielzug fragen.

8.

Falls Sie 7. mit zwei input’s gelöst haben, dann schreiben Sie es um, sodass Sie es mit einem input lösen.

9.

Schreiben Sie eine Funktion in class Spielbrett, die einen random Spielzug generiert. Benutzen Sie dafür folgende Funktion:

import random
# Random Integer zwischen 0 und 2
random.randint(0,2)

Beachten Sie dabei, dass der Spielzug valide sein muss.

10.

Schreiben Sie die Funktion lets_go(self), die so oft random Spielzüge macht, bis Hanoi “gewonnen” wurde.

Disclaimer: Das könnte lange dauern.

Bonus

Verändern Sie die print-Ausgaben, sodass es schöner aussieht.

Ich würde zum Beispiel “█” benutzen, statt “*”.

Bonus Bonus

Verändern Sie den Code weiter bis Sie zufrieden sind.

Tipp: Strings Aufteilen

Achtung Spoiler!
class Stein:
    """Ich bin 1-Stein"""
    def __init__(self, größe : int):
        self.größe : int = größe

    def __str__(self) -> str:
        """ Damit die Scheiben schön aufeinander liegen können, also
              **
             ****
            ******
            soll man pro Größe 2 * drucken
        """

        return '**' * self.größe

    def __int__(self) -> int:
        return self.größe

class Spielbrett:
    def __init__(self, anzahl_der_steine : int):
        self.anzahl_der_steine : int = anzahl_der_steine
        # Das ist eine von vielen Designentscheidungen, die wir in unserer sehr guten Dokumentation ganz genau erklären
        self.türme = [ [], [], [] ] # türme[0] = turm links, türme[1] = turm mitte, türme[2] = turm rechts

        for index in range(0, anzahl_der_steine):
            # Linke Liste ist self.türme[0]
            self.türme[0].append(Stein(anzahl_der_steine - index))


    def spielzug(self, von : int, nach : int) -> bool:

        if 0 <= von < 3 and 0 <= nach <= 3:
            # Ist der von-Turm nicht-leer
            if len(self.türme[von]) > 0:
                # Nur kleinere auf größere Steine
                if len(self.türme[nach]) == 0 or int(self.türme[von][-1]) < int(self.türme[nach][-1]):
                    # Nimm letztes Element (vergleiche https://docs.python.org/3/tutorial/datastructures.html#more-on-lists)
                    letztes_element_vom_von_turm = self.türme[von].pop()
                    # Lege Element ab
                    self.türme[nach].append(letztes_element_vom_von_turm)
                    return True

        return False

    def __str__(self) -> str:
        """Todo: Schön machen"""
        ausgabe = ""

        for zeilenindex in range(1, self.anzahl_der_steine+1):
            # Ist an dieser Höhenposition ein Stein?
            for turm in self.türme:
                position_in_der_liste = self.anzahl_der_steine - zeilenindex
                if len(turm) > position_in_der_liste:
                    ausgabe = ausgabe + "."*(self.anzahl_der_steine - int(turm[position_in_der_liste])) + f"{turm[position_in_der_liste]}" + "."*(self.anzahl_der_steine - int(turm[position_in_der_liste]))
                else:
                    ausgabe = ausgabe + "."*(2*self.anzahl_der_steine)
                ausgabe = ausgabe + "|"
            ausgabe = ausgabe + '\n'


        return ausgabe


def hanoi():
    print(f"Test")
    mygame = Spielbrett(5)
    print(f"{mygame}")
    mygame.spielzug(0, 1)
    mygame.spielzug(0, 1)
    mygame.spielzug(0, 1)
    mygame.spielzug(0, 1)
    mygame.spielzug(0, 1)
    mygame.spielzug(0, 1)
    mygame.spielzug(0, 2)
    mygame.spielzug(1, 2)

    print(f"{mygame}")



def main():
    """Hier startet die Funktion ihre Arbeit"""
    hanoi()


if __name__ == '__main__':
    main()