Zum Inhalt

Ozobot Oop

Note

11.12.24 Version 1

Aufgabe 1:

Erzeugen Sie einen Ozo. Der Ozo leuchtet blau und soll ein Quadrat mit 5cm Seitenlänge mit 4cm/s Geschwindigkeit fahren. Drehrichtung rechts:

Hier der Code zur Aufgabe:

import ozobot
import math

class Ozobot:
    def __init__(self, geschwindigkeit, top_light_color=[1, 1, 1]):
        self.ozo = ozobot.get_robot()
        self.top_light_color = top_light_color
        self.geschwindigkeit = geschwindigkeit / 100

        self.set_top_light(top_light_color)
        print("Der Ozo ist bereit!")

    def set_top_light(self, color):
        r = color[0]
        g = color[1]
        b = color[2]
        self.ozo.light_effects.set_light_color_rgb(r, g, b, ozobot.Lights.TOP)

    def geradeaus(self, distanz_cm):
        """Ozo fährt Distanz in cm geradeaus. Mit der Geschwindigkeit in cm/s"""
        distanz_cm /= 100  # Umrechnung für move-Methode
        self.ozo.movement.move(distanz_cm, self.geschwindigkeit)
        print(f"Ozobot fährt {distanz_cm * 100} cm geradeaus.")

    def drehen(self, richtung, grad, geschwindigkeit):
        """Dreht x Grad mit Geschwindigkeit in Grad pro Sekunde. Standardmäßig nach rechts. Mit richtung="links" nach links."""
        if richtung == "links":
            self.ozo.movement.rotate(math.radians(grad), math.radians(geschwindigkeit))
        else:
            self.ozo.movement.rotate(math.radians(-grad), math.radians(geschwindigkeit))
        print(f"Ozobot dreht {grad} Grad nach {richtung}.")

# Erzeuge den Ozobot
ozo = Ozobot(geschwindigkeit=4, top_light_color=[0, 0, 1])

seitenlaenge = 5
geschwindigkeit = 4

for _ in range(4):
    ozo.geradeaus(seitenlaenge)
    ozo.drehen(richtung="rechts", grad=90, geschwindigkeit=90)

Aufgabe 2:

Ergänzen Sie den Code aus Aufgabe 1 und erstellen Sie eine weitere Ozobot-Instanz bzw. Ozobot-Objekt. Dieser Ozo soll nun rot leuchten, 8cm/s schnell fahren und das Quadrat in anderer Richtung abfahren.

import ozobot
import math

# Definiere eine Klasse für den Ozobot
class Ozobot:
    def __init__(self, geschwindigkeit, top_light_color=[1, 1, 1]):
        # Initialisierung des Ozobot mit einer Instanz
        self.ozo = ozobot.get_robot()
        self.top_light_color = top_light_color
        self.geschwindigkeit = geschwindigkeit / 100  # Anpassung für movement-Methoden

        self.set_top_light(top_light_color)
        print("Der Ozo ist bereit!")

    def set_top_light(self, color):
        r = color[0]
        g = color[1]
        b = color[2]
        self.ozo.light_effects.set_light_color_rgb(r, g, b, ozobot.Lights.TOP)

    def geradeaus(self, distanz_cm):
        """Ozo fährt Distanz in cm geradeaus. Mit der Geschwindigkeit in cm/s"""
        distanz_cm /= 100  # Umrechnung für move-Methode
        self.ozo.movement.move(distanz_cm, self.geschwindigkeit)
        print(f"Ozobot fährt {distanz_cm * 100} cm geradeaus.")

    def drehen(self, richtung, grad, geschwindigkeit):
        """Dreht x Grad mit Geschwindigkeit in Grad pro Sekunde. Standardmäßig nach rechts. Mit richtung="links" nach links."""
        if richtung == "links":
            self.ozo.movement.rotate(math.radians(grad), math.radians(geschwindigkeit))
        else:
            self.ozo.movement.rotate(math.radians(-grad), math.radians(geschwindigkeit))
        print(f"Ozobot dreht {grad} Grad nach {richtung}.")

# Erzeuge den Ozobot
ozo = Ozobot(geschwindigkeit=8, top_light_color=[1, 0, 0])  # Blau

# Fahre ein Quadrat mit 5 cm Seitenlänge
seitenlaenge = 5  # cm
geschwindigkeit = 8  # cm/s

