Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Praxisbeispiel: Tic Tac Toe Vibe Coding

Heinrich-Heine-Universität Düsseldorf

Hier ist eine Abfolge von iterativen Vibe Coding Experimenten, also jeweils 1-2 Prompts von einer Version zur nächsten. Etwa bei Version 6 ist eine Komplexitätsschwelle erreicht, bei der unbedarftes Vibe Coding nicht mehr mit billigen Modellen gut gelingt (mit teureren oder stärkerer Vorstrukturierung schon).

Der volle Verlauf ist hier zu finden.

Übungsaufgaben dazu:

  • Wählen Sie eine Variante aus, z.B. die letzte (gen7) und versuchen Sie (mit KI-Hilfe) einen Prompt zu rekonstruieren, der ungefähr diesen Code (ähnliche Struktur, gleiche Semantik) generiert ohne dass man mehrfach prompten muss (“one-shot”).

  • Denken Sie sich eine weitere Tic Tac Toe Variante aus und lassen sie diese hinzu vibe coden. Wie prüfen Sie, ob es (gut) geklappt hat?

%pycat generated-0.py
from functools import cache # Permutationen der D8-Gruppe (Identität, 3x Rotation, 4x Spiegelung) P = [[0,1,2,3,4,5,6,7,8], [6,3,0,7,4,1,8,5,2], [8,7,6,5,4,3,2,1,0], [2,5,8,1,4,7,0,3,6], [2,1,0,5,4,3,8,7,6], [6,7,8,3,4,5,0,1,2], [0,3,6,1,4,7,2,5,8], [8,5,2,7,4,1,6,3,0]] W = [(0,1,2),(3,4,5),(6,7,8),(0,3,6),(1,4,7),(2,5,8),(0,4,8),(2,4,6)] def norm(b): # Lexikographisches Maximum liefert bis auf Symmetrie eindeutige Normalform (X > O > .) return max("".join(b[i] for i in p) for p in P) def win(b, p): return any(all(b[i] == p for i in w) for w in W) @cache def mm(b, p): if win(b, 'X'): return 1 if win(b, 'O'): return -1 if '.' not in b: return 0 q = 'O' if p == 'X' else 'X' res = [mm(norm(b[:i]+p+b[i+1:]), q) for i in range(9) if b[i] == '.'] return max(res) if p == 'X' else min(res) def print_board(b): print(f"\n {b[0]} | {b[1]} | {b[2]} \n---+---+---\n {b[3]} | {b[4]} | {b[5]} \n---+---+---\n {b[6]} | {b[7]} | {b[8]} \n") b = "........." while '.' in b and not win(b, 'X') and not win(b, 'O'): b = norm(b) print_board(b) if b.count('.') % 2 != 0: # X ist am Zug (Mensch) while True: try: m = int(input("Zug X (0-8): ")) if 0 <= m <= 8 and b[m] == '.': b = b[:m] + 'X' + b[m+1:] break except ValueError: pass else: # O ist am Zug (Computer) _, m = min((mm(norm(b[:i]+'O'+b[i+1:]), 'X'), i) for i in range(9) if b[i] == '.') b = b[:m] + 'O' + b[m+1:] b = norm(b) print("Endstand:") print_board(b) print("Gewinner:", 'X' if win(b, 'X') else 'O' if win(b, 'O') else 'Unentschieden')
!printf "0\n1\n2\n2\n1\n0\n3\n" | uv run generated-0.py

 . | . | . 
---+---+---
 . | . | . 
---+---+---
 . | . | . 

Zug X (0-8): 
 X | . | . 
---+---+---
 . | . | . 
---+---+---
 . | . | . 


 X | . | . 
---+---+---
 . | O | . 
---+---+---
 . | . | . 

Zug X (0-8): 
 X | X | . 
---+---+---
 . | O | . 
---+---+---
 . | . | . 


 X | X | O 
---+---+---
 . | O | . 
---+---+---
 . | . | . 

Zug X (0-8): Zug X (0-8): Zug X (0-8): Zug X (0-8): Zug X (0-8): 
 X | X | O 
---+---+---
 X | O | . 
---+---+---
 . | . | . 

Endstand:

 X | X | O 
---+---+---
 X | O | . 
---+---+---
 O | . | . 

