Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

some:09.01.2020

Protokoll

Heute haben wir versucht den Code, den wir letzte Woche gefunden haben, auf unser selbst gebautes Spiel zu übertragen. Hierbei lernt die Ai, indem alle möglichen Zustände und die Werte, also ob der Zustand gut oder schlecht ist, in einer Tabelle stehen und die Ai so einfach bestimmen kann, was der beste Zug ist, indem sie einfach den zustand mit dem höchsten Wert und somit der höchsten Gewinnwahrscheinlichkeit auswählt. Da unser Spiel ganz andere Methoden verwendet, als das, was wir gefunden haben, ist uns die Umstellung nicht so leicht gefallen. So ist unter anderem folgender unvollständiger Code entstanden.

import turtle as t
import numpy as np
from math import inf as infinity
import itertools
import random
 
 
def play_move(state, player, block_num):#Hier wird der ausgewählte Zug in die Matrix übertragen
    if state[int((block_num-1)/3)][(block_num-1)%3] is ' ':
        state[int((block_num-1)/3)][(block_num-1)%3] = player
        if(player == 'X'):
            printX(int((block_num-1)/3), (block_num-1)%3)
        else:
            print0(int((block_num-1)/3), (block_num-1)%3)
 
def copy_game_state(state):#Der Spielzustand wird kopiert
    new_state = [[' ',' ',' '],[' ',' ',' '],[' ',' ',' ']]
    for i in range(3):
        for j in range(3):
            new_state[i][j] = state[i][j]
    return new_state
 
def check_current_state(game_state):#Überprüfung ob wer gewonnen hat oder das Spiel unentschieden ausgegangen ist
    # Check horizontals
    if (game_state[0][0] == game_state[0][1] and game_state[0][1] == game_state[0][2] and game_state[0][0] is not ' '):
        return game_state[0][0], "Done"
    if (game_state[1][0] == game_state[1][1] and game_state[1][1] == game_state[1][2] and game_state[1][0] is not ' '):
        return game_state[1][0], "Done"
    if (game_state[2][0] == game_state[2][1] and game_state[2][1] == game_state[2][2] and game_state[2][0] is not ' '):
        return game_state[2][0], "Done"
 
    # Check verticals
    if (game_state[0][0] == game_state[1][0] and game_state[1][0] == game_state[2][0] and game_state[0][0] is not ' '):
        return game_state[0][0], "Done"
    if (game_state[0][1] == game_state[1][1] and game_state[1][1] == game_state[2][1] and game_state[0][1] is not ' '):
        return game_state[0][1], "Done"
    if (game_state[0][2] == game_state[1][2] and game_state[1][2] == game_state[2][2] and game_state[0][2] is not ' '):
        return game_state[0][2], "Done"
 
    # Check diagonals
    if (game_state[0][0] == game_state[1][1] and game_state[1][1] == game_state[2][2] and game_state[0][0] is not ' '):
        return game_state[1][1], "Done"
    if (game_state[2][0] == game_state[1][1] and game_state[1][1] == game_state[0][2] and game_state[2][0] is not ' '):
        return game_state[1][1], "Done"
 
    # Check if draw
    draw_flag = 0
    for i in range(3):
        for j in range(3):
            if game_state[i][j] is ' ':
                draw_flag = 1
    if draw_flag is 0:
        return None, "Draw"
 
    return None, "Not Done"
 
def comstarts():#Aufruf damit der Computer anfängt zu spielen
    global playerChoice
    newGame('O')
    playerChoice = 0
 
def playerstarts():#Aufruf, damit man selber anfangen kann
    global playerChoice
    newGame('X')
    playerChoice = 1
 
def newGame(player_choice):#Es wird "aufgeräumt" und Platz für ein neues Spiel gemacht
    global NoWin
    global WinsPlayer
    global WinsCom
    if(check_current_state(game_state)== "Done" or NoWin == 0 and WinsPlayer == 0 and WinsCom == 0):
        start.up()
        start.clear()
        start.setx(-2)
        start.hideturtle()
        start.write(WinsPlayer)
        start.sety(start.ycor()+2)
        start.write(WinsCom)
        start.sety(start.ycor()+2)
        start.write(NoWin)
        t.clear()
        if(player_choice == 'O'):
            block_choice = getBestMove(game_state, players[0])
            play_move(game_state ,players[0], block_choice)
 
 