for _ in range(4):
    ozo.geradeaus(seitenlaenge)  # Geradeaus fahren
    ozo.drehen(richtung="links", grad=-90, geschwindigkeit=90)  # Nach rechts drehen

Aufgabe 3:

import ozobot
import math
# Definiere eine Klasse für den Ozobot
class Ozobot:
    def __init__(self, geschwindigkeit, top_light_color = [1,1,1]):
        # Initialisierung des Ozobot mit einer Instanz
        self.ozo = ozobot.get_robot()
        self.top_light_color = top_light_color
        self.__geschwindigkeit = geschwindigkeit/100 # Anpassung für movement-Methoden
        self.set_top_light(top_light_color)
        print("Der Ozo ist bereit!")
    def get_geschwindigkeit():
        return self.__geschwindigkeit
    def set_geschwindigkeit(self, geschwindigkeit):
        if geschwindigkeit >= 1 and geschwindigkeit <= 10: #Wert von 1 bis 10
            self.__geschwindigkeit = geschwindigkeit/100 #die geschwindigkeit wird übertragen
            print (f"ihre geschwindigkeit beträgt {self.__geschwindigkeit}.")
        else:
            print("Die geschwindigkeit muss zwischen 1 und 10 sein")

    def set_top_light (self, color):
        r = color[0]
        g = color[1]
        b = color[2]
        self.ozo.light_effects.set_light_color_rgb(r,g,b, ozobot.Lights.TOP)
    def geradeaus(self, distanz_cm):
        """Ozo fährt Distanz in cm geradeaus. Mit der Geschwindikeit in cm/s"""
        distanz_cm /= 100 # Umrechnung für move-Methode
        self.ozo.movement.move(distanz_cm, self.__geschwindigkeit)
        print(f"Ozobot fährt {distanz_cm} geradeaus.")
    def drehen(self, richtung, grad, geschwindigkeit):
        """Dreht x grad mit geschwindigkeit in grad pro Sekunde standarmässig nach rechts. Mit richtung ="links" nach links."""
        if richtung == "links":
            self.ozo.movement.rotate(math.radians(grad), math.radians(geschwindigkeit))
        else:
            self.ozo.movement.rotate(math.radians(-grad), math.radians(geschwindigkeit))
        print(f"Ozobot dreht {grad} Grad nach rechts.")
    def rw_fahren(self, distanz_cm):
        distanz_cm /= 100 # Umrechnung für move-Methode
        self.ozo.movement.move(distanz_cm, self.__geschwindigkeit)
        print(f"Ozobot fährt {distanz_cm} geradeaus.")



ozo1 = Ozobot(1, [0, 1.0, 0])
ozo1.geradeaus(5)
ozo1.set_geschwindigkeit(51)
ozo1.rw_fahren(-10) # Änderung Geschwindigkeit
ozo1.set_geschwindigkeit(10)
ozo1.geradeaus(10)eschwindigkeit(15)  # Ungültig: Geschwindigkeit bleibt unverändert

Anpassungen:

  1. set_geschwindigkeit Methode angepasst, um nur die Geschwindigkeit zu setzen (Entfernung des richtung-Parameters).

  2. Konstruktor (__init__) geändert, um nur die Geschwindigkeit zu übergeben, ohne richtung.

  3. Fehlerbehebung beim Aufruf von set_geschwindigkeit, sodass die Geschwindigkeit korrekt gesetzt wird.

  4. Direkter Zugriff auf geschwindigkeit blockiert durch den Setter, der eine ValueError wirft, wenn jemand versucht, den Wert direkt zu ändern.

Aufgabe 4

Aufgabe:

Lassen Sie den OzoAdvanced nun mit Toplight rot und Frontlights grün RÜCKWÄRTS ein Dreieck mit 5 cm Seitenlänge fahren

Wir haben am Code etwa 1 Stunde ausprobiert und haben dann den Code von jemandem übernommen.

# Importiere die Ozobot-Bibliothek
import ozobot
import math

