From 1845e424889e270c4e4ef8d120e98d1d784a5cd3 Mon Sep 17 00:00:00 2001 From: c0de Date: Mon, 24 Oct 2022 19:55:50 -0500 Subject: [PATCH] Use the `with` statement on the game class This is because the class is a context manager / state machine --- GhostBallBot/database/models.py | 2 +- GhostBallBot/discord_client/client.py | 4 +-- GhostBallBot/game.py | 40 +++++++++++++++++++-------- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/GhostBallBot/database/models.py b/GhostBallBot/database/models.py index 9121ea0..589c78c 100644 --- a/GhostBallBot/database/models.py +++ b/GhostBallBot/database/models.py @@ -7,7 +7,7 @@ import datetime from peewee import * -# User can provide path to database, or it will be put next to models.py +# User can provide path to database, or it will be put next to main.py DATABASE = os.environ.get('database_path', os.getcwd() + '/ghostball.db') database = SqliteDatabase(DATABASE) diff --git a/GhostBallBot/discord_client/client.py b/GhostBallBot/discord_client/client.py index dbbb22a..2118306 100644 --- a/GhostBallBot/discord_client/client.py +++ b/GhostBallBot/discord_client/client.py @@ -15,8 +15,8 @@ class GhostBallClient(discord.Client): def __init__(self, *args, **kwargs): super(GhostBallClient, self).__init__(*args, **kwargs) - self.game = game.Game() - self.game.discord = self + with game.Game() as self.game: + self.game.discord = self async def on_ready(self): print("Logged on as", self.user) diff --git a/GhostBallBot/game.py b/GhostBallBot/game.py index dcc7c70..afda48c 100644 --- a/GhostBallBot/game.py +++ b/GhostBallBot/game.py @@ -13,9 +13,15 @@ class Game: The game state class This represents a game that exists in a channel - """ + """ - def __init__(self): + def __enter__(self): + """ + Allows use of `with Game as game` for try/except statements + + We are using this instead of __init__, they work very similar + to each other (https://peps.python.org/pep-0343/) + """ # Only one game should run at at time self.is_running = False @@ -36,18 +42,32 @@ class Game: self.discord = None database.connect() + return self - def __exit__(self, exc_type, exc_val, exc_tb): + def __exit__(self, exception_type, exception_value, exception_traceback): """ Automagically close the database when this class has ended execution """ database.close() + async def check_is_running(method, start_new_game=True): + """ + Decorator that determines if the game is running or not + """ + async def wrapper(self): + + if self.is_running and start_new_game: + return await self.message.channel.send("A game is already running") + elif not self.is_running and not start_new_game: + return await self.message.channel.send("There is no game running to add guesses to") + + await method(self) + + return await wrapper + + @check_is_running async def start(self): - if self.is_running: - return await self.message.channel.send("A game is already running") - self.is_running = True # game.pitch_value is unknown at the start of the game @@ -68,10 +88,8 @@ class Game: return None, False, None, None + @check_is_running(start_new_game=False) async def stop(self): - if not self.is_running: - return await self.message.channel.send("There is no game running to resolve") - # Determine arguments pitch_value, has_batter, batter_id, batter_guess = self.__stopArgs__() if not pitch_value: @@ -97,10 +115,8 @@ class Game: self.is_running = False self.game = None + @check_is_running(start_new_game=False) async def guess(self): - if not self.is_running: - return await self.message.channel.send("There is no game running to add guesses to") - value = int(self.message.content.split()[1]) if value < 1 or value > 1000: return await self.message.channel.send(f"Invalid value. It must be between 1 and 1000 inclusive")