def wheretogo(x, y):#Prüft wo man hingesetzt hat
    '''
    prüft, wo der Spieler hinklickt und gibt je nachdem eine Zahl zwischen 1 und 9 zurück.
    '''
    global game_state
    if(x > 0 and x <=10):
        spalte = 1
    if(x >10 and x <=20):
        spalte = 2
    if(x >20 and x <=30):
        spalte = 3
    if(y > 0 and y <=10):
        zeile = 0
    if(y >10 and y <=20):
        zeile = 1
    if(y >20 and y <=30):
        zeile = 2
    block_choice = 3*zeile +spalte
    if(game_state[int((block_choice-1)/3)][(block_choice-1)%3] == ' '):
        t.up()
        t.setx((spalte-1)*10+5)
        t.sety(zeile*10+5)
        game(block_choice)
 
 
def printX(zeile, spalte):#Zeigt ein X
    t.up()
    t.setx(spalte*10+5)
    t.sety(zeile*10+5)
    t.down()
    t.left(45)
    t.forward(5)
    t.backward(10)
    t.forward(5)
    t.left(90)
    t.forward(5)
    t.backward(10)
    t.forward(5)
    t.right(135)
    t.up()
 
def print0(zeile, spalte):#Zeigt einen Kreis
    t.up()
    t.setx(spalte*10+5)
    t.sety(zeile*10+5)
    t.down()
    t.up()
    t.right(90)
    t.forward(4)
    t.left(90)
    t.down()
    t.circle(4)
    t.up()
 
def tttfeld():#Grundlage für das ganze Tic Tac Toe Feld
    """
    Malt ein 3x3 Feld.
    """
    t.setworldcoordinates(0,30,30,0)
    spalten = t.Turtle()
    spalten.left(90)
    zeilen = t.Turtle()
    spalten.speed(0)
    zeilen.speed(0)
    spalten.hideturtle()
    zeilen.hideturtle()
    for i in range(4):
        spalten.setx(i*10)
        zeilen.sety(i*10)
        spalten.forward(30)
        zeilen.forward(30)
        spalten.sety(0)
        zeilen.setx(0)
    zeilen.goto(0,0)
    spalten.goto(0,0)
    zeilen.up()
    zeilen.setx(-3)
    zeilen.write("Siege vom Spieler:", align="right")
    zeilen.sety(zeilen.ycor()+2)
    zeilen.write("Siege vom Computer:", align="right")
    zeilen.sety(zeilen.ycor()+2)
    zeilen.write("Unentschieden:", align="right")
    zeilen.goto(0,0)
    zeilen.goto(31,15)
    zeilen.write("Wer soll anfangen? Du(X) oder der Computer(O)?", align="left", font=("Arial", 8, "normal"))
    zeilen.down()
 
 
 
def update_state_value(curr_state_idx, next_state_idx, learning_rate):#Die Ai passt den Wert für einen Zustand an
    new_value = state_values_for_AI[curr_state_idx] + learning_rate*(state_values_for_AI[next_state_idx]  - state_values_for_AI[curr_state_idx])
    state_values_for_AI[curr_state_idx] = new_value
 
def getBestMove(state, player):#Hier wird der beste Zug für die Ai ermittelt
    '''
    Reinforcement Learning Algorithm
    '''    
    moves = []
    curr_state_values = []
    empty_cells = []
    for i in range(3):#Hier werden die leeren Felder bestimmt
        for j in range(3):
            if state[i][j] is ' ':
                empty_cells.append(i*3 + (j+1))
 
    for empty_cell in empty_cells:#Hier wird jeder mögliche Zug überprüft
        moves.append(empty_cell)
        new_state = copy_game_state(state)
        #play_move(new_state, player, empty_cell)
        next_state_idx = list(states_dict.keys())[list(states_dict.values()).index(new_state)]
        curr_state_values.append(state_values_for_AI[next_state_idx])
 
    best_move_idx = np.argmax(curr_state_values)#Und hier der Zug mit dem höchsten Wert, also der beste Zug ermittelt
    best_move = moves[best_move_idx]
    return best_move
 