# Definiere eine Klasse für den Ozobot
class Ozobot:
    def __init__(self, geschwindigkeit, top_light_color=[1, 1, 1]):
        self.ozo = ozobot.get_robot()
        self.top_light_color = top_light_color
        self._geschwindigkeit = geschwindigkeit / 100  # Anpassung für movement-Methoden

        self.set_top_light(top_light_color)
        print("Der Ozo ist bereit!")

    def set_top_light(self, color):
        r, g, b = color
        self.ozo.light_effects.set_light_color_rgb(r, g, b, ozobot.Lights.TOP)

    def set_geschwindigkeit(self, richtung, wert):
        if richtung not in ["vorwaerts", "rueckwaerts"]:
            print("Ungültige Richtung! Benutze 'vorwaerts' oder 'rueckwaerts'.")
            return
        if 1 <= wert <= 10:
            self._geschwindigkeit = (wert / 100) * (-1 if richtung == "rueckwaerts" else 1)
            print(f"Geschwindigkeit auf {wert} cm/s in Richtung {richtung} gesetzt.")
        else:
            print("Geschwindigkeit außerhalb des gültigen Bereichs (1-10 cm/s). Kein Update durchgeführt.")

    def geradeaus(self, distanz_cm):
        distanz_cm /= 100  # Umrechnung für move-Methode
        self.ozo.movement.move(distanz_cm, self._geschwindigkeit)
        print(f"Ozobot fährt {distanz_cm * 100} cm geradeaus.")

    def drehen(self, richtung, grad, geschwindigkeit):
        if richtung == "links":
            self.ozo.movement.rotate(math.radians(grad), math.radians(geschwindigkeit))
        else:
            self.ozo.movement.rotate(math.radians(-grad), math.radians(geschwindigkeit))
        print(f"Ozobot dreht {grad} Grad nach {richtung}.")


# Definiere die Unterklasse OzoAdvanced
class OzoAdvanced(Ozobot):
    def __init__(self, geschwindigkeit, top_light_color=[1, 1, 1], front_light_color=[1, 1, 1]):
        super().__init__(geschwindigkeit, top_light_color)
        self.front_light_color = front_light_color
        self.set_front_light(front_light_color)

    def set_front_light(self, color):
        try:
            print(f"Frontlichter auf Farbe RGB {color} gesetzt.")
            r, g, b = color
            self.ozo.light_effects.set_light_color_rgb(r, g, b, ozobot.Lights.ALL_FRONT) #Im Ozoboz API Documentation steht das man alle lichter mit ALL_FRONT benutzen kann
        except AttributeError:
            print("Die Steuerung der Frontlichter wird von der aktuellen Ozobot-Bibliothek nicht unterstützt.")

    def dreieck(self, seitenlaenge):
        for _ in range(3):
            self.geradeaus(seitenlaenge)
            self.drehen("links", 120, 90)  # Ein gleichseitiges Dreieck hat 120°-Winkel
        print(f"Ozo hat ein Dreieck mit Seitenlänge {seitenlaenge} cm gefahren.")


ozo_adv = OzoAdvanced(geschwindigkeit=8, top_light_color=[1, 0, 0], front_light_color=[0, 1, 0])  # Toplight rot, Frontlight grün
ozo_adv.set_geschwindigkeit("rueckwaerts", 5)  # Rückwärts mit Geschwindigkeit 5
ozo_adv.dreieck(5)  # Dreieck mit 5 cm Seitenlänge

Aufgabe 5

Aufgabe:

Läufer Objekt
Läufer 1 ozo1 (Klasse Ozobot, Farbe grün, Geschwindigkeit 5) Staffelübergabedauer 0,5s
Läufer 2 ozo2(rot,7) Staffelübergabedauer 0,5s
Läufer 3 ozo3(blau,7)
Läufer 4 ozo4(gelb,10)
Siegesfeier Schleife mit allen Läufern (ozo1-ozo4) und einem ozo_fans aus der Klasse OzoAdvanced:

Mehrmals nacheinander die Läufer und die  Fans (set_front_lights, dreieck) kurze, aber schnelle Bewegungen ausführen lassen

Hinweis: Bei der Siegesfeier arbeiten die Top-Light-Farben nicht wie gewünscht. Programmieren Sie eine Getter-Methode für die Top-Lights und weisen Sie den Farbwert (Array) der set_top_light-Methode zu.

Wissen Sie warum sich die Farben sonst nicht ändern ❓

Code für Aufgabe 5:

# Importiere die Ozobot-Bibliothek
import ozobot
import math
import time