Gewinner: O
%pycat generated-1.py
import deal from hypothesis import given, strategies as st from functools import cache # --- Kernlogik --- P = [[0,1,2,3,4,5,6,7,8], [6,3,0,7,4,1,8,5,2], [8,7,6,5,4,3,2,1,0], [2,5,8,1,4,7,0,3,6], [2,1,0,5,4,3,8,7,6], [6,7,8,3,4,5,0,1,2], [0,3,6,1,4,7,2,5,8], [8,5,2,7,4,1,6,3,0]] W = [(0,1,2),(3,4,5),(6,7,8),(0,3,6),(1,4,7),(2,5,8),(0,4,8),(2,4,6)] def norm(b: str) -> str: return max("".join(b[i] for i in p) for p in P) def win(b: str, p: str) -> bool: return any(all(b[i] == p for i in w) for w in W) @cache def mm(b: str, p: str) -> int: if win(b, 'X'): return 1 if win(b, 'O'): return -1 if '.' not in b: return 0 q = 'O' if p == 'X' else 'X' res = [mm(norm(apply_move(b, p, i)), q) for i in range(9) if b[i] == '.'] return max(res) if p == 'X' else min(res) # --- Verträge --- # --- Verträge --- @deal.pre(lambda b, p, m: len(b) == 9) @deal.pre(lambda b, p, m: p in ('X', 'O')) @deal.pre(lambda b, p, m: 0 <= m <= 8) @deal.pre(lambda b, p, m: b[m] == '.') @deal.post(lambda res: len(res) == 9) def apply_move(b: str, p: str, m: int) -> str: return b[:m] + p + b[m+1:] @deal.pre(lambda b: len(b) == 9) @deal.pre(lambda b: '.' in b and not win(b, 'X') and not win(b, 'O')) @deal.post(lambda res: 0 <= res <= 8) def best_ai_move(b: str) -> int: return min((mm(norm(apply_move(b, 'O', i)), 'X'), i) for i in range(9) if b[i] == '.')[1] # --- Tests --- valid_boards = st.text(alphabet='XO.', min_size=9, max_size=9).filter( lambda b: '.' in b and not win(b, 'X') and not win(b, 'O') and abs(b.count('X') - b.count('O')) <= 1) @given(valid_boards, st.integers(0, 8)) def test_move_validity(b: str, m: int): if b[m] == '.': assert apply_move(b, 'X', m).count('.') == b.count('.') - 1 @given(valid_boards) def test_ai_optimality(b: str): m = best_ai_move(b) v_opt = mm(norm(apply_move(b, 'O', m)), 'X') assert all(v_opt <= mm(norm(apply_move(b, 'O', i)), 'X') for i in range(9) if b[i] == '.') # --- Spielschleife --- if __name__ == '__main__': def print_board(b): print(f"\n {b[0]} | {b[1]} | {b[2]} \n---+---+---\n {b[3]} | {b[4]} | {b[5]} \n---+---+---\n {b[6]} | {b[7]} | {b[8]} \n") b = "........." while '.' in b and not win(b, 'X') and not win(b, 'O'): b = norm(b) print_board(b) if b.count('.') % 2 != 0: try: m = int(input("Zug X (0-8): ")) if 0 <= m <= 8 and b[m] == '.': b = apply_move(b, 'X', m) except ValueError: pass else: b = apply_move(b, 'O', best_ai_move(b)) b = norm(b) print("Endstand:") print_board(b) print("Gewinner:", 'X' if win(b, 'X') else 'O' if win(b, 'O') else 'Unentschieden')
!uv run crosshair check generated-1.py
!uv run pytest generated-1.py
!printf "0\n1\n2\n2\n1\n0\n3\n" | uv run generated-1.py
============================= test session starts ==============================
platform linux -- Python 3.13.2, pytest-9.0.3, pluggy-1.6.0
rootdir: /home/voelkel/sciebo/hhu/eipy-26/eipy-skript
configfile: pyproject.toml
plugins: cov-5.0.0, hypothesis-6.152.9, jaxtyping-0.3.11, gremlins-1.8.1, anyio-4.13.0, typeguard-4.5.2, Faker-40.23.0, hydra-core-1.3.2, logfire-4.37.0
collected 2 items                                                              

generated-1.py ..                                                        [100%]

============================== 2 passed in 0.50s ===============================

 . | . | . 
---+---+---
 . | . | . 
---+---+---
 . | . | . 

Zug X (0-8): 
 X | . | . 
---+---+---
 . | . | . 
---+---+---
 . | . | . 


 X | . | . 
---+---+---
 . | O | . 
---+---+---
 . | . | . 

Zug X (0-8): 
 X | X | . 
---+---+---
 . | O | . 
---+---+---
 . | . | . 


 X | X | O 
---+---+---
 . | O | . 
---+---+---
 . | . | . 

Zug X (0-8): 
 X | X | O 
---+---+---
 . | O | . 
---+---+---
 . | . | . 

Zug X (0-8): 
 X | X | O 
---+---+---
 . | O | . 
---+---+---
 . | . | . 

Zug X (0-8): 
 X | X | O 
---+---+---
 . | O | . 
---+---+---
 . | . | . 

Zug X (0-8): 
 X | X | O 
---+---+---
 . | O | . 
---+---+---
 . | . | . 

Zug X (0-8): 
 X | X | O 
---+---+---
 X | O | . 
---+---+---
 . | . | . 

Endstand:

 X | X | O 
---+---+---
 X | O | . 
---+---+---
 O | . | . 

Gewinner: O
%pycat generated-2.py
import sys, deal from hypothesis import given, strategies as st from functools import cache # --- Kernlogik & Verträge --- P = [[0,1,2,3,4,5,6,7,8], [6,3,0,7,4,1,8,5,2], [8,7,6,5,4,3,2,1,0], [2,5,8,1,4,7,0,3,6], [2,1,0,5,4,3,8,7,6], [6,7,8,3,4,5,0,1,2], [0,3,6,1,4,7,2,5,8], [8,5,2,7,4,1,6,3,0]] W = [(0,1,2),(3,4,5),(6,7,8),(0,3,6),(1,4,7),(2,5,8),(0,4,8),(2,4,6)] def norm(b: str) -> str: return max("".join(b[i] for i in p) for p in P) def win(b: str, p: str) -> bool: return any(all(b[i] == p for i in w) for w in W) @deal.pre(lambda b, p, m: len(b) == 9 and p in ('X', 'O') and 0 <= m <= 8 and b[m] == '.') @deal.post(lambda res: len(res) == 9) def apply_move(b: str, p: str, m: int) -> str: return b[:m] + p + b[m+1:] @cache def mm(b: str, p: str) -> int: if win(b, 'X'): return 1 if win(b, 'O'): return -1 if '.' not in b: return 0 q = 'O' if p == 'X' else 'X' res = [mm(norm(apply_move(b, p, i)), q) for i in range(9) if b[i] == '.'] return max(res) if p == 'X' else min(res) @deal.pre(lambda b: len(b) == 9 and '.' in b and not win(b, 'X') and not win(b, 'O')) @deal.post(lambda res: 0 <= res <= 8) def best_ai_move(b: str) -> int: return min((mm(norm(apply_move(b, 'O', i)), 'X'), i) for i in range(9) if b[i] == '.')[1] # --- Tests (Hypothesis) --- valid_boards = st.text(alphabet='XO.', min_size=9, max_size=9).filter( lambda b: '.' in b and not win(b, 'X') and not win(b, 'O') and abs(b.count('X') - b.count('O')) <= 1) @given(valid_boards, st.integers(0, 8)) def test_move_validity(b: str, m: int): if b[m] == '.': assert apply_move(b, 'X', m).count('.') == b.count('.') - 1 @given(valid_boards) def test_ai_optimality(b: str): v_opt = mm(norm(apply_move(b, 'O', best_ai_move(b))), 'X') assert all(v_opt <= mm(norm(apply_move(b, 'O', i)), 'X') for i in range(9) if b[i] == '.') # --- UI & Spielschleife --- if __name__ == '__main__': auto_mode = '--auto' in sys.argv def print_board(b, u, f): d = [f"\033[91m{i}\033[0m" if i in f else f"\033[92m{i}\033[0m" if i in u else '.' if b[i]=='.' else b[i] for i in range(9)] print(f"\n {d[0]} | {d[1]} | {d[2]} \n---+---+---\n {d[3]} | {d[4]} | {d[5]} \n---+---+---\n {d[6]} | {d[7]} | {d[8]} \n") b = "........." while '.' in b and not win(b, 'X') and not win(b, 'O'): b = norm(b) if b.count('.') % 2 != 0: sym_moves = {} for i in range(9): if b[i] == '.': nb = norm(apply_move(b, 'X', i)) if nb not in sym_moves: sym_moves[nb] = i uniq = list(sym_moves.values()) forced = [i for i in range(9) if b[i] == '.' and win(apply_move(b, 'O', i), 'O')] print_board(b, uniq, forced) if auto_mode and (forced or len(uniq) == 1): m = forced[0] if forced else uniq[0] print(f"[\033[93mAUTO\033[0m] Führe determinierten Zug aus: {m}") b = apply_move(b, 'X', m) continue while True: try: m = int(input("Zug X (Grün=Optionen, Rot=Zwang): ")) if m in uniq or m in forced: # Beschränkt Eingabe auf kanonische/zwingende Züge b = apply_move(b, 'X', m) break elif 0 <= m <= 8 and b[m] == '.': print("Bitte wähle einen der farblich markierten Repräsentanten aus.") except ValueError: pass else: b = apply_move(b, 'O', best_ai_move(b)) b = norm(b) print("Endstand:") print_board(b, [], []) print("Gewinner:", 'X' if win(b, 'X') else 'O' if win(b, 'O') else 'Unentschieden')
!uv run crosshair check generated-2.py
!uv run pytest generated-2.py
!printf "0\n1\n2\n2\n1\n0\n3\n" | uv run generated-2.py
============================= test session starts ==============================
platform linux -- Python 3.13.2, pytest-9.0.3, pluggy-1.6.0
rootdir: /home/voelkel/sciebo/hhu/eipy-26/eipy-skript
configfile: pyproject.toml
plugins: cov-5.0.0, hypothesis-6.152.9, jaxtyping-0.3.11, gremlins-1.8.1, anyio-4.13.0, typeguard-4.5.2, Faker-40.23.0, hydra-core-1.3.2, logfire-4.37.0
collected 2 items                                                              

