From d5b86b057ef87b61ef16b786034b1a86bb6bd194 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Mon, 10 Jun 2024 08:37:21 +0200 Subject: [PATCH] Added human player --- a_player.py | 10 ++++++++ human_player.py | 59 +++++++++++++++++++++++++++++++++++++++++++++++ machine_player.py | 18 ++------------- tic_tac_toe.py | 19 ++++++--------- 4 files changed, 78 insertions(+), 28 deletions(-) create mode 100644 human_player.py diff --git a/a_player.py b/a_player.py index e6ddc11..9532fbb 100644 --- a/a_player.py +++ b/a_player.py @@ -14,9 +14,19 @@ class APlayer(object): def set_debug(self, with_debug): pass + @staticmethod + 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] + return np.array(indices) + def move(self, state: np.array): return state, False + def state_from_move(self, state: np.array, field): + state.reshape(state.size)[field] = self.mark + return state + def reward(self, value): pass diff --git a/human_player.py b/human_player.py new file mode 100644 index 0000000..3a9e542 --- /dev/null +++ b/human_player.py @@ -0,0 +1,59 @@ +import numpy as np + +from a_player import APlayer +from helper import to_state_string, create_empty_state, create_test_state + + +class HumanPlayer(APlayer): + def __init__(self, mark, name: str): + APlayer.__init__(self, mark) + self.name = name + + def move(self, state: np.array): + move = 0 + has_moved = False + while True: + 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?") + choice = input("Feldnummer: ") + + if choice in "Qq": + print("Abbruch") + break + + if not choice in "123456789" or len(choice) != 1: + print("Ungültiges Feld!") + print("Versuche es nochmal") + continue + + move = int(choice) - 1 + if not move in self.get_potential_moves(state): + print("Feld is bereits belegt!") + print("Versuche es nochmal") + continue + + print("So soll es geschehen") + has_moved = True + break + + state_next = self.state_from_move(state.copy(), move) + return state_next, has_moved + + def reward(self, value): + if value > 0: + print(f"{self.name}, Du hast gewonnen, super!") + else: + print(f"{self.name}, Du hast leider verloren!") + + +if __name__ == '__main__': + p = HumanPlayer("X", "Jens") + state = create_empty_state() + while True: + state, has_moved = p.move(state) + if not has_moved: + break + + p.reward(1.0) diff --git a/machine_player.py b/machine_player.py index 4854846..340dee3 100644 --- a/machine_player.py +++ b/machine_player.py @@ -10,21 +10,16 @@ class MachinePlayer(APlayer): self.p_exp = p_exp self.alpha = alpha - def __init__(self, mark, params: Params): + def __init__(self, mark, params: Params, values): APlayer.__init__(self, mark) self.params = params self.values = {} self.with_debug = False + self.values = values def set_debug(self, with_debug): self.with_debug = with_debug - def assign_values(self, values): - self.values = values - - def init_values(self): - self.values = {} - def print_state_table(self): count = 0 for key in self.values: @@ -53,12 +48,6 @@ class MachinePlayer(APlayer): def reward(self, value): self.set_value(self.state, value) - @staticmethod - 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] - return np.array(indices) - def new_game(self): self.state = None self.state_last = None @@ -116,6 +105,3 @@ class MachinePlayer(APlayer): return self.state, True - def state_from_move(self, state: np.array, field): - state.reshape(state.size)[field] = self.mark - return state diff --git a/tic_tac_toe.py b/tic_tac_toe.py index 20d1e9b..6630814 100644 --- a/tic_tac_toe.py +++ b/tic_tac_toe.py @@ -1,6 +1,7 @@ import numpy as np from helper import create_empty_state, to_state_string from machine_player import MachinePlayer +from human_player import HumanPlayer from player_provider import PlayerProvider import json @@ -42,17 +43,13 @@ def play(player_provider: PlayerProvider, k_max=10000, with_debug=False): if not has_moved: if with_debug: print(f"{player.mark}: No more moves") - if isinstance(player, MachinePlayer): player.reward(0.0) - if isinstance(other_player, MachinePlayer): other_player.reward(0.0) run = False if player.has_won(state): if with_debug: print(f"{player.mark}: Has won the game") - if isinstance(player, MachinePlayer): player.reward(1.0) - if isinstance(other_player, MachinePlayer): other_player.reward(0.0) run = False @@ -69,23 +66,21 @@ 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)) -po = MachinePlayer(mark='O', params=MachinePlayer.Params(p_exp=0.2, alpha=0.1)) - -px.assign_values(x_values) -po.assign_values(o_values) +#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 if do_training: - play(player_provider, 10000, False) + play(player_provider, 10000, True) play(player_provider, 10, True) # Convert and write JSON object to file with open("values_x.json", "w") as fp: - json.dump(px.values, fp, indent=0) + json.dump(x_values, fp, indent=0) with open("values_o.json", "w") as fp: - json.dump(po.values, fp, indent=0) + json.dump(o_values, fp, indent=0)