L Lyrnify

Akinator — Ein lernender Entscheidungsbaum in Python

lock
Bevorstehend

Bauen Sie einen Akinator-Klon in Python, der durch Ja-oder-Nein-Fragen rät — und dazulernt, indem er sein Wissen als Entscheidungsbaum speichert.

Ziele dieses Moduls
  • Sie können den Aufbau eines Entscheidungsbaums als verschachteltes Dictionary erklären.
    Verstehen
  • Sie können ein Python-Programm mit Rekursion, Datei-Ein-/Ausgabe (JSON) und Dictionary-Manipulation umsetzen.
    Anwenden
  • Sie können den Akinator um eigene Funktionen wie Statistik und erweiterte Benutzerführung ergänzen.
    Kreieren
label
PythonKIEntscheidungsbaumJSONRekursion

In diesem Modul bauen Sie einen Akinator-Klon in Python. Das Programm stellt Ja-oder-Nein-Fragen, um zu erraten, woran Sie denken — und lernt aus seinen Fehlern. Kernkonzepte: Entscheidungsbaum, Rekursion, JSON-Dateien.

Was ist Akinator?

Akinator ist ein bekanntes Online-Spiel, das versuchen kann, eine Person, einen Gegenstand oder ein Tier zu erraten — nur durch Ja-oder-Nein-Fragen. Das Erstaunliche: Je öfter man spielt, desto besser wird es!

Dahinter steckt ein Entscheidungsbaum — eine Baumstruktur, bei der jede Frage zu zwei weiteren Ästen führt (ja/nein). Am Ende der Äste stehen die Antworten.

In diesem Modul bauen Sie Ihren eigenen Akinator in Python — und das Besondere: Er lernt dazu! Wenn er etwas nicht weiss, fragt er Sie und merkt es sich fürs nächste Mal.

Note

Wie funktioniert ein Entscheidungsbaum?

Stell dir einen Baum vor:

  • Jeder Knoten enthält entweder eine Frage oder eine Antwort.
  • Bei einer Frage gibt es zwei Wege: ja (links) und nein (rechts).
  • Bei einer Antwort ist das Spiel vorbei — der Computer rät.

Beispiel:

[Ist es ein Lebewesen?]
  ├── ja → [Hat es vier Beine?]
  │        ├── ja → "Hund"
  │        └── nein → "Mensch"
  └── nein → [Kann man es essen?]
             ├── ja → "Pizza"
             └── nein → "Stein"

In Python speichern wir diesen Baum als verschachteltes Dictionary. Das Lernen funktioniert, indem wir neue Fragen und Antworten in den Baum einfügen.

import json
import os

DATEI = "wissen.json"

STANDARD_WISSEN = {
    "frage": "Ist es ein Lebewesen?",
    "ja": {
        "frage": "Hat es vier Beine?",
        "ja": {"antwort": "Hund"},
        "nein": {"antwort": "Mensch"}
    },
    "nein": {
        "frage": "Kann man es essen?",
        "ja": {"antwort": "Pizza"},
        "nein": {"antwort": "Stein"}
    }
}

def wissen_laden():
    if os.path.exists(DATEI):
        with open(DATEI, "r", encoding="utf-8") as f:
            return json.load(f)
    return STANDARD_WISSEN

def wissen_speichern(wissen):
    with open(DATEI, "w", encoding="utf-8") as f:
        json.dump(wissen, f, ensure_ascii=False, indent=2)

def frage_stellen(text):
    while True:
        antwort = input(text + " (ja/nein): ").strip().lower()
        if antwort in ["ja", "j", "yes", "y"]:
            return True
        if antwort in ["nein", "n", "no"]:
            return False
        print("Bitte antworte mit 'ja' oder 'nein'.")

def lernen(knoten, falsche_antwort):
    richtige_antwort = input("Was hast du dir ausgedacht? ")
    neue_frage = input(
        "Gib mir eine Frage, die '" + richtige_antwort
        + "' von '" + falsche_antwort + "' unterscheidet: "
    )
    antwort_fuer_neu = frage_stellen(
        "Ist die Antwort fuer '" + richtige_antwort + "' ja?"
    )
    knoten.clear()
    knoten["frage"] = neue_frage
    if antwort_fuer_neu:
        knoten["ja"] = {"antwort": richtige_antwort}
        knoten["nein"] = {"antwort": falsche_antwort}
    else:
        knoten["ja"] = {"antwort": falsche_antwort}
        knoten["nein"] = {"antwort": richtige_antwort}