generated-2.py ..                                                        [100%]

============================== 2 passed in 0.51s ===============================

 0 | 1 | . 
---+---+---
 . | 4 | . 
---+---+---
 . | . | . 

Zug X (Grün=Optionen, Rot=Zwang): 
 X | 1 | 2 
---+---+---
 . | O | 5 
---+---+---
 . | . | 8 

Zug X (Grün=Optionen, Rot=Zwang): 
 X | X | O 
---+---+---
 3 | O | 5 
---+---+---
 6 | 7 | 8 

Zug X (Grün=Optionen, Rot=Zwang): Zug X (Grün=Optionen, Rot=Zwang): Zug X (Grün=Optionen, Rot=Zwang): Zug X (Grün=Optionen, Rot=Zwang): Zug X (Grün=Optionen, Rot=Zwang): Endstand:

 X | X | O 
---+---+---
 X | O | . 
---+---+---
 O | . | . 

Gewinner: O
%pycat generated-3.py
import sys, deal from hypothesis import given, strategies as st from functools import cache # --- Kernlogik & Verträge --- P = [[0,1,2,3,4,5,6,7,8], [6,3,0,7,4,1,8,5,2], [8,7,6,5,4,3,2,1,0], [2,5,8,1,4,7,0,3,6], [2,1,0,5,4,3,8,7,6], [6,7,8,3,4,5,0,1,2], [0,3,6,1,4,7,2,5,8], [8,5,2,7,4,1,6,3,0]] W = [(0,1,2),(3,4,5),(6,7,8),(0,3,6),(1,4,7),(2,5,8),(0,4,8),(2,4,6)] def norm(b: str) -> str: return max("".join(b[i] for i in p) for p in P) def win(b: str, p: str) -> bool: return any(all(b[i] == p for i in w) for w in W) @deal.pre(lambda b, p, m: len(b) == 9 and p in ('X', 'O') and 0 <= m <= 8 and b[m] == '.') @deal.post(lambda res: len(res) == 9) def apply_move(b: str, p: str, m: int) -> str: return b[:m] + p + b[m+1:] @cache def mm(b: str, p: str) -> int: if win(b, 'X'): return 1 if win(b, 'O'): return -1 if '.' not in b: return 0 q = 'O' if p == 'X' else 'X' res = [mm(norm(apply_move(b, p, i)), q) for i in range(9) if b[i] == '.'] return max(res) if p == 'X' else min(res) @deal.pre(lambda b: len(b) == 9 and '.' in b and not win(b, 'X') and not win(b, 'O')) @deal.post(lambda res: 0 <= res <= 8) def best_ai_move(b: str) -> int: return min((mm(norm(apply_move(b, 'O', i)), 'X'), i) for i in range(9) if b[i] == '.')[1] # --- Zustandsraum-Analyse --- @cache def count_paths(b: str) -> int: if win(b, 'X') or win(b, 'O') or '.' not in b: return 1 if b.count('.') % 2 != 0: win_x = [i for i in range(9) if b[i] == '.' and win(apply_move(b, 'X', i), 'X')] win_o = [i for i in range(9) if b[i] == '.' and win(apply_move(b, 'O', i), 'O')] forced = win_x or win_o if forced: return count_paths(norm(apply_move(b, 'X', forced[0]))) sym_moves = {norm(apply_move(b, 'X', i)): i for i in range(9) if b[i] == '.'} uniq = list(sym_moves.values()) if len(uniq) == 1: return count_paths(norm(apply_move(b, 'X', uniq[0]))) return sum(count_paths(norm(apply_move(b, 'X', m))) for m in uniq) else: # KI verzweigt über alle Züge, die das Minimax-Optimum (bis auf Symmetrie) realisieren v_opt = min(mm(norm(apply_move(b, 'O', i)), 'X') for i in range(9) if b[i] == '.') opt_states = {norm(apply_move(b, 'O', i)) for i in range(9) if b[i] == '.' and mm(norm(apply_move(b, 'O', i)), 'X') == v_opt} return sum(count_paths(nb) for nb in opt_states) # --- Tests (Hypothesis) --- valid_boards = st.text(alphabet='XO.', min_size=9, max_size=9).filter( lambda b: '.' in b and not win(b, 'X') and not win(b, 'O') and abs(b.count('X') - b.count('O')) <= 1) @given(valid_boards, st.integers(0, 8)) def test_move_validity(b: str, m: int): if b[m] == '.': assert apply_move(b, 'X', m).count('.') == b.count('.') - 1 @given(valid_boards) def test_ai_optimality(b: str): v_opt = mm(norm(apply_move(b, 'O', best_ai_move(b))), 'X') assert all(v_opt <= mm(norm(apply_move(b, 'O', i)), 'X') for i in range(9) if b[i] == '.') # --- UI & Spielschleife --- if __name__ == '__main__': auto_mode = '--auto' in sys.argv def print_board(b, u, f): d = [f"\033[91m{i}\033[0m" if i in f else f"\033[92m{i}\033[0m" if i in u else '.' if b[i]=='.' else b[i] for i in range(9)] print(f"\n {d[0]} | {d[1]} | {d[2]} \n---+---+---\n {d[3]} | {d[4]} | {d[5]} \n---+---+---\n {d[6]} | {d[7]} | {d[8]} \n") b = norm(".........") while '.' in b and not win(b, 'X') and not win(b, 'O'): print(f"\n========================================\nVerbleibende distinkte Spielverläufe ab hier: {count_paths(b)}") if b.count('.') % 2 != 0: win_x = [i for i in range(9) if b[i] == '.' and win(apply_move(b, 'X', i), 'X')] win_o = [i for i in range(9) if b[i] == '.' and win(apply_move(b, 'O', i), 'O')] forced = win_x or win_o sym_moves = {} for i in range(9): if b[i] == '.': nb = norm(apply_move(b, 'X', i)) if nb not in sym_moves: sym_moves[nb] = i uniq = list(sym_moves.values()) print_board(b, uniq, forced) if auto_mode and (forced or len(uniq) == 1): m = forced[0] if forced else uniq[0] print(f"[\033[93mAUTO\033[0m] Führe determinierten Zug aus: {m}") b = norm(apply_move(b, 'X', m)) continue while True: try: m = int(input("Zug X (Grün=Optionen, Rot=Zwang): ")) if m in uniq or m in forced: b = norm(apply_move(b, 'X', m)) break elif 0 <= m <= 8 and b[m] == '.': print("Bitte wähle einen der farblich markierten Repräsentanten aus.") except ValueError: pass else: print("KI zieht...") # KI zieht im tatsächlichen Spiel weiterhin den Repräsentanten mit kleinstem Index b = norm(apply_move(b, 'O', best_ai_move(b))) print("\n========================================") print("Endstand:") print_board(b, [], []) print("Gewinner:", 'X' if win(b, 'X') else 'O' if win(b, 'O') else 'Unentschieden')
!uv run crosshair check generated-3.py
!uv run pytest generated-3.py
!printf "0\n1\n2\n2\n1\n0\n3\n" | uv run generated-3.py
============================= test session starts ==============================
platform linux -- Python 3.13.2, pytest-9.0.3, pluggy-1.6.0
rootdir: /home/voelkel/sciebo/hhu/eipy-26/eipy-skript
configfile: pyproject.toml
plugins: cov-5.0.0, hypothesis-6.152.9, jaxtyping-0.3.11, gremlins-1.8.1, anyio-4.13.0, typeguard-4.5.2, Faker-40.23.0, hydra-core-1.3.2, logfire-4.37.0
collected 2 items                                                              