def game(block_choice):#Das eigentliche Spiel
    global NoWin
    global WinsPlayer
    global WinsCom
    global game_state
    global playerChoice
    current_player_idx=playerChoice
 
    current_state = "Not Done"  
    winner = None
    if current_player_idx == 0:
        player_choice = 'X'
    else: 
        player_choice = 'O'
    curr_state_idx = list(states_dict.keys())[list(states_dict.values()).index(game_state)]
    if current_player_idx == 0: #Mensch macht ersten Zug
        play_move(game_state ,players[current_player_idx], block_choice)
        current_player_idx = 1 
        block_choice = getBestMove(game_state, players[current_player_idx])
        play_move(game_state ,players[current_player_idx], block_choice)
 
    else:   #Computer macht ersten Zug
        play_move(game_state ,players[current_player_idx], block_choice)
        current_player_idx = 0
        block_choice = getBestMove(game_state, players[current_player_idx])
        play_move(game_state ,players[current_player_idx], block_choice)
 
    print(game_state)
    winner, current_state = check_current_state(game_state)
    if winner is not None:
        t.up()
        t.goto(15,15)
        if(str(winner) == player_choice):
            WinsPlayer = WinsPlayer +1
            t.write("Du hast gewonnen", align="center", font=("Arial", 32, "normal"))
        else:
            WinsCom = WinsCom +1
            t.write("Du hast verloren", align="center", font=("Arial", 32, "normal"))
        t.goto(40,15)
        t.write("Wer soll anfangen? Du(X) oder der Computer(O)?", align="left", font=("Arial", 8, "normal"))
    if current_state is "Draw":
        NoWin = NoWin +1
        t.up()
        t.goto(15,15)
        t.write("Unentschieden", align="center", font=("Arial", 30, "normal"))
        t.goto(40,15)
        t.write("Wer soll anfangen? Du(X) oder der Computer(O)?", align="left", font=("Arial", 8, "normal"))
# PLaying
 
# Initialize state values
player = ['X','O',' ']
states_dict = {}
all_possible_states = [[list(i[0:3]),list(i[3:6]),list(i[6:10])] for i in itertools.product(player, repeat = 9)]
n_states = len(all_possible_states) # 2 players, 9 spaces
n_actions = 9   # 9 spaces
state_values_for_AI = np.full((n_states),0.0)
print("n_states = %i \nn_actions = %i"%(n_states, n_actions))
 
for i in range(n_states):
    states_dict[i] = all_possible_states[i]
    winner, _ = check_current_state(states_dict[i])
    if winner == 'O':   # AI won
        state_values_for_AI[i] = 1
    elif winner == 'X':   # AI lost
        state_values_for_AI[i] = -1
 
 
 
 
 
start = t.Turtle() 
start.speed(0)
t.speed(0)
t.hideturtle()
screen=t.Screen()
WinsPlayer = 0
WinsCom = 0
NoWin = 0
playerChoice = 0
game_state = [[' ',' ',' '],
              [' ',' ',' '],
              [' ',' ',' ']]
players = ['X','O']
 
current_state = "Not Done"
tttfeld()
 
 
#LOAD TRAINED STATE VALUES
state_values_for_AI = np.loadtxt('trained_state_values_O.txt', dtype=np.float64)
 
 
 
screen.onclick(wheretogo)
screen.onkeypress(comstarts, "o")
screen.onkeypress(playerstarts, "x")
screen.listen()
t.mainloop()
 
t.exitonclick()

Protokoll für den 23.1.2020 Wir haben angefangen eine Funkiton zu schreiben um die umgebung eines neu gesetzten Stein zu prüfen und festzustellen ob dadurch eine Prtei gewinnt. Funktion zum checken von jedem Array:

def Summe(self, zeile, spalte): #muss noch mit der umgebung verknüpft werden
        for i in range(len(a)-3):
            b=a[i:i+4]
            if (sum(b)== 4 or sum(b)==-4):
                return sum(b) 

Spalte: a=board[:6, s-1:s] Diagonale: a=np.diagonal(board, s-z) Zeile: a=board[:1] #für die Zeile

Protokoll für den 06.02.2020 Training Algorithmus fertig Funktion fertig - Wissen ob 4 in einer Reihe sind

Problem: Anzahl möglicher Zustände über 10 hoch 20 D.h. das Programm läuft so noch nicht

Kommentierte Version des Codes mit dem NN:

import random
import gym
import numpy as np
from collections import deque
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import Adam
import keras
 
 
def ViergewinntAnfangsmatrix():
    #game_state[x,0,0] greift auf das zu benutzende Feld zu (x=0/1 sind Spiele; x=2 zeigt leere Felder)
    #game_state[0,x,0] greift auf die Zeile zu
    #game_state[0,0,x] greift auf die Spalte zu
    game_state = np.zeros_like(np.arange(42*3).reshape(3,6,7))
    game_state[2]=1
    return game_state
 
def check_array(a):
    #Prüft ob in einem Array 4 in einer Reihe sind
    for i in range(len(a)-3):
        b=sum(a[i:i+4])   
        if (b== 4): return 4
 
def checkgewonnen(game_state):
    #Prüft ob jemand gewonnen hat
    Winstate = game_state[0]
    Losestate = game_state[1]
    Drawstate = game_state[2] 
   #Spalte
    for i in range(7):
        a=check_array(Winstate[:6, i:i+1].reshape(6,))
        b=check_array(Losestate[:6, i:i+1].reshape(6,))
        if(a==4):return "Win"
        if(b==4):return "Lose"
 
    #Diagonalen:
    for i in range(3): 
        a=check_array(np.diagonal(Winstate, i+1))
        b=check_array(np.diagonal(Losestate, i+1))
        if(a==4):return "Win"
        if(b==4):return "Lose"
        a=check_array(np.diagonal(Winstate, -i))
        b=check_array(np.diagonal(Losestate, -i))
        if(a==4):return "Win"
        if(b==4):return "Lose"
        a=check_array(np.fliplr(Winstate).diagonal(i+1))
        b=check_array(np.fliplr(Losestate).diagonal(i+1))
        if(a==4):return "Win"
        if(b==4):return "Lose"
        a=check_array(np.fliplr(Winstate).diagonal(-i))
        b=check_array(np.fliplr(Losestate).diagonal(-i))
        if(a==4):return "Win"
        if(b==4):return "Lose"
 
    #Zeile: 
    for i in range(6):
        a=check_array(Winstate[i:i+1].reshape(7,))
        b=check_array(Losestate[i:i+1].reshape(7,))
        if(a==4):return "Win"
        if(b==4):return "Lose"
    # Check if draw
    for i in range(7):  
        if(Drawstate[0,i] == 1):
           return None
    return "Draw"
 
 
 
class Agent:
    def __init__(self, state_size, action_size):
        self.state_size = state_size
        self.action_size = action_size
        self.memory = deque(maxlen=2000) #Erinnerungen
        self.gamma = 1.0   # discount rate
        self.epsilon = 1.0  # exploration rate
        self.epsilon_min = 0.01
        self.epsilon_decay = 0.999
        self.learning_rate = 0.001
        self.model = self._build_model() #NN wird gebaut
 
    def _build_model(self):
        # Einfaches NN 
        #Müssen weitere Layer hinzugefügt werden, da 4gewinnt komplexer ist?
        model = Sequential() #Standard komplett vernetztes NN
        model.add(Dense(48, input_dim=self.state_size, activation='relu', 
                        kernel_regularizer=keras.regularizers.l2(0.00001)))#Input muss angepasst werden
        model.add(Dropout(0.3)) # Soll "Overfitting" vermeiden
        model.add(Dense(24, activation='relu', kernel_regularizer=keras.regularizers.l2(0.00001)))#Hidden-Layer
        model.add(Dense(self.action_size, activation='linear'))#Output im Bezug auf mögliche Aktionen (hier 7)
        model.compile(loss='mse',
                      optimizer=Adam(lr=self.learning_rate)) #Erstellung
        return model
 
    def remember(self, state, action, reward, next_state, done):#Erinnerungsmöglichkeit
        # merkt sich alle bisher durchlaufenen Zustände
        self.memory.append((state, action, reward, next_state, done))
 
    def act(self, state):
        # epsilon-greedy: off-policy oder policy
 
        if np.random.rand() <= self.epsilon:#Zufällige Aktion
            return random.randrange(self.action_size)
        act_values = self.model.predict(state)#Vorhersage des NN
        return np.argmax(act_values[0])  # returns action
 
    def replay(self, batch_size):
        # baut den Vektor der Q-Werte aus 
        # als reward zum Zeitpunkt t + gamma*max(moegliche rewards zum Zeitpunkt t+1)
        #prüft ob ein Zug gut war?
        minibatch = random.sample(self.memory, batch_size)
        states, targets_f = [], []
        for state, action, reward, next_state, done in minibatch:
            target = reward #Reward-Anpassung
            if not done:
                target = (reward + self.gamma *
                          np.amax(self.model.predict(next_state)[0]))
            target_f = self.model.predict(state)
            target_f[0][action] = target 
            # Filtering out states and targets for training
            states.append(state[0])
            targets_f.append(target_f[0])
        history = self.model.fit(np.array(states), np.array(targets_f), epochs=1, verbose=0)
        # Keeping track of loss
        loss = history.history['loss'][0]
        if self.epsilon > self.epsilon_min:
            self.epsilon *= self.epsilon_decay
        return loss
 
    #laden und speichern des NN
    def load(self, name):
        self.model.load_weights(name)
 
    def save(self, name):
        self.model.save_weights(name)
 
 
 