# Definiere die Klasse Ozobot
class Ozobot:
    def __init__(self, geschwindigkeit, top_light_color=[1, 1, 1]):
        self.ozo = ozobot.get_robot()
        self._top_light_color = top_light_color
        self._geschwindigkeit = geschwindigkeit / 100  # Anpassung für movement-Methoden

        self.set_top_light(top_light_color)
        print("Der Ozo ist bereit!")

    def set_top_light(self, color):
        """Setzt die Farbe des Top-Lichts."""
        self._top_light_color = color
        r, g, b = color
        self.ozo.light_effects.set_light_color_rgb(r, g, b, ozobot.Lights.TOP)

    def get_top_light(self):
        """Gibt die aktuelle Farbe des Top-Lichts zurück."""
        return self._top_light_color

    def set_front_light(self, color):
        """Setzt die Farbe der Frontlichter."""
        r, g, b = color
        try:
            self.ozo.light_effects.set_light_color_rgb(r, g, b, ozobot.Lights.ALL_FRONT)
            print(f"Frontlichter auf Farbe RGB {color} gesetzt.")
        except AttributeError:
            print("Frontlichter werden von der Bibliothek nicht unterstützt.")

    def set_geschwindigkeit(self, richtung, wert):
        if richtung not in ["vorwaerts", "rueckwaerts"]:
            print("Ungültige Richtung! Benutze 'vorwaerts' oder 'rueckwaerts'.")
            return
        if 1 <= wert <= 10:
            self._geschwindigkeit = (wert / 100) * (-1 if richtung == "rueckwaerts" else 1)
            print(f"Geschwindigkeit auf {wert} cm/s in Richtung {richtung} gesetzt.")
        else:
            print("Geschwindigkeit außerhalb des gültigen Bereichs (1-10 cm/s). Kein Update durchgeführt.")

    def geradeaus(self, distanz_cm):
        distanz_cm /= 100  # Umrechnung für move-Methode
        self.ozo.movement.move(distanz_cm, self._geschwindigkeit)
        print(f"Ozobot fährt {distanz_cm * 100} cm geradeaus.")

    def drehen(self, richtung, grad, geschwindigkeit):
        if richtung == "links":
            self.ozo.movement.rotate(math.radians(grad), math.radians(geschwindigkeit))
        else:
            self.ozo.movement.rotate(math.radians(-grad), math.radians(geschwindigkeit))
        print(f"Ozobot dreht {grad} Grad nach {richtung}.")

# 4x5 geradeaus mit Lichtwechsel
def fahren_geradeaus(ozo, runden, distanz_cm):
    """Lässt den Ozobot 4x5 cm geradeaus fahren und bei jeder Runde Top- und Front-Lights wechseln."""
    farben = [
        {"top": [0, 1, 0], "front": [0, 1, 0]},  # Grün Toplight, Rot Frontlight
        {"top": [1, 0, 0], "front": [1, 0, 0]},  # Rot Toplight, Blau Frontlight
        {"top": [0, 0, 1], "front": [0, 0, 1]},  # Blau Toplight, Gelb Frontlight
        {"top": [1, 1, 0], "front": [1, 1, 0]}   # Gelb Toplight, Türkis Frontlight
    ]

    for runde in range(runden):
        # Setze die Farben für Top- und Frontlights für die aktuelle Runde
        ozo.set_top_light(farben[runde % len(farben)]["top"])
        ozo.set_front_light(farben[runde % len(farben)]["front"])
        print(f"Runde {runde + 1}: Toplight und Frontlight gesetzt.")

        # Fährt geradeaus
        ozo.geradeaus(distanz_cm)  # Fährt die Distanz in cm
        time.sleep(1)  # Pause zwischen den Wiederholungen

# Siegesfeier
def siegesfeier(laeufer, fans):
    """Lässt die Läufer und Fans kurze Bewegungen und Lichtwechsel ausführen."""
    for _ in range(3):  # Wiederholung der Siegesfeier
        for ozo in laeufer:
            ozo.drehen("links", 90, 200)  # Drehe 90 Grad links
            ozo.set_front_light([1, 0, 0])  # Weißes Toplight
            time.sleep(0.25)
            ozo.set_front_light([0, 0, 1])


        fans.drehen("rechts", 120, 300)  # Fans drehen schneller
        fans.set_front_light([0, 1, 1])  # Fans mit türkisen Frontlichtern
        fans.geradeaus(3)  # Fans bewegen sich kurz vorwärts
        time.sleep(0.5)