generated-3.py ..                                                        [100%]

============================== 2 passed in 0.48s ===============================

========================================
Verbleibende distinkte Spielverläufe ab hier: 354

 0 | 1 | . 
---+---+---
 . | 4 | . 
---+---+---
 . | . | . 

Zug X (Grün=Optionen, Rot=Zwang): 
========================================
Verbleibende distinkte Spielverläufe ab hier: 31
KI zieht...

========================================
Verbleibende distinkte Spielverläufe ab hier: 31

 X | 1 | 2 
---+---+---
 . | O | 5 
---+---+---
 . | . | 8 

Zug X (Grün=Optionen, Rot=Zwang): 
========================================
Verbleibende distinkte Spielverläufe ab hier: 2
KI zieht...

========================================
Verbleibende distinkte Spielverläufe ab hier: 2

 X | X | O 
---+---+---
 3 | O | 5 
---+---+---
 6 | 7 | 8 

Zug X (Grün=Optionen, Rot=Zwang): Zug X (Grün=Optionen, Rot=Zwang): Zug X (Grün=Optionen, Rot=Zwang): Zug X (Grün=Optionen, Rot=Zwang): Zug X (Grün=Optionen, Rot=Zwang): 
========================================
Verbleibende distinkte Spielverläufe ab hier: 1
KI zieht...

========================================
Endstand:

 X | X | O 
---+---+---
 X | O | . 
---+---+---
 O | . | . 

Gewinner: O
%pycat generated-4.py
!uv run crosshair check generated-4.py
!uv run pytest generated-4.py
!printf "0\n1\n2\n2\n1\n0\n3\n" | uv run generated-4.py
============================= test session starts ==============================
platform linux -- Python 3.13.2, pytest-9.0.3, pluggy-1.6.0
rootdir: /home/voelkel/sciebo/hhu/eipy-26/eipy-skript
configfile: pyproject.toml
plugins: cov-5.0.0, hypothesis-6.152.9, jaxtyping-0.3.11, gremlins-1.8.1, anyio-4.13.0, typeguard-4.5.2, Faker-40.23.0, hydra-core-1.3.2, logfire-4.37.0
collected 2 items                                                              

generated-4.py ..                                                        [100%]