# Lernen: 
 
#  EPISODES mal durchspielen, bis der Mast umfaellt
 
 
 
 
EPISODES = 10
 
 
env = gym.make('CartPole-v1')
#4gewinnt einfuegen
 
 
#state_size = env.observation_space.shape[0]
state_size = 7 #Für die 7 Möglichkeiten die es gibt einen Stein zu platzieren
#Spielfeld?
 
 
action_size = env.action_space.n
#Wird 7 sein, solange keine Spalte voll ist
 
 
agent = Agent(state_size, action_size)
done = False
batch_size = 32#Muss eventuell auch angepasst werden
 
for e in range(EPISODES):
    state = env.reset()
    #eigene Reset Funktion
 
    state = np.reshape(state, [1, state_size])#Erzeugt einen Array, der den Zustand repräsentiert
    cum_reward = 0
    for time in range(500):#Zeit braucht man nicht bei 4 gewinnt, ersetzen mit max Spiellänge
        #env.render()
        action = agent.act(state)#Auswahl der möglichen Aktionen
        next_state, reward, done, _ = env.step(action)#Ausführung dieser Aktion
        reward = reward/(abs(next_state[0])+1.)**2 if not done else -10 #Anpssung des rewards-System
        cum_reward += reward
        next_state = np.reshape(next_state, [1, state_size])#nächsten Zustand herbei führen
        agent.remember(state, action, reward, next_state, done)#merken
        state = next_state
        if done:
            print(("episode: {}/{}, score: {}, e: {:.2}"#Score sollte nicht abhängig von Anzahl Züge, sondern von gewonenen/verloren sein
                  .format(e, EPISODES, time, agent.epsilon)))
            break
        if len(agent.memory) > batch_size:
            loss = agent.replay(batch_size)
            # Logging training loss and actual reward every 10 timesteps
            if time % 10 == 0:
                print(("episode: {}/{}, time: {}, cumulative reward: {:.4f}, loss: {:.4f}".format(e, EPISODES, time, cum_reward, loss))) 
 
agent.save("qlearning_cartpole.weights")
 
 
# Testen des gelernten Modells mit leichten Störungen, um die Stabilität zu sehen. Mit Visualisierung
#Funktioniert hier nicht so richtig
 
#2 Ai's gegeneinander spielen lassen?
 
agent.load("qlearning_cartpole.weights")#gemerkte Entscheidungen laden, um damit gute Züge machen zu können
 
import time  as ti #Zeit braucht man nicht
for e in range(1000):#Von hier
    state = env.reset()
    state[0] = state[0] + np.random.randn()*0.1
    state[1] = state[1] + np.random.randn()*0.1
    state[2] = state[2] + np.random.randn()*0.1
    state[3] = state[3] + np.random.randn()*0.1
    env.env.state = state
    state = np.reshape(state, [1, state_size])
    for time in range(2000):#bis hier muss komplett ersetzt werden
 
        env.render()#Nicht Zeit abhängig, braucht man also nicht
        agent.epsilon = 0# Setzt Zufallshandlung auf 0
        action = agent.act(state)
        next_state, reward, done, _ = env.step(action)
        next_state = np.reshape(next_state, [1, state_size])
        state = next_state#Spielt einen Zug durch
        if done:
            print("Duration: ", time)
            break
 
    else:
        print("Volle Zeit")#Hier wichtig ob Gewonnen/Verloren/Unentschieden?

Vorheriger Termin: 19.12.2019
Nächster Termin: 23.01.2020

some/09.01.2020.txt · Zuletzt geändert: 2020/03/27 16:51 von benbaute