diff --git a/AI/ai_context.py b/AI/ai_context.py index 0f80366..6c15619 100644 --- a/AI/ai_context.py +++ b/AI/ai_context.py @@ -5,6 +5,9 @@ class AIContext(): """ + This is the context of the AI strategy pattern. + It holds the strategy and runs the strategy as a new thread. + It uses either the WeakAIStrategy or the AdvancedAIStrategy. Use: AIContext(strategy: ai_strategy.AIStrategy) -> Pass the strategy(WeakAIStrategy or StrongAIStrategy) to the AIContext, then call run_strategy() to run the strategy as a new thread. It will then connect to localhost and play the game using the strategy. diff --git a/AI/ai_strategy.py b/AI/ai_strategy.py index 085bac8..ee149ff 100644 --- a/AI/ai_strategy.py +++ b/AI/ai_strategy.py @@ -8,11 +8,14 @@ import logging import copy -logging.basicConfig(level=logging.DEBUG) -logger = logging.getLogger(__name__) - class AIStrategy(ABC, GameClient): + """ + This is the abstract strategy class for the AI. + It implements as many methods as possible and leaves the actual logic to the inheriting classes. + This avoids code duplication and makes it easier to add new strategies. + """ + def __init__(self): self._strength = "Placeholder" @@ -30,19 +33,26 @@ def post_init(self): super().__init__(self._ip, self._port, self._player) def thread_entry(self): + """ + Entry point for the AI thread. Run the AI in asyncio. + """ asyncio.run(self.run()) async def run(self): + """ + Start running the AI by joining a game and getting ready for the game. + """ - # The AI-UUID is hardcoded so that it can be excluded from statistics await self.join_game() asyncio.timeout(1) await self.lobby_ready() - logger.info("test") await self._listening_task async def join_game(self): + """ + Join a game. + """ await self.connect() self._listening_task = asyncio.create_task(self.listen()) @@ -52,6 +62,9 @@ async def join_game(self): async def _message_handler(self, message_type: str): + """ + Handle the incoming messages from the server. + """ match message_type: case "lobby/status": @@ -84,9 +97,15 @@ async def _message_handler(self, message_type: str): return async def wish_good_luck(self): + """ + Send a good luck message to the chat on game start. + """ await self.chat_message(self._good_luck_message) async def say_good_game(self): + """ + Send a good game message to the chat, depending on the outcome of the game. + """ if self._winner.uuid == self._current_uuid: await self.chat_message(self._good_game_message_won) elif self._winner.uuid == None: @@ -110,7 +129,13 @@ async def do_turn(self): pass class WeakAIStrategy(AIStrategy): - + """ + Weak AI Strategy: + The weak AI strategy is a simple AI that makes random moves. + It is one strategy in the strategy pattern for the AI. + """ + + def __init__(self, uuid: str = '108eaa05-2b0e-4e00-a190-8856edcd56a5'): super().__init__() self._current_uuid = uuid @@ -123,12 +148,23 @@ def __init__(self, uuid: str = '108eaa05-2b0e-4e00-a190-8856edcd56a5'): self.post_init() async def do_turn(self): + """ + Do one turn in the game. + Make the move on a random empty cell. + """ + empty_cells = self.get_empty_cells(self._playfield) move = random.randint(0, len(empty_cells) - 1) await self.game_make_move(empty_cells[move][0], empty_cells[move][1]) class AdvancedAIStrategy(AIStrategy): + """ + Advanced AI Strategy: + The advanced AI strategy is a more complex AI that tries to win the game. + It is one strategy in the strategy pattern for the AI. + """ + def __init__(self, uuid: str = 'd90397a5-a255-4101-9864-694b43ce8a6c'): super().__init__() self._current_uuid = uuid