============================== 2 passed in 0.51s ===============================

========================================
Aktueller Pfad: Start
Pendente Zweige: 0 | Abgeschlossen: 0
Verbleibende distinkte Spielverläufe ab hier: 354

 0 | 1 | . 
---+---+---
 . | 4 | . 
---+---+---
 . | . | . 

Zug X (z.B. '1', '1,4', 'all', 'full'): 
========================================
Aktueller Pfad: X:0
Pendente Zweige: 0 | Abgeschlossen: 0
Verbleibende distinkte Spielverläufe ab hier: 31
KI verarbeitet optimale Züge...

========================================
Aktueller Pfad: X:0 -> O:4
Pendente Zweige: 0 | Abgeschlossen: 0
Verbleibende distinkte Spielverläufe ab hier: 31

 X | 1 | 2 
---+---+---
 . | O | 5 
---+---+---
 . | . | 8 

Zug X (z.B. '1', '1,4', 'all', 'full'): 
========================================
Aktueller Pfad: X:0 -> O:4 -> X:1
Pendente Zweige: 0 | Abgeschlossen: 0
Verbleibende distinkte Spielverläufe ab hier: 2
KI verarbeitet optimale Züge...

========================================
Aktueller Pfad: X:0 -> O:4 -> X:1 -> O:2
Pendente Zweige: 0 | Abgeschlossen: 0
Verbleibende distinkte Spielverläufe ab hier: 2

 X | X | O 
---+---+---
 3 | O | 5 
---+---+---
 6 | 7 | 8 

Zug X (z.B. '1', '1,4', 'all', 'full'): Ungültig. Wähle aus den farblich markierten Repräsentanten.
Zug X (z.B. '1', '1,4', 'all', 'full'): Ungültig. Wähle aus den farblich markierten Repräsentanten.
Zug X (z.B. '1', '1,4', 'all', 'full'): Ungültig. Wähle aus den farblich markierten Repräsentanten.
Zug X (z.B. '1', '1,4', 'all', 'full'): Ungültig. Wähle aus den farblich markierten Repräsentanten.
Zug X (z.B. '1', '1,4', 'all', 'full'): 
========================================
Aktueller Pfad: X:0 -> O:4 -> X:1 -> O:2 -> X:3
Pendente Zweige: 0 | Abgeschlossen: 0
Verbleibende distinkte Spielverläufe ab hier: 1
KI verarbeitet optimale Züge...
[1] Ast beendet (Sieg O): X:0 -> O:4 -> X:1 -> O:2 -> X:3 -> O:6

##################################################
ZUSAMMENFASSUNG DER EXPLORATION
##################################################
Komplett explorierte Endstände : 1
Davon Sieg X                   : 0
Davon Sieg KI (O)              : 1
Davon Unentschieden            : 0
Noch in Queue verblieben       : 0
##################################################

%pycat generated-5.py
!uv run crosshair check generated-5.py
!uv run pytest generated-5.py
!printf "0\nfull\n" | uv run generated-5.py
Fetching long content....
%pycat generated-6.py
!uv run crosshair check generated-6.py
!uv run pytest generated-6.py
!printf "0\n4\n" | uv run generated-6.py
============================= test session starts ==============================
platform linux -- Python 3.13.2, pytest-9.0.3, pluggy-1.6.0
rootdir: /home/voelkel/sciebo/hhu/eipy-26/eipy-skript
configfile: pyproject.toml
plugins: cov-5.0.0, hypothesis-6.152.9, jaxtyping-0.3.11, gremlins-1.8.1, anyio-4.13.0, typeguard-4.5.2, Faker-40.23.0, hydra-core-1.3.2, logfire-4.37.0
collected 4 items                                                              

generated-6.py ....                                                      [100%]

============================== 4 passed in 0.87s ===============================
Starte Tic-Tac-Toe...

========================================
Aktueller Pfad: Start
Pendente Zweige: 0 | Abgeschlossen: 0
Verbleibende distinkte Spielverläufe ab hier: 354

 0 | 1 | . 
---+---+---
 . | 4 | . 
---+---+---
 . | . | . 

Zug P1 (z.B. '1', '1,4', 'all', 'full'): Traceback (most recent call last):
  File "/home/voelkel/sciebo/hhu/eipy-26/eipy-skript/part-practical/generated-6.py", line 260, in <module>
    queue.insert(0, (g.norm(g.apply_move_custom(b, m, sym)), path + [f"P1:{m}({sym})"], False))
                            ^^^^^^^^^^^^^^^^^^^
