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.")

Der Akinator "lernt" dazu, indem er neue Einträge in seinen Entscheidungsbaum einfügt. Ist das echtes Lernen im Sinne von Künstlicher Intelligenz? Was fehlt, damit ein Computer wirklich "verstehen" würde, was er da speichert?

Antwort wird geladen...

Mindestens 50 Zeichen, Maximal 1000 Zeichen (Aktuell: 0)

Lokal gespeichert — Login, um Antworten dauerhaft zu sichern.