def spielen(knoten):
    if "antwort" in knoten:
        ratung = knoten["antwort"]
        if frage_stellen("Ist es " + ratung + "?"):
            print("Super! Ich hab's gewusst!")
        else:
            print("Oh, das wusste ich nicht.")
            lernen(knoten, ratung)
        return
    if frage_stellen(knoten["frage"]):
        spielen(knoten["ja"])
    else:
        spielen(knoten["nein"])

def main():
    print("=== Akinator ===")
    print("Denk dir etwas aus, und ich versuche es zu erraten!")
    print()
    wissen = wissen_laden()
    while True:
        spielen(wissen)
        wissen_speichern(wissen)
        if not frage_stellen("Nochmal spielen?"):
            print("Bis bald!")
            break

main()

Challenge

Dein Auftrag: Erweitere den Akinator!

Der Code funktioniert — aber mit nur 4 Einträgen im Baum ist er schnell durch. Erweitern Sie ihn!

Teil 1 — Basis (alle)

  • Kopiere den Code in eine Datei akinator.py und teste ihn.
  • Spielen Sie mehrmals und bringen Sie dem Akinator mindestens 5 neue Dinge bei.
  • Schauen Sie sich die Datei wissen.json an — wie wächst der Baum mit jedem neuen Eintrag?
  • Erweitern Sie STANDARD_WISSEN mit 3–5 weiteren Einträgen, damit der Start-Baum grösser ist.

Teil 2 — Mittel

  • Bauen Sie einen Runden-Zähler ein: Das Programm zeigt an, wie viele Fragen es gestellt hat und wie oft es richtig geraten hat.
  • Fügen Sie eine Statistik hinzu: "Ich habe schon X Mal gespielt und Y Mal richtig geraten." Speichern Sie die Statistik ebenfalls in der JSON-Datei.

Teil 3 — Fortgeschritten (optional)

  • Fügen Sie eine "Vielleicht"-Antwort hinzu: Bei "vielleicht" soll der Akinator beide Äste des Baums durchsuchen und alle möglichen Antworten sammeln.
  • Bauen Sie einen "Zurücksetzen"-Befehl ein, der den Baum auf den Anfangszustand zurücksetzt.
  • Geben Sie den aktuellen Baum als Text-Diagramm aus (ähnlich wie im Infokasten oben).

Warning

Häufige Fehler

  • Rekursion verstehen: Die Funktion spielen() ruft sich selbst auf — das nennt man Rekursion. Bei jedem Aufruf geht man einen Knoten tiefer im Baum. Der Abbruch ist erreicht, wenn "antwort" im Knoten steht.
  • knoten.copy() im lernen(): Ohne .copy() würden die alten Daten überschrieben. Der ursprüngliche Knoten wird zum neuen Frage-Knoten, die alte Antwort rutscht auf die "nein"-Seite.
  • JSON-Datei wird nicht erstellt: Beim ersten Spiel gibt es noch keine wissen.json — deshalb prüft os.path.exists() zuerst, ob die Datei existiert.
  • Umlaute in JSON: Das ensure_ascii=False in json.dump() ist wichtig, damit Umlaute (ä, ö, ü) korrekt gespeichert werden.

# Tipp für die Statistik (Teil 2):

STATS_DATEI = "akinator_stats.json"

def stats_laden():
    if os.path.exists(STATS_DATEI):
        with open(STATS_DATEI, "r", encoding="utf-8") as f:
            return json.load(f)
    return {"spiele": 0, "richtig": 0}

def stats_speichern(stats):
    with open(STATS_DATEI, "w", encoding="utf-8") as f:
        json.dump(stats, f, ensure_ascii=False, indent=2)

# In main() einbauen:
#   stats = stats_laden()
#   ... nach jedem Spiel:
#   stats["spiele"] += 1
#   if gewonnen: stats["richtig"] += 1
#   stats_speichern(stats)
#   print(f"Statistik: {stats['richtig']} von {stats['spiele']} richtig.")
Antwort wird geladen...

Lokal gespeichert — melde dich an, um Antworten dauerhaft zu sichern.

Login