From e47959373b91d20319751170672d8d5768012d22 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Mon, 10 Jun 2024 21:07:38 +0200 Subject: [PATCH] Refactored --- helper.py | 38 -------------------------------------- human_player.py | 6 +++--- machine_player.py | 9 +++------ state.py | 38 ++++++++++++++++++++++++++++++++++++++ tic_tac_toe.py | 35 +++++++++++++++++++++-------------- 5 files changed, 65 insertions(+), 61 deletions(-) diff --git a/helper.py b/helper.py index e59f98e..f7010f9 100644 --- a/helper.py +++ b/helper.py @@ -2,14 +2,6 @@ import numpy as np from numpy.random import uniform -def create_test_state() -> np.array: - return np.array([['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9']]) - - -def create_empty_state() -> np.array: - return np.array([['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]) - - def softmax(values: np.array, eps=1.0E-6) -> np.array: result = (values + eps) / (sum(values + eps)) return result @@ -46,36 +38,6 @@ def test_sample(data): print(c) -def to_state_string(state, state_nex=None): - sp = ' ' - sp_arrow = ' => ' - sp_ = [sp, sp_arrow, sp] - - def col(str_in, state): - str_out = str_in - for c in range(0, 3): - char = state[r][c] - if char == '-': - char = ' ' - str_out += "|" + char - str_out += '|' - return str_out - - state_str = '' - for r in range(0, 3): - if state is not None: - state_str = col(state_str, state) - - if state_nex is not None: - state_str += sp_[r] - state_str = col(state_str, state_nex) - - if r != 2: - state_str += '\x0A' - - return state_str - - if __name__ == '__main__': print("Testing sample()") test_sample([0.7, 0.1, 0.1, 0.1]) diff --git a/human_player.py b/human_player.py index 2588d09..9adbe46 100644 --- a/human_player.py +++ b/human_player.py @@ -1,7 +1,7 @@ import numpy as np from a_player import APlayer -from helper import to_state_string, create_empty_state, create_test_state +from state import to_state_string, create_empty_state, create_test_state from state import get_potential_moves @@ -17,7 +17,7 @@ class HumanPlayer(APlayer): print(f"{self.name}, Du bist dran. Das Spielfeld sieht so aus:") print(to_state_string(state, create_test_state())) - print(f"{self.name}, in welches Feld willst Du Dein \"{self.mark}\" setzen?") + print(f"{self.name}, in welches Feld willst Du das \"{self.mark}\" setzen?") choice = input("Feldnummer: ") if choice in "Qq": @@ -35,7 +35,7 @@ class HumanPlayer(APlayer): print("Versuche es nochmal") continue - print("So soll es geschehen") + print(f"Okay, nächstes \"{self.mark}\" auf Feld {move+1}") has_moved = True break diff --git a/machine_player.py b/machine_player.py index df081e0..373f63a 100644 --- a/machine_player.py +++ b/machine_player.py @@ -6,8 +6,8 @@ from state import get_potential_moves class MachinePlayer(APlayer): class Params: - def __init__(self, p_exp, alpha): - self.p_exp = p_exp + def __init__(self, p_explore, alpha): + self.p_exp = p_explore self.alpha = alpha def __init__(self, mark, params: Params, values): @@ -53,7 +53,6 @@ class MachinePlayer(APlayer): self.state_last = None def move(self, state: np.array): - do_sample = False values = np.array([]) # get possible move moves = get_potential_moves(state) @@ -74,13 +73,11 @@ class MachinePlayer(APlayer): next_move = best_move is_exp = False + # Randomly perform exploratory move if uniform() < self.params.p_exp: index = np.random.randint(len(moves)) next_move = moves[index] is_exp = best_move != next_move - elif do_sample: - index = sample(values) - next_move = moves[index] if self.with_debug: print(f"{self.mark}: Values = {values}") diff --git a/state.py b/state.py index f90885a..ba93318 100644 --- a/state.py +++ b/state.py @@ -1,6 +1,44 @@ import numpy as np +def create_test_state() -> np.array: + return np.array([['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9']]) + + +def create_empty_state() -> np.array: + return np.array([['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]) + + +def to_state_string(state, state_nex=None): + sp = ' ' + sp_arrow = ' => ' + sp_ = [sp, sp_arrow, sp] + + def col(str_in, state): + str_out = str_in + for c in range(0, 3): + char = state[r][c] + if char == '-': + char = ' ' + str_out += "|" + char + str_out += '|' + return str_out + + state_str = '' + for r in range(0, 3): + if state is not None: + state_str = col(state_str, state) + + if state_nex is not None: + state_str += sp_[r] + state_str = col(state_str, state_nex) + + if r != 2: + state_str += '\x0A' + + return state_str + + def get_potential_moves(state: np.array) -> np.array: st = state.reshape(state.size) indices = [idx for idx, s in enumerate(st) if '-' in s] diff --git a/tic_tac_toe.py b/tic_tac_toe.py index 7dfcfb7..f58d9eb 100644 --- a/tic_tac_toe.py +++ b/tic_tac_toe.py @@ -1,5 +1,5 @@ import numpy as np -from helper import create_empty_state, to_state_string +from state import create_empty_state, to_state_string from machine_player import MachinePlayer from human_player import HumanPlayer from player_provider import PlayerProvider @@ -66,21 +66,28 @@ with open("values_x.json", "r") as fp: with open("values_o.json", "r") as fp: o_values = json.load(fp) -#px = MachinePlayer(mark='X', params=MachinePlayer.Params(p_exp=0.2, alpha=0.1), values=x_values) -px = HumanPlayer(mark='X', name="Jens") -po = MachinePlayer(mark='O', params=MachinePlayer.Params(p_exp=0.2, alpha=0.1), values=o_values) - -player_provider = PlayerProvider(px, po) - do_training = 1 +do_human_player = 1 + +p_hx = HumanPlayer(mark='X', name="Jens") +p_mx = MachinePlayer(mark='X', params=MachinePlayer.Params(p_explore=0.2, alpha=0.1), values=x_values) +p_mo = MachinePlayer(mark='O', params=MachinePlayer.Params(p_explore=0.2, alpha=0.1), values=o_values) + if do_training: - play(player_provider, 10000, True) + play(PlayerProvider(p_mx, p_mo), 10000, False) -play(player_provider, 10, True) + # Values after training + # Convert and write JSON object to file + with open("values_x.json", "w") as fp: + json.dump(p_mx.values, fp, indent=0) -# Convert and write JSON object to file -with open("values_x.json", "w") as fp: - json.dump(x_values, fp, indent=0) + with open("values_o.json", "w") as fp: + json.dump(p_mo.values, fp, indent=0) + +if do_human_player: + pp = PlayerProvider(p_hx, p_mo) +else: + pp = PlayerProvider(p_mx, p_mo) + +play(pp, 10, True) -with open("values_o.json", "w") as fp: - json.dump(o_values, fp, indent=0)