# Hauptprogramm
ozo1 = Ozobot(5, [0, 1, 0])  # Läufer 1: Grün
ozo2 = Ozobot(7, [1, 0, 0])  # Läufer 2: Rot
ozo3 = Ozobot(7, [0, 0, 1])  # Läufer 3: Blau
ozo4 = Ozobot(10, [1, 1, 0])  # Läufer 4: Gelb

ozo_fans = Ozobot(8, [1, 1, 1])  # Fans: Weißes Toplight

# Fahren und Siegesfeier
fahren_geradeaus(ozo1, 4, 5)  # Läufer 1 fährt 4x5 cm
siegesfeier([ozo1, ozo2, ozo3, ozo4], ozo_fans)  # Siegesfeier mit allen Läufern und Fans

wir konnten es dann mit einer for-schleife umsetzen:)

Fragen:

  1. Warum distanz_cm /= 100?

Die Zeile distanz_cm /= 100 teilt die Distanz in Zentimetern durch 100, um sie in Meter umzurechnen, da die move-Methode des Ozobots die Distanz in Metern erwartet.

  1. Wie haben Sie den zweiten Ozo aus Aufgabe 2 instanziiert?

Ich habe denn ersten Ozo abgeändert da ich das nicht so genau gelesen habe aber wenn ich es gemacht hätte, hätte ich ein neuse Objekt namens Ozo2 erstellt.

  1. Um welches Konzept der OoP geht es in Aufgabe 3? Was ist ein Setter/Getter? Was ist der Sinn?

In Aufgabe 3 geht es um das Konzept der Datenkapselung in der objektorientierten Programmierung (OOP), bei dem Setter- und Getter-Methoden verwendet werden.

  • Setter: Ermöglicht das sichere Setzen von Werten für private Attribute.

  • Getter: Ermöglicht das Zugreifen auf private Attribute.

Sinn von Settern und Gettern:

  • Zugangskontrolle: Sie schützen private Attribute vor unkontrolliertem Zugriff.

  • Validierung: Sie erlauben die Prüfung der Eingabewerte, bevor sie gespeichert werden.

  • Flexibilität: Änderungen an den Attributen können vorgenommen werden, ohne den restlichen Code zu beeinflussen.

  • Schutz der Integrität: Sie sichern die Datenintegrität und verhindern direkte Manipulationen.

  • Um welches Konzept der OoP geht es in Aufgabe 4?

In Aufgabe 4 wird das Vererbungskonzept angewendet, bei dem die Unterklasse (OzoAdvanced) von der Elternklasse (Ozobot) erbt und zusätzlich neue Funktionalitäten hinzufügt.

  1. Aufgabe 5 Staffellauf: Warum ändern sich die Farben nicht? Wie konnten Sie das lösen?

Wir haben dies wie oben beschrieben mit einer for-schleife umgesetzt in dem wir immer wieder die Farben abgeändert haben sodass sie nacher richtig funktioniert haben.

GUI-Kaffee

Erweitern Sie die objektorientierte Variante mit KI-Hilfe um eine GUI. Die GUI soll die Maschine grob darstellen und es soll möglich sein eine Auswahl der Kaffeesorten auszuwählen und zu bezahlen.

Ich habe die main.py und die kaffeemaschine.py der KI gegeben und den folgenden Output erhalten:

import tkinter as tk
from tkinter import messagebox
from kaffeemaschine import Kaffeeautomat

class KaffeeautomatGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("Kaffeeautomat")
        self.automat = Kaffeeautomat()

        # GUI Aufbau
        self.create_widgets()

    def create_widgets(self):
        # Begrüßung
        welcome_label = tk.Label(self.root, text="Willkommen beim Kaffeeautomat", font=("Helvetica", 16, "bold"))
        welcome_label.pack(pady=10)

        # Auswahl-Menü
        self.selection_var = tk.StringVar(value="Espresso")
        selection_label = tk.Label(self.root, text="Wählen Sie ein Getränk:")
        selection_label.pack()

        for drink in self.automat.menu.keys():
            rb = tk.Radiobutton(self.root, text=f"{drink} - CHF {self.automat.menu[drink]['preis']:.2f}",
                                variable=self.selection_var, value=drink)
            rb.pack(anchor=tk.W)

        # Button zur Bestellung
        order_button = tk.Button(self.root, text="Bestellen", command=self.bestellung_durchfuehren)
        order_button.pack(pady=10)

        # Status-Anzeige
        status_button = tk.Button(self.root, text="Maschinenstatus anzeigen", command=self.status_anzeigen)
        status_button.pack(pady=5)

        # Ressourcen auffüllen
        refill_button = tk.Button(self.root, text="Ressourcen auffüllen", command=self.ressourcen_auffuellen)
        refill_button.pack(pady=5)

        # Textbereich für Ausgaben
        self.output_text = tk.Text(self.root, height=10, width=40, state=tk.DISABLED)
        self.output_text.pack(pady=10)

    def bestellung_durchfuehren(self):
        auswahl = self.selection_var.get()
        drink_info = self.automat.menu[auswahl]
        preis = drink_info['preis']

        if not self.automat.reichen_ressourcen(drink_info['zusammensetzung']):
            self.ausgabe_anzeigen(f"Nicht genug Ressourcen für {auswahl}.")
            return

        # Simulierte Zahlung
        geld = self.geld_eingabe(preis)
        if geld >= preis:
            self.automat.ist_geld_ausreichend(geld, preis)
            self.automat.kaffee_ausgeben(auswahl)
            self.ausgabe_anzeigen(f"Ihr {auswahl} wurde zubereitet! Geniessen Sie Ihren Kaffee ☕")
        else:
            self.ausgabe_anzeigen("Zahlung fehlgeschlagen. Nicht genug Geld eingegeben.")

    def geld_eingabe(self, preis):
        geld_popup = tk.Toplevel(self.root)
        geld_popup.title("Geldeingabe")
        tk.Label(geld_popup, text=f"Bitte geben Sie mindestens CHF {preis:.2f} ein:").pack()
        geld_var = tk.DoubleVar(value=0)
        tk.Entry(geld_popup, textvariable=geld_var).pack()

        def submit_geld():
            geld_popup.destroy()

        submit_button = tk.Button(geld_popup, text="Bestätigen", command=submit_geld)
        submit_button.pack()
        geld_popup.wait_window()
        return geld_var.get()

    def status_anzeigen(self):
        status = f"Wasser: {self.automat.ressourcen['wasser']}ml\n"
        status += f"Milch: {self.automat.ressourcen['milch']}ml\n"
        status += f"Kaffeebohnen: {self.automat.ressourcen['kaffeebohnen']}g\n"
        status += f"Eingenommenes Geld: CHF {self.automat.geldbetrag:.2f}"
        messagebox.showinfo("Maschinenstatus", status)

    def ressourcen_auffuellen(self):
        self.automat.ressourcen["wasser"] += 300
        self.automat.ressourcen["milch"] += 200
        self.automat.ressourcen["kaffeebohnen"] += 100
        self.ausgabe_anzeigen("Ressourcen wurden erfolgreich aufgefüllt!")

    def ausgabe_anzeigen(self, text):
        self.output_text.config(state=tk.NORMAL)
        self.output_text.insert(tk.END, text + "\n")
        self.output_text.config(state=tk.DISABLED)

if __name__ == "__main__":
    root = tk.Tk()
    app = KaffeeautomatGUI(root)
    root.mainloop()

ich habe dann denn Code ausgeführt und es hat sich folgendes Fenster geöffnet:

es hat mir aber nur das terminal gemacht des automaten und keinen richtigen kaffeeautomat aber alles funktionierte und ich habe dann nochmals nachgehakt und es nochmals probiert und es sah dann so aus:

ich habe dann der KI gesagt sie soll es so anpassen das es stimmt und so sah es dann aus:

Die KI hat es zwar geschafft wenn ich das Fenster kleiner oder grösser mache die sachen anzupassen sodass sie nicht verrutschen aber konnte es nicht auf genau die maschine einsetzen. Ich glaube wenn das Bild im hintergrund stimmt dann sollte es kein Problem sein so etwas zu erstellen. Ich habe die Kaffeemaschine natürlich auch auf funktionalität getestet und es funktioniert alles. Jeder Knopf und jede Eingabe gibt einen Output.     Hier ist der Code dazu:

import tkinter as tk
from tkinter import messagebox, PhotoImage
from kaffeemaschine import Kaffeeautomat

class KaffeeautomatGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("Kaffeeautomat")
        self.automat = Kaffeeautomat()

        # Hintergrundbild
        self.background_image = PhotoImage(file="kaffeeordner/kaffeemaschine.png")
        self.canvas = tk.Canvas(self.root, width=self.background_image.width(), height=self.background_image.height())
        self.canvas.pack()
        self.canvas.create_image(0, 0, anchor=tk.NW, image=self.background_image)

        # Widgets platzieren
        self.create_widgets()

    def create_widgets(self):
        # Auswahl-Label und Buttons
        self.canvas.create_text(200, 50, text="Wählen Sie Ihr Getränk:", font=("Helvetica", 14, "bold"), fill="black")
        self.selection_var = tk.StringVar(value="Espresso")

        y_offset = 80
        for drink in self.automat.menu.keys():
            preis = self.automat.menu[drink]["preis"]
            rb = tk.Radiobutton(self.root, text=f"{drink} - CHF {preis:.2f}", variable=self.selection_var, value=drink,
                                bg="white")
            self.canvas.create_window(200, y_offset, window=rb)
            y_offset += 30

        # Buttons
        self.create_button("Bestellen", self.bestellung_durchfuehren, 200, 220)
        self.create_button("Maschinenstatus", self.status_anzeigen, 200, 260)
        self.create_button("Ressourcen auffüllen", self.ressourcen_auffuellen, 200, 300)

        # Geld einwerfen
        self.canvas.create_text(200, 340, text="Geld einwerfen (CHF):", font=("Helvetica", 10), fill="black")
        self.geld_var = tk.DoubleVar(value=0)
        self.geld_entry = tk.Entry(self.root, textvariable=self.geld_var)
        self.canvas.create_window(200, 370, window=self.geld_entry)
        self.create_button("Geld bestätigen", self.geld_bestätigen, 200, 400)

        # Textbereich für Ausgaben
        self.output_text = tk.Text(self.root, height=5, width=40, state=tk.DISABLED, bg="lightgrey")
        self.canvas.create_window(200, 460, window=self.output_text)

    def create_button(self, text, command, x, y):
        button = tk.Button(self.root, text=text, command=command, bg="lightgrey")
        self.canvas.create_window(x, y, window=button)

    def bestellung_durchfuehren(self):
        auswahl = self.selection_var.get()
        preis = self.automat.menu[auswahl]["preis"]
        geld = self.geld_var.get()

        if self.automat.reichen_ressourcen(self.automat.menu[auswahl]["zusammensetzung"]):
            if geld >= preis:
                self.automat.kaffee_ausgeben(auswahl)
                self.ausgabe_anzeigen(f"Ihr {auswahl} wurde zubereitet! ☕")
                self.geld_var.set(0)
                self.geld_entry.delete(0, tk.END)
            else:
                self.ausgabe_anzeigen("Nicht genug Geld eingegeben.")
        else:
            self.ausgabe_anzeigen(f"Nicht genug Ressourcen für {auswahl}.")

    def geld_bestätigen(self):
        geld = self.geld_var.get()
        self.ausgabe_anzeigen(f"CHF {geld:.2f} eingegeben.")

    def status_anzeigen(self):
        status = f"Wasser: {self.automat.ressourcen['wasser']}ml\n"
        status += f"Milch: {self.automat.ressourcen['milch']}ml\n"
        status += f"Kaffeebohnen: {self.automat.ressourcen['kaffeebohnen']}g\n"
        status += f"Eingenommenes Geld: CHF {self.automat.geldbetrag:.2f}"
        messagebox.showinfo("Maschinenstatus", status)

    def ressourcen_auffuellen(self):
        self.automat.ressourcen["wasser"] += 300
        self.automat.ressourcen["milch"] += 200
        self.automat.ressourcen["kaffeebohnen"] += 100
        self.ausgabe_anzeigen("Ressourcen wurden erfolgreich aufgefüllt!")

    def ausgabe_anzeigen(self, text):
        self.output_text.config(state=tk.NORMAL)
        self.output_text.insert(tk.END, text + "\n")
        self.output_text.config(state=tk.DISABLED)

if __name__ == "__main__":
    root = tk.Tk()
    app = KaffeeautomatGUI(root)
    root.mainloop()