90 lines
2.7 KiB
Python
90 lines
2.7 KiB
Python
import random
|
|
from dataclasses import dataclass
|
|
|
|
@dataclass
|
|
class Move:
|
|
state: int
|
|
move: int
|
|
|
|
def optimal_move():
|
|
global state
|
|
for n in [1, 2, 3]:
|
|
if (state - n) % 4 == 1: # Wenn der andere Spieler bei diesem Zug verliert
|
|
return n
|
|
return random.randint(1, 3) # Wenn keine perfekte Wahl, dann irgendein Zug
|
|
|
|
def random_move():
|
|
return random.randint(1, 3)
|
|
|
|
def ki_move(lastMove, better_version):
|
|
global state
|
|
antiMoves = lostMoves.get(state)
|
|
if antiMoves == None:
|
|
return random.randint(1, 3)
|
|
availableMoves = [True, True, True]
|
|
for badMove in antiMoves:
|
|
availableMoves[badMove - 1] = False
|
|
for i, good in enumerate(availableMoves):
|
|
if good:
|
|
return i + 1
|
|
|
|
# Es gibt keine guten Züge mehr, also muss der letzte Zug schlecht gewesen sein.
|
|
if better_version:
|
|
addLostMove(lastMove.state, lastMove.move)
|
|
return random.randint(1, 3)
|
|
|
|
def makeMove(move): # gibt True zurück, wenn der Spieler verloren hat
|
|
global state
|
|
state -= move
|
|
|
|
# state kann auch kleiner 0 sein, da der Einfachheit halber am Ende auch Züge gemacht werden,
|
|
# die mehr alle Hölzchen wegnehmen. Dies wird dann so betrachtet, wie als wären 0 Hölzchen da.
|
|
return state <= 0
|
|
|
|
def addLostMove(state, move):
|
|
moves = lostMoves.get(state)
|
|
if moves == None:
|
|
moves = []
|
|
moves.append(move)
|
|
lostMoves[state] = moves
|
|
|
|
def game(train, opponent, better_version):
|
|
global state
|
|
state = 12
|
|
lastMove = None
|
|
while True:
|
|
# KI beginnt, sonst kann sie nicht gewinnen
|
|
move = ki_move(lastMove, better_version)
|
|
lost = makeMove(move)
|
|
if lost:
|
|
if train:
|
|
addLostMove(state + move, move)
|
|
return 0 # optimale Strategie hat gewonnen
|
|
lastMove = Move(state + move, move)
|
|
|
|
move = opponent()
|
|
lost = makeMove(move)
|
|
if lost:
|
|
return 1 # KI hat gewonnen
|
|
|
|
state = 12
|
|
lostMoves = {}
|
|
|
|
# train
|
|
opponents = [random_move, optimal_move]
|
|
for ki_version in [False, True]:
|
|
for train_opponent in opponents:
|
|
for eval_opponent in opponents:
|
|
ki_text = "optimale Version" if ki_version else "erste Version"
|
|
print(f"KI: {ki_text} trainiert mit {train_opponent.__name__} und evaluiert mit {eval_opponent.__name__}")
|
|
for _ in range(1000):
|
|
game(train=True, opponent=train_opponent, better_version=ki_version)
|
|
|
|
# eval
|
|
numberEvalGames = 100000
|
|
wonGames = 0
|
|
for _ in range(numberEvalGames):
|
|
wonGames += game(False, opponent=eval_opponent, better_version=ki_version)
|
|
|
|
print(f"Die KI hat {wonGames / numberEvalGames * 100}% der Spiele gewonnen.\n")
|