diff options
author | 2020-03-01 21:35:58 +0000 | |
---|---|---|
committer | 2020-03-01 21:35:58 +0000 | |
commit | 3d7aaa55aeae430388f6a57c0636ef9c34aa2ab1 (patch) | |
tree | e3ac244deae4adda3d126e68f3eecc1140e7a9f9 | |
parent | Applied suggestions from code review for Battleships (diff) |
Applied suggestions from code review for Battleships
-rw-r--r-- | bot/seasons/evergreen/battleship.py | 78 |
1 files changed, 60 insertions, 18 deletions
diff --git a/bot/seasons/evergreen/battleship.py b/bot/seasons/evergreen/battleship.py index 9bca2bfc..bc076d7f 100644 --- a/bot/seasons/evergreen/battleship.py +++ b/bot/seasons/evergreen/battleship.py @@ -36,38 +36,39 @@ class Player: grid: Grid -SHIPS = { +SHIPS = { # The name of the ship and its size "Carrier": 5, "Battleship": 4, "Cruiser": 3, "Submarine": 3, "Destroyer": 2, -} # The name of the ship and its size +} # For these two variables, the first boolean is whether the square is a ship (True) or not (False). # The second boolean is whether the player has aimed for that square (True) or not (False) -SHIP_EMOJIS = { + +SHIP_EMOJIS = { # This is for the player's own board which shows the location of their own ships. (True, True): ":fire:", (True, False): ":ship:", (False, True): ":anger:", (False, False): ":ocean:", -} # This is for the player's own board which shows the location of their own ships. +} -HIDDEN_EMOJIS = { +HIDDEN_EMOJIS = { # This is for the opposing player's board which only shows aimed locations. (True, True): ":red_circle:", (True, False): ":black_circle:", (False, True): ":white_circle:", (False, False): ":black_circle:", -} # This is for the opposing player's board which only shows aimed locations. +} -LETTERS = ( +LETTERS = ( # For the top row of the board ":stop_button::regional_indicator_a::regional_indicator_b::regional_indicator_c::regional_indicator_d:" ":regional_indicator_e::regional_indicator_f::regional_indicator_g::regional_indicator_h:" ":regional_indicator_i::regional_indicator_j:" -) # For the top row of the board +) -NUMBERS = [ +NUMBERS = [ # For the first column of the board ":one:", ":two:", ":three:", @@ -78,7 +79,7 @@ NUMBERS = [ ":eight:", ":nine:", ":keycap_ten:", -] # For the first column of the board +] CROSS_EMOJI = "\u274e" HAND_RAISED_EMOJI = "\U0001f64b" @@ -107,6 +108,7 @@ class Game: self.next: typing.Optional[discord.Member] = None self.match: typing.Optional[typing.Match] = None + self.surrender: bool = False self.setup_grids() @@ -166,7 +168,7 @@ class Game: for player in (self.p1, self.p2): for name, size in SHIPS.items(): while True: # Repeats if about to overwrite another boat - overwrite = False + ship_collision = False coords = [] coord1 = random.randint(0, 9) @@ -183,9 +185,10 @@ class Game: new_x = x + (xincr * i) new_y = y + (yincr * i) if player.grid[new_x][new_y].boat: # Check if there's already a boat - overwrite = True + ship_collision = True + break coords.append((new_x, new_y)) - if not overwrite: # If not overwriting any other boat spaces, break loop + if not ship_collision: # If not overwriting any other boat spaces, break loop break for x, y in coords: @@ -216,6 +219,9 @@ class Game: def predicate(self, message: discord.Message) -> bool: """Predicate checking the message typed for each turn.""" if message.author == self.turn.user and message.channel == self.turn.user.dm_channel: + if message.content.lower() == "surrender": + self.surrender = True + return True self.match = re.match("([A-J]|[a-j]) ?((10)|[1-9])", message.content.strip()) if not self.match: self.bot.loop.create_task(message.add_reaction(CROSS_EMOJI)) @@ -225,7 +231,8 @@ class Game: """Lets the player who's turn it is choose a square.""" square = None turn_message = await self.turn.user.send( - "It's your turn! Type the square you want to fire at. Format it like this: A1" + "It's your turn! Type the square you want to fire at. Format it like this: A1\n" + "Type `surrender` to give up" ) await self.next.user.send("Their turn", delete_after=3.0) while True: @@ -234,9 +241,19 @@ class Game: except asyncio.TimeoutError: await self.turn.user.send("You took too long. Game over!") await self.next.user.send(f"{self.turn.user} took too long. Game over!") + await self.public_channel.send( + f"Game over! {self.turn.user.mention} timed out so {self.next.user.mention} wins!" + ) self.gameover = True break else: + if self.surrender: + await self.next.user.send(f"{self.turn.user} surrendered. Game over!") + await self.public_channel.send( + f"Game over! {self.turn.user.mention} surrendered to {self.next.user.mention}!" + ) + self.gameover = True + break square = self.get_square(self.next.grid, self.match.string) if square.aimed: await self.turn.user.send("You've already aimed at this square!", delete_after=3.0) @@ -275,6 +292,8 @@ class Game: return square = await self.take_turn() + if not square: + return square.aimed = True for message in alert_messages: @@ -308,7 +327,7 @@ class Battleship(commands.Cog): announcement: discord.Message, reaction: discord.Reaction, user: discord.Member - ) -> typing.Optional[bool]: + ) -> bool: """Predicate checking the criteria for the announcement message.""" if self.already_playing(ctx.author): # If they've joined a game since requesting a player 2 return True # Is dealt with later on @@ -319,7 +338,23 @@ class Battleship(commands.Cog): ): if self.already_playing(user): self.bot.loop.create_task(ctx.send(f"{user.mention} You're already playing a game!")) + self.bot.loop.create_task(announcement.remove_reaction(reaction, user)) return False + + if user in self.waiting: + self.bot.loop.create_task(ctx.send( + f"{user.mention} Please cancel your game first before joining another one." + )) + self.bot.loop.create_task(announcement.remove_reaction(reaction, user)) + return False + + return True + + if ( + user.id == ctx.author.id + and str(reaction.emoji) == CROSS_EMOJI + and reaction.message.id == announcement.id + ): return True return False @@ -345,13 +380,15 @@ class Battleship(commands.Cog): announcement = await ctx.send( "**Battleship**: A new game is about to start!\n" - f"Press :raising_hand: to play against {ctx.author.mention}!" + f"Press {HAND_RAISED_EMOJI} to play against {ctx.author.mention}!\n" + f"(Cancel the game with {CROSS_EMOJI}.)" ) self.waiting.append(ctx.author) await announcement.add_reaction(HAND_RAISED_EMOJI) + await announcement.add_reaction(CROSS_EMOJI) try: - _reaction, user = await self.bot.wait_for( + reaction, user = await self.bot.wait_for( "reaction_add", check=partial(self.predicate, ctx, announcement), timeout=60.0 @@ -361,6 +398,11 @@ class Battleship(commands.Cog): await announcement.delete() return await ctx.send(f"{ctx.author.mention} Seems like there's no one here to play...") + if str(reaction.emoji) == CROSS_EMOJI: + self.waiting.remove(ctx.author) + await announcement.delete() + return await ctx.send(f"{ctx.author.mention} Game cancelled.") + await announcement.delete() self.waiting.remove(ctx.author) if self.already_playing(ctx.author): @@ -372,7 +414,7 @@ class Battleship(commands.Cog): self.games.remove(game) except discord.Forbidden: await ctx.send( - f"{ctx.author.mention} {user.mention}" + f"{ctx.author.mention} {user.mention} " "Game failed. This is likely due to you not having your DMs open. Check and try again." ) self.games.remove(game) |