From de52c5260dea11ae0d73ef1d68afb79a9c6f70f6 Mon Sep 17 00:00:00 2001 From: "luca@igor" Date: Mon, 31 Dec 2018 13:10:08 +0100 Subject: [PATCH 01/11] first --- easyAI/TwoTeamsGame.py | 106 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 easyAI/TwoTeamsGame.py diff --git a/easyAI/TwoTeamsGame.py b/easyAI/TwoTeamsGame.py new file mode 100644 index 0000000..99f1840 --- /dev/null +++ b/easyAI/TwoTeamsGame.py @@ -0,0 +1,106 @@ +from copy import deepcopy + + +class TwoTeamsGame: + + def play(self, nmoves=1000, verbose=True): + + history = [] + + if verbose: + self.show() + + for self.nmove in range(1, nmoves + 1): + + if self.is_over(): + break + + move = self.player.ask_move(self) + history.append((deepcopy(self), move)) + self.make_move(move) + + if verbose: + self.show() + + self.switch_player() + + history.append(deepcopy(self)) + + return history + + #@property + #def nopponent(self): + # return 2 if (self.nplayer == 1) else 1 + + + @property + def opponent_team(self): + return self.current_opponent_team() + + @property + def player(self): + return self.current_player() + + def current_player(self): + return self.player_selector.current_player() + + def current_opponent_team(self): + return self.player_selector.opponent_team() + + def switch_player(self): + self.player_selector.next_player() + + def copy(self): + return deepcopy(self) + + def get_move(self): + """ + Method for getting a move from the current player. If the player is an + AI_Player, then this method will invoke the AI algorithm to choose the + move. If the player is a Human_Player, then the interaction with the + human is via the text terminal. + """ + return self.player.ask_move(self) + + def play_move(self, move): + """ + Method for playing one move with the current player. After making the move, + the current player will change to the next player. + + Parameters + ----------- + + move: + The move to be played. ``move`` should match an entry in the ``.possibles_moves()`` list. + """ + result = self.make_move(move) + self.switch_player() + return result + +class OrderedPlayerSelector: + + def __init__(self, team1, team2): + self.teams = [team1, team2] + self.move_no = 0 + self.counters = [0, 0] + + + def current_player(self): + + team_id = self.move_no % 2 + team = self.teams[self.move_no % 2] + + character_id = self.counters[team_id] % len(team) + + return self.teams[team_id][character_id] + + def next_player(self): + team_id = self.move_no % 2 + self.counters[team_id] += 1 + self.move_no += 1 + + def current_team(self): + return self.teams[(self.move_no) % 2] + + def opponent_team(self): + return self.teams[(self.move_no + 1) % 2] \ No newline at end of file From b4427d4be972219497368599a9032823defad03a Mon Sep 17 00:00:00 2001 From: "luca@igor" Date: Mon, 31 Dec 2018 15:16:53 +0100 Subject: [PATCH 02/11] first --- easyAI/TwoTeamsGame.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/easyAI/TwoTeamsGame.py b/easyAI/TwoTeamsGame.py index 99f1840..6f2f8dd 100644 --- a/easyAI/TwoTeamsGame.py +++ b/easyAI/TwoTeamsGame.py @@ -47,6 +47,9 @@ def current_player(self): def current_opponent_team(self): return self.player_selector.opponent_team() + def current_team(self): + return self.player_selector.current_team() + def switch_player(self): self.player_selector.next_player() From c6025f40999c83acf4bba2736ba77c2a7bf279ee Mon Sep 17 00:00:00 2001 From: "luca@igor" Date: Mon, 31 Dec 2018 16:20:08 +0100 Subject: [PATCH 03/11] first --- easyAI/TwoTeamsGame.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/easyAI/TwoTeamsGame.py b/easyAI/TwoTeamsGame.py index 6f2f8dd..eab2089 100644 --- a/easyAI/TwoTeamsGame.py +++ b/easyAI/TwoTeamsGame.py @@ -87,23 +87,31 @@ def __init__(self, team1, team2): self.move_no = 0 self.counters = [0, 0] + def filter_team(self, team): + return team def current_player(self): - team_id = self.move_no % 2 - team = self.teams[self.move_no % 2] + team_id = self._current_team_id() + team = self.current_team() character_id = self.counters[team_id] % len(team) - return self.teams[team_id][character_id] + return team[character_id] + + def _current_team_id(self): + return self.move_no % 2 + + def _next_team_id(self): + return (self.move_no + 1) % 2 def next_player(self): - team_id = self.move_no % 2 + team_id = self._current_team_id() self.counters[team_id] += 1 self.move_no += 1 def current_team(self): - return self.teams[(self.move_no) % 2] + return self.filter_team(self.teams[self._current_team_id()]) def opponent_team(self): - return self.teams[(self.move_no + 1) % 2] \ No newline at end of file + return self.filter_team(self.teams[self._next_team_id()]) \ No newline at end of file From 3c6be44e2988c5514d1b147cdd34c03eea32150b Mon Sep 17 00:00:00 2001 From: "luca@igor" Date: Mon, 7 Jan 2019 13:31:18 +0100 Subject: [PATCH 04/11] Revert "first" This reverts commit c6025f4 --- easyAI/TwoTeamsGame.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/easyAI/TwoTeamsGame.py b/easyAI/TwoTeamsGame.py index eab2089..6f2f8dd 100644 --- a/easyAI/TwoTeamsGame.py +++ b/easyAI/TwoTeamsGame.py @@ -87,31 +87,23 @@ def __init__(self, team1, team2): self.move_no = 0 self.counters = [0, 0] - def filter_team(self, team): - return team def current_player(self): - team_id = self._current_team_id() - team = self.current_team() + team_id = self.move_no % 2 + team = self.teams[self.move_no % 2] character_id = self.counters[team_id] % len(team) - return team[character_id] - - def _current_team_id(self): - return self.move_no % 2 - - def _next_team_id(self): - return (self.move_no + 1) % 2 + return self.teams[team_id][character_id] def next_player(self): - team_id = self._current_team_id() + team_id = self.move_no % 2 self.counters[team_id] += 1 self.move_no += 1 def current_team(self): - return self.filter_team(self.teams[self._current_team_id()]) + return self.teams[(self.move_no) % 2] def opponent_team(self): - return self.filter_team(self.teams[self._next_team_id()]) \ No newline at end of file + return self.teams[(self.move_no + 1) % 2] \ No newline at end of file From 87dd91cfcdb88edee449ef85ff4ff23ae08f9eca Mon Sep 17 00:00:00 2001 From: "luca@igor" Date: Fri, 11 Jan 2019 22:11:39 +0100 Subject: [PATCH 05/11] Revert "first" This reverts commit c6025f4 --- easyAI/TwoTeamsGame.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/easyAI/TwoTeamsGame.py b/easyAI/TwoTeamsGame.py index 6f2f8dd..5f2bbe2 100644 --- a/easyAI/TwoTeamsGame.py +++ b/easyAI/TwoTeamsGame.py @@ -3,6 +3,9 @@ class TwoTeamsGame: + def __init__(self, team1, team2): + self.player_selector = OrderedPlayerSelector(team1, team2) + def play(self, nmoves=1000, verbose=True): history = [] @@ -40,6 +43,9 @@ def opponent_team(self): @property def player(self): return self.current_player() + @property + def nplayer(self): + return self.current_player().name def current_player(self): return self.player_selector.current_player() @@ -56,6 +62,15 @@ def switch_player(self): def copy(self): return deepcopy(self) + def make_move(self, move): + pass + + def show(self): + pass + + def is_over(self): + return False + def get_move(self): """ Method for getting a move from the current player. If the player is an @@ -81,6 +96,17 @@ def play_move(self, move): return result class OrderedPlayerSelector: + """ + Selects next player, the behaviour is: + + team1 - player1 + team2 - player 1 + + team 1 - player 2 + team 2 - player 2 + + etc + """ def __init__(self, team1, team2): self.teams = [team1, team2] From 2093e815104589b8c76309738b092e7b017ca401 Mon Sep 17 00:00:00 2001 From: "luca@igor" Date: Sun, 13 Jan 2019 11:15:26 +0100 Subject: [PATCH 06/11] Revert "first" This reverts commit c6025f4 --- easyAI/TwoTeamsGame.py | 59 ++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/easyAI/TwoTeamsGame.py b/easyAI/TwoTeamsGame.py index 5f2bbe2..41bb1ba 100644 --- a/easyAI/TwoTeamsGame.py +++ b/easyAI/TwoTeamsGame.py @@ -4,7 +4,26 @@ class TwoTeamsGame: def __init__(self, team1, team2): + """ + :param team1: array of easyAI-supported objects. See Player module + :param team2: + """ self.player_selector = OrderedPlayerSelector(team1, team2) + #self.move_output = '' + self.setup_game() + + def make_move(self, move): + raise NotImplementedError('Abstract method') + + def show(self): + raise NotImplementedError('Abstract method') + + def is_over(self): + raise NotImplementedError('Abstract method') + + def setup_game(self): + raise NotImplementedError('Abstract method') + def play(self, nmoves=1000, verbose=True): @@ -31,10 +50,6 @@ def play(self, nmoves=1000, verbose=True): return history - #@property - #def nopponent(self): - # return 2 if (self.nplayer == 1) else 1 - @property def opponent_team(self): @@ -43,6 +58,7 @@ def opponent_team(self): @property def player(self): return self.current_player() + @property def nplayer(self): return self.current_player().name @@ -62,15 +78,6 @@ def switch_player(self): def copy(self): return deepcopy(self) - def make_move(self, move): - pass - - def show(self): - pass - - def is_over(self): - return False - def get_move(self): """ Method for getting a move from the current player. If the player is an @@ -106,6 +113,8 @@ class OrderedPlayerSelector: team 2 - player 2 etc + + according to rules defined in filter_team """ def __init__(self, team1, team2): @@ -113,23 +122,35 @@ def __init__(self, team1, team2): self.move_no = 0 self.counters = [0, 0] + def filter_team(self, team): + return team def current_player(self): - team_id = self.move_no % 2 - team = self.teams[self.move_no % 2] + team_id = self._current_team_id() + team = self.current_team() character_id = self.counters[team_id] % len(team) - return self.teams[team_id][character_id] + return team[character_id] + + def _current_team_id(self): + return self.move_no % 2 + + def _next_team_id(self): + return (self.move_no + 1) % 2 def next_player(self): - team_id = self.move_no % 2 + """ + Moves pointer to next player + :return: + """ + team_id = self._current_team_id() self.counters[team_id] += 1 self.move_no += 1 def current_team(self): - return self.teams[(self.move_no) % 2] + return self.filter_team(self.teams[self._current_team_id()]) def opponent_team(self): - return self.teams[(self.move_no + 1) % 2] \ No newline at end of file + return self.filter_team(self.teams[self._next_team_id()]) \ No newline at end of file From c061c9161737f4844e03b12a6da0e1e37be3be2f Mon Sep 17 00:00:00 2001 From: "luca@igor" Date: Sun, 13 Jan 2019 11:41:29 +0100 Subject: [PATCH 07/11] first --- easyAI/TwoTeamsGame.py | 15 +++++---------- easyAI/two_teams_game_sandbox.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 easyAI/two_teams_game_sandbox.py diff --git a/easyAI/TwoTeamsGame.py b/easyAI/TwoTeamsGame.py index 41bb1ba..58fb4db 100644 --- a/easyAI/TwoTeamsGame.py +++ b/easyAI/TwoTeamsGame.py @@ -3,14 +3,12 @@ class TwoTeamsGame: - def __init__(self, team1, team2): + def __init__(self, team1, team2, player_selector): """ :param team1: array of easyAI-supported objects. See Player module :param team2: """ - self.player_selector = OrderedPlayerSelector(team1, team2) - #self.move_output = '' - self.setup_game() + self.player_selector = player_selector(team1, team2) def make_move(self, move): raise NotImplementedError('Abstract method') @@ -21,9 +19,6 @@ def show(self): def is_over(self): raise NotImplementedError('Abstract method') - def setup_game(self): - raise NotImplementedError('Abstract method') - def play(self, nmoves=1000, verbose=True): @@ -102,9 +97,9 @@ def play_move(self, move): self.switch_player() return result -class OrderedPlayerSelector: +class AbstractOrderedPlayerSelector: """ - Selects next player, the behaviour is: + Base class for player selectors. Selects next player in order, the behaviour is: team1 - player1 team2 - player 1 @@ -123,7 +118,7 @@ def __init__(self, team1, team2): self.counters = [0, 0] def filter_team(self, team): - return team + raise NotImplementedError('Abstract method') def current_player(self): diff --git a/easyAI/two_teams_game_sandbox.py b/easyAI/two_teams_game_sandbox.py new file mode 100644 index 0000000..9d3addb --- /dev/null +++ b/easyAI/two_teams_game_sandbox.py @@ -0,0 +1,32 @@ +from easyAI.TwoTeamsGame import TwoTeamsGame, AbstractOrderedPlayerSelector + +from easyAI import Human_Player + +class MyGame(TwoTeamsGame): + """ + a dummy class for making experiments. With this script it ends up at 4 moves, and nothing happens :-) + """ + + def make_move(self, move): + print(str(self.player.name) + ' makes ' + move) + + def is_over(self): + return False + + def show(self): + print('Possible moves: ' + str(self.possible_moves())) + + def setup_game(self): + pass + + def possible_moves(self): + return ['1'] + +class MyPlayerSelector(AbstractOrderedPlayerSelector): + def filter_team(self, team): + return team + + + +g = MyGame([Human_Player()], [Human_Player()], MyPlayerSelector) +g.play(nmoves=4) From 6fac564b75373e3db1c623147488d4b3406e0942 Mon Sep 17 00:00:00 2001 From: "luca@igor" Date: Sun, 13 Jan 2019 11:48:42 +0100 Subject: [PATCH 08/11] refactor --- easyAI/TwoTeamsGame.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/easyAI/TwoTeamsGame.py b/easyAI/TwoTeamsGame.py index 58fb4db..9e0b557 100644 --- a/easyAI/TwoTeamsGame.py +++ b/easyAI/TwoTeamsGame.py @@ -9,6 +9,14 @@ def __init__(self, team1, team2, player_selector): :param team2: """ self.player_selector = player_selector(team1, team2) + self.setup_game() + + def setup_game(self): + """ + put here your own initialization and so on + :return: + """ + raise NotImplementedError('Abstract method') def make_move(self, move): raise NotImplementedError('Abstract method') From 470961648d146ef94b375abdd4c71ea32dc6e09c Mon Sep 17 00:00:00 2001 From: "luca@igor" Date: Sun, 13 Jan 2019 12:00:20 +0100 Subject: [PATCH 09/11] code comments --- easyAI/TwoTeamsGame.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/easyAI/TwoTeamsGame.py b/easyAI/TwoTeamsGame.py index 9e0b557..3a12ecf 100644 --- a/easyAI/TwoTeamsGame.py +++ b/easyAI/TwoTeamsGame.py @@ -6,7 +6,8 @@ class TwoTeamsGame: def __init__(self, team1, team2, player_selector): """ :param team1: array of easyAI-supported objects. See Player module - :param team2: + :param team2: array of easyAI-supported objects. + :param player_selector constructor for objects of type AbstractOrderedPlayerSelector (see below) """ self.player_selector = player_selector(team1, team2) self.setup_game() @@ -126,6 +127,11 @@ def __init__(self, team1, team2): self.counters = [0, 0] def filter_team(self, team): + """ + Filters an array of players. Used for return active players. For example in a RPG game may be the still alive ones + :param team: + :return: + """ raise NotImplementedError('Abstract method') def current_player(self): From 417364d0b418d76e9d2ff4017d9765aeb942a05c Mon Sep 17 00:00:00 2001 From: "luca@igor" Date: Fri, 26 Jul 2019 14:19:32 +0200 Subject: [PATCH 10/11] code comments --- easyAI/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 easyAI/README.md diff --git a/easyAI/README.md b/easyAI/README.md new file mode 100644 index 0000000..20d47cd --- /dev/null +++ b/easyAI/README.md @@ -0,0 +1 @@ +An easy AI fork that adds teams of players support \ No newline at end of file From 173e1b626fcba5e4f412c48b76715dc490186dfe Mon Sep 17 00:00:00 2001 From: "luca@igor" Date: Fri, 26 Jul 2019 14:27:36 +0200 Subject: [PATCH 11/11] code comments --- easyAI/README.md => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename easyAI/README.md => README.md (100%) diff --git a/easyAI/README.md b/README.md similarity index 100% rename from easyAI/README.md rename to README.md