AttributeError: 'TicTacToe' object has no attribute 'apply_move_custom'
%pycat gen7engine.py
%pycat gen7ui.py
import sys import deal from gen7engine import TicTacToe, Notakto, WildTicTacToe, Engine, GameAnalyzer def print_board(b, u, f): d = [ f"\033[91m{i}\033[0m" if i in f else f"\033[92m{i}\033[0m" if i in u else "." if b[i] == "." else b[i] for i in range(9) ] print(f"\n {d[0]} | {d[1]} | {d[2]} \n---+---+---\n {d[3]} | {d[4]} | {d[5]} \n---+---+---\n {d[6]} | {d[7]} | {d[8]} \n") def run_ui(): deal.activate() auto_mode = "--auto" in sys.argv if "--notakto" in sys.argv: g = Notakto() elif "--wild" in sys.argv: g = WildTicTacToe() else: g = TicTacToe() eng = Engine(g) analyzer = GameAnalyzer(g, eng) queue = [(g.norm(g.initial()), [], False)] try: while queue: norm_b, path, is_full = queue.pop(0) term, val = g.is_terminal(norm_b) if term: print(f"Ast beendet (Wert: {val}): {' -> '.join(path)}") continue print(f"\nDistinkte Spielverläufe ab hier: {analyzer.count_paths(norm_b)}") if g.is_turn_p1(norm_b): if path: print(f"\n\033[94m[{len(path)}] Aktueller Ast:\033[0m {' -> '.join(path)}") else: print(f"\n\033[94m[0] Wurzelknoten (Start)\033[0m") forced = g.forced_moves(norm_b) uniq = g.get_canonical_moves(norm_b) print_board(norm_b, uniq, forced) if auto_mode and (forced or len(uniq) == 1): m = forced[0] if forced else uniq[0] queue.insert(0, (g.norm(g.apply_move(norm_b, m)), path + [f"P1:{m}"], is_full)) continue inp = "full" if is_full else input("Zug (z.B. '1' oder '1,O'): ").lower() if inp in ["full", "all"]: for m in (forced if forced else uniq): queue.insert(0, (g.norm(g.apply_move(norm_b, m)), path + [f"P1:{m}"], (inp == "full"))) else: try: p = inp.split(",") m = int(p[0]) s = p[1].upper() if len(p) > 1 else None if m in g.valid_moves(norm_b): nb = g.apply_move(norm_b, m, s) queue.insert(0, (g.norm(nb), path + [f"P1:{m}({s if s is not None else 'X'})"], False)) else: print(f"Zug {m} ist auf diesem Brett nicht erlaubt!") queue.insert(0, (norm_b, path, is_full)) except Exception as e: print("Eingabefehler:", e) queue.insert(0, (norm_b, path, is_full)) else: moves = [(m, s) for m in g.valid_moves(norm_b) for s in (["X", "O"] if isinstance(g, WildTicTacToe) else ["None"])] def eval_move(m, s): return -eng.mm(g.norm(g.apply_move(norm_b, m, s if s != "None" else None))) opt_val = max(eval_move(m, s) for m, s in moves) for m, s in moves: if eval_move(m, s) == opt_val: nb = g.norm(g.apply_move(norm_b, m, s if s != "None" else None)) queue.insert(0, (nb, path + [f"KI:{m}({s if s != 'None' else g.get_symbol(norm_b, m)})"], is_full)) except KeyboardInterrupt: print("\nAbbruch.") if __name__ == "__main__": run_ui()
%pycat gen7tests.py
import pytest import deal from hypothesis import given, strategies as st from gen7engine import TicTacToe, Notakto, WildTicTacToe, Engine, Game, GameAnalyzer # Aktiviert deal-Contracts für Laufzeitprüfungen in den Tests deal.activate() valid_ttt = st.text(alphabet="XO.", min_size=9, max_size=9).filter( lambda b: "." in b and not TicTacToe().is_terminal(b)[0] and abs(b.count("X") - b.count("O")) <= 1 ) valid_notakto = st.text(alphabet="X.", min_size=9, max_size=9).filter( lambda b: "." in b and not Notakto().is_terminal(b)[0] ) def test_canonical_moves_initial_board(): g = TicTacToe() b = g.initial() canonical = g.get_canonical_moves(b) assert canonical == [0, 1, 4], f"Erwartet [0, 1, 4], aber erhalten: {canonical}" def test_engine_perfect_play_draw(): """Nullsummen-Garantie: Perfektes Spiel in klassischem Tic-Tac-Toe führt zum Remis.""" g = TicTacToe() eng = Engine(g) assert eng.mm(g.initial()) == 0 @given(valid_ttt) def test_norm_idempotence_ttt(b: str): """Property-based Test: norm(norm(b)) == norm(b).""" g = TicTacToe() assert g.norm(g.norm(b)) == g.norm(b) @given(valid_ttt) def test_ttt_ai_optimality(b: str): g, eng = TicTacToe(), Engine(TicTacToe()) moves = g.valid_moves(b) if moves: v_opt = max(-eng.mm(g.norm(g.apply_move(b, m))) for m in moves) assert all(v_opt >= -eng.mm(g.norm(g.apply_move(b, m))) for m in moves) @given(valid_notakto) def test_notakto_ai_optimality(b: str): g, eng = Notakto(), Engine(Notakto()) moves = g.valid_moves(b) if moves: v_opt = max(-eng.mm(g.norm(g.apply_move(b, m))) for m in moves) assert all(v_opt >= -eng.mm(g.norm(g.apply_move(b, m))) for m in moves) @pytest.mark.parametrize("game_class", [TicTacToe, Notakto]) def test_terminal_invariance(game_class): g = game_class() test_boards = ["XXXOO....", "XOXOXOXOX"] for b in test_boards: if b.count('X') + b.count('O') != 9 and not any(all(b[i] != '.' and b[i] == b[w[0]] for i in w) for w in g.W): continue # Skip invalid intermediate states for the specific game term_b, val_b = g.is_terminal(b) term_n, val_n = g.is_terminal(g.norm(b)) assert term_b == term_n assert val_b == val_n def test_ui_logic_consistency(): g = WildTicTacToe() b = g.initial() m = 4 nb = g.apply_move(b, m, "X") with pytest.raises(deal.PreContractError): g.apply_move(nb, m) # Zug auf bereits besetztes Feld
!uv run crosshair check gen7engine.py
!uv run pytest gen7tests.py
============================= test session starts ==============================
platform linux -- Python 3.13.2, pytest-9.0.3, pluggy-1.6.0
rootdir: /home/voelkel/sciebo/hhu/eipy-26/eipy-skript
configfile: pyproject.toml
plugins: cov-5.0.0, hypothesis-6.152.9, jaxtyping-0.3.11, gremlins-1.8.1, anyio-4.13.0, typeguard-4.5.2, Faker-40.23.0, hydra-core-1.3.2, logfire-4.37.0
collected 8 items                                                              

gen7tests.py ........                                                    [100%]

============================== 8 passed in 0.94s ===============================
!printf "0\n4\nfull" | uv run gen7ui.py

Distinkte Spielverläufe ab hier: 354

[0] Wurzelknoten (Start)

 0 | 1 | . 
---+---+---
 . | 4 | . 
---+---+---
 . | . | . 

Zug (z.B. '1' oder '1,O'): 
Distinkte Spielverläufe ab hier: 31

Distinkte Spielverläufe ab hier: 31

[2] Aktueller Ast: P1:0(X) -> KI:4(O)

 X | 1 | 2 
---+---+---
 . | O | 5 
---+---+---
 . | . | 8 

Zug (z.B. '1' oder '1,O'): Zug 4 ist auf diesem Brett nicht erlaubt!

Distinkte Spielverläufe ab hier: 31

[2] Aktueller Ast: P1:0(X) -> KI:4(O)

 X | 1 | 2 
---+---+---
 . | O | 5 
---+---+---
 . | . | 8 

Zug (z.B. '1' oder '1,O'): 
Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[4] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:7(O)

 X | O | 2 
---+---+---
 3 | O | 5 
---+---+---
 6 | 7 | X 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:7(O) -> P1:7 -> KI:2(O)

 X | X | O 
---+---+---
 3 | O | 5 
---+---+---
 6 | O | X 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:7(O) -> P1:7 -> KI:2(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | 5 
---+---+---
 X | O | X 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:8 -> KI:7(O) -> P1:7 -> KI:2(O) -> P1:6 -> KI:3(O) -> P1:5

Distinkte Spielverläufe ab hier: 1

[4] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:5(O)

 X | O | 2 
---+---+---
 3 | O | 5 
---+---+---
 6 | 7 | X 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:5(O) -> P1:7 -> KI:2(O)

 X | X | O 
---+---+---
 3 | O | 5 
---+---+---
 6 | O | X 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:5(O) -> P1:7 -> KI:2(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | 5 
---+---+---
 X | O | X 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:8 -> KI:5(O) -> P1:7 -> KI:2(O) -> P1:6 -> KI:3(O) -> P1:5

Distinkte Spielverläufe ab hier: 1

[4] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:3(O)

 X | O | 2 
---+---+---
 3 | O | 5 
---+---+---
 6 | 7 | X 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:3(O) -> P1:7 -> KI:2(O)

 X | X | O 
---+---+---
 3 | O | 5 
---+---+---
 6 | O | X 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:3(O) -> P1:7 -> KI:2(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | 5 
---+---+---
 X | O | X 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:8 -> KI:3(O) -> P1:7 -> KI:2(O) -> P1:6 -> KI:3(O) -> P1:5

Distinkte Spielverläufe ab hier: 1

[4] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:1(O)

 X | O | 2 
---+---+---
 3 | O | 5 
---+---+---
 6 | 7 | X 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:1(O) -> P1:7 -> KI:2(O)

 X | X | O 
---+---+---
 3 | O | 5 
---+---+---
 6 | O | X 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:8 -> KI:1(O) -> P1:7 -> KI:2(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | 5 
---+---+---
 X | O | X 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:8 -> KI:1(O) -> P1:7 -> KI:2(O) -> P1:6 -> KI:3(O) -> P1:5

Distinkte Spielverläufe ab hier: 23

Distinkte Spielverläufe ab hier: 13

[4] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O)

 X | 1 | 2 
---+---+---
 3 | O | X 
---+---+---
 6 | 7 | O 


Distinkte Spielverläufe ab hier: 5

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:6(O)

 X | 1 | O 
---+---+---
 3 | O | X 
---+---+---
 6 | X | O 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:6(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:6(O) -> P1:6 -> KI:3(O) -> P1:7

Distinkte Spielverläufe ab hier: 4

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:3(O)

 X | O | 2 
---+---+---
 3 | O | X 
---+---+---
 6 | X | O 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:3(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:3(O) -> P1:6 -> KI:3(O) -> P1:8

Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:3(O) -> P1:3 -> KI:2(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 6 | X | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:3(O) -> P1:3 -> KI:2(O) -> P1:6

Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:3(O) -> P1:2 -> KI:8(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:3(O) -> P1:2 -> KI:8(O) -> P1:7

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:3(O) -> P1:2 -> KI:7(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:3(O) -> P1:2 -> KI:7(O) -> P1:8

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:2(O)

 X | 1 | O 
---+---+---
 3 | O | X 
---+---+---
 6 | X | O 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:2(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:2(O) -> P1:6 -> KI:3(O) -> P1:7

Distinkte Spielverläufe ab hier: 4

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:1(O)

 X | O | 2 
---+---+---
 3 | O | X 
---+---+---
 6 | X | O 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:1(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:1(O) -> P1:6 -> KI:3(O) -> P1:8

Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:1(O) -> P1:3 -> KI:2(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 6 | X | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:1(O) -> P1:3 -> KI:2(O) -> P1:6

Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:1(O) -> P1:2 -> KI:8(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:1(O) -> P1:2 -> KI:8(O) -> P1:7

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:1(O) -> P1:2 -> KI:7(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:7 -> KI:1(O) -> P1:2 -> KI:7(O) -> P1:8

Distinkte Spielverläufe ab hier: 4

Distinkte Spielverläufe ab hier: 4

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:6 -> KI:1(O)

 X | O | X 
---+---+---
 3 | O | 5 
---+---+---
 O | X | 8 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:6 -> KI:1(O) -> P1:8 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | 5 
---+---+---
 X | O | X 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:6 -> KI:1(O) -> P1:8 -> KI:3(O) -> P1:5

Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:6 -> KI:1(O) -> P1:5 -> KI:2(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:6 -> KI:1(O) -> P1:5 -> KI:2(O) -> P1:7

Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:6 -> KI:1(O) -> P1:3 -> KI:8(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:6 -> KI:1(O) -> P1:3 -> KI:8(O) -> P1:7

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:6 -> KI:1(O) -> P1:3 -> KI:7(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:6 -> KI:1(O) -> P1:3 -> KI:7(O) -> P1:8

Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:3 -> KI:2(O)

 X | X | O 
---+---+---
 3 | O | 5 
---+---+---
 6 | X | O 


Distinkte Spielverläufe ab hier: 1
Ast beendet (Wert: -1): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:3 -> KI:2(O) -> P1:5 -> KI:6(O)

Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 2

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:2 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | 5 
---+---+---
 X | 7 | 8 


Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:2 -> KI:3(O) -> P1:5 -> KI:8(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:2 -> KI:3(O) -> P1:5 -> KI:8(O) -> P1:7

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:2 -> KI:3(O) -> P1:5 -> KI:7(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:2 -> KI:3(O) -> P1:5 -> KI:7(O) -> P1:8

Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:1 -> KI:2(O)

 X | X | O 
---+---+---
 3 | O | X 
---+---+---
 6 | 7 | O 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:1 -> KI:2(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:8(O) -> P1:1 -> KI:2(O) -> P1:6 -> KI:3(O) -> P1:7

Distinkte Spielverläufe ab hier: 1

[4] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:7(O)

 X | 1 | 2 
---+---+---
 3 | O | X 
---+---+---
 6 | O | 8 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:7(O) -> P1:1 -> KI:2(O)

 X | X | O 
---+---+---
 3 | O | X 
---+---+---
 6 | O | 8 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:7(O) -> P1:1 -> KI:2(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:7(O) -> P1:1 -> KI:2(O) -> P1:6 -> KI:3(O) -> P1:8

Distinkte Spielverläufe ab hier: 4

[4] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:2(O)

 X | 1 | O 
---+---+---
 3 | O | X 
---+---+---
 6 | 7 | 8 


Distinkte Spielverläufe ab hier: 4

Distinkte Spielverläufe ab hier: 4

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:2(O) -> P1:6 -> KI:1(O)

 X | O | X 
---+---+---
 3 | O | 5 
---+---+---
 O | X | 8 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:2(O) -> P1:6 -> KI:1(O) -> P1:8 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | 5 
---+---+---
 X | O | X 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:2(O) -> P1:6 -> KI:1(O) -> P1:8 -> KI:3(O) -> P1:5

Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:2(O) -> P1:6 -> KI:1(O) -> P1:5 -> KI:2(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:2(O) -> P1:6 -> KI:1(O) -> P1:5 -> KI:2(O) -> P1:7

Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:2(O) -> P1:6 -> KI:1(O) -> P1:3 -> KI:8(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:2(O) -> P1:6 -> KI:1(O) -> P1:3 -> KI:8(O) -> P1:7

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:2(O) -> P1:6 -> KI:1(O) -> P1:3 -> KI:7(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:2(O) -> P1:6 -> KI:1(O) -> P1:3 -> KI:7(O) -> P1:8

Distinkte Spielverläufe ab hier: 5

[4] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O)

 X | O | 2 
---+---+---
 3 | O | X 
---+---+---
 6 | 7 | 8 


Distinkte Spielverläufe ab hier: 5

Distinkte Spielverläufe ab hier: 4

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:8(O)

 X | O | 2 
---+---+---
 3 | O | X 
---+---+---
 6 | X | O 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:6 -> KI:3(O) -> P1:8

Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:3 -> KI:2(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 6 | X | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:3 -> KI:2(O) -> P1:6

Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:2 -> KI:8(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:2 -> KI:8(O) -> P1:7

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:2 -> KI:7(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:2 -> KI:7(O) -> P1:8

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:6(O)

 X | O | 2 
---+---+---
 3 | O | X 
---+---+---
 O | X | 8 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:6(O) -> P1:2 -> KI:2(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:5 -> KI:1(O) -> P1:7 -> KI:6(O) -> P1:2 -> KI:2(O) -> P1:7

Distinkte Spielverläufe ab hier: 5

Distinkte Spielverläufe ab hier: 5

[4] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O)

 X | O | X 
---+---+---
 3 | O | . 
---+---+---
 6 | 7 | . 


Distinkte Spielverläufe ab hier: 5

Distinkte Spielverläufe ab hier: 4

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:8(O)

 X | O | X 
---+---+---
 3 | O | 5 
---+---+---
 O | X | 8 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:8 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | 5 
---+---+---
 X | O | X 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:8 -> KI:3(O) -> P1:5

Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:5 -> KI:2(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:5 -> KI:2(O) -> P1:7

Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:3 -> KI:8(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:3 -> KI:8(O) -> P1:7

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:3 -> KI:7(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:8(O) -> P1:3 -> KI:7(O) -> P1:8

Distinkte Spielverläufe ab hier: 4

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:6(O)

 X | O | X 
---+---+---
 3 | O | 5 
---+---+---
 O | X | 8 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:6(O) -> P1:8 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | 5 
---+---+---
 X | O | X 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:6(O) -> P1:8 -> KI:3(O) -> P1:5

Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:6(O) -> P1:5 -> KI:2(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:6(O) -> P1:5 -> KI:2(O) -> P1:7

Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:6(O) -> P1:3 -> KI:8(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:6(O) -> P1:3 -> KI:8(O) -> P1:7

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:6(O) -> P1:3 -> KI:7(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:6(O) -> P1:3 -> KI:7(O) -> P1:8

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:5(O)

 X | O | X 
---+---+---
 O | O | 5 
---+---+---
 6 | X | 8 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:5(O) -> P1:5 -> KI:2(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:5(O) -> P1:5 -> KI:2(O) -> P1:8

Distinkte Spielverläufe ab hier: 1

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:3(O)

 X | O | X 
---+---+---
 O | O | 5 
---+---+---
 6 | X | 8 


Distinkte Spielverläufe ab hier: 1

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:3(O) -> P1:5 -> KI:2(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:2 -> KI:1(O) -> P1:7 -> KI:3(O) -> P1:5 -> KI:2(O) -> P1:8

Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 2

[4] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:1 -> KI:2(O)

 X | X | O 
---+---+---
 3 | O | 5 
---+---+---
 6 | 7 | 8 


Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 2

[6] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:1 -> KI:2(O) -> P1:6 -> KI:3(O)

 X | X | O 
---+---+---
 O | O | 5 
---+---+---
 X | 7 | 8 


Distinkte Spielverläufe ab hier: 2

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:1 -> KI:2(O) -> P1:6 -> KI:3(O) -> P1:5 -> KI:8(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | 7 | O 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:1 -> KI:2(O) -> P1:6 -> KI:3(O) -> P1:5 -> KI:8(O) -> P1:7

Distinkte Spielverläufe ab hier: 1

[8] Aktueller Ast: P1:0(X) -> KI:4(O) -> P1:1 -> KI:2(O) -> P1:6 -> KI:3(O) -> P1:5 -> KI:7(O)

 X | X | O 
---+---+---
 O | O | X 
---+---+---
 X | O | 8 

Ast beendet (Wert: 0): P1:0(X) -> KI:4(O) -> P1:1 -> KI:2(O) -> P1:6 -> KI:3(O) -> P1:5 -> KI:7(O) -> P1:8