From fe7d6c6535ccfa756d255cd11e68157714992581 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Fri, 9 Aug 2019 17:23:31 +0200 Subject: added minesweeper cog --- bot/seasons/evergreen/minesweeper.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 bot/seasons/evergreen/minesweeper.py (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py new file mode 100644 index 00000000..e5276df5 --- /dev/null +++ b/bot/seasons/evergreen/minesweeper.py @@ -0,0 +1,13 @@ +from discord.ext import commands + + +class Minesweeper(commands.Cog): + """play a game of minesweeper""" + + def __init__(self, bot: commands.Bot) -> None: + self.bot = bot + + +def setup(bot: commands.Bot) -> None: + """Cog load.""" + bot.add_cog(Minesweeper(bot)) -- cgit v1.2.3 From f32fdda6bb95225ea536c07446a764e015145ca4 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Fri, 9 Aug 2019 17:36:56 +0200 Subject: added logic for when a user already have a game running --- bot/seasons/evergreen/minesweeper.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index e5276df5..3540df80 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -1,11 +1,30 @@ +import typing + +import discord from discord.ext import commands class Minesweeper(commands.Cog): - """play a game of minesweeper""" + """Play a game of minesweeper.""" def __init__(self, bot: commands.Bot) -> None: self.bot = bot + self.games: typing.Dict[discord.member, typing.Dict] = {} # Store the currently running games + + @commands.command(name="minesweeper") + async def minesweeper_command(self, ctx: commands.Context) -> None: + """Start a game of minesweeper.""" + if ctx.author in self.games.keys(): # Player is already playing + msg = await ctx.send(f"{ctx.author.mention} you already have a game running") + await msg.delete(delay=2) + await ctx.message.delete(delay=2) + return + + # Add game to list + + self.games[ctx.author] = { + + } def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From dc488fb963e680c9ba8cef8bbd4f0bd6f1c8ed32 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Fri, 9 Aug 2019 18:09:55 +0200 Subject: add generate_board (it might have a bug, will begone more apparent when adding formatting for discord.) --- bot/seasons/evergreen/minesweeper.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 3540df80..39428000 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -1,4 +1,5 @@ import typing +from random import random import discord from discord.ext import commands @@ -11,6 +12,29 @@ class Minesweeper(commands.Cog): self.bot = bot self.games: typing.Dict[discord.member, typing.Dict] = {} # Store the currently running games + @staticmethod + def is_bomb(cell: typing.Union[str, int]) -> int: + """Returns 1 if `cell` is a bomb if not 0""" + return 1 if cell == "bomb" else 0 + + def generate_board(self) -> typing.List[typing.List[typing.Union[str, int]]]: + """Generate a 2d array for the board.""" + board: typing.List[typing.List[typing.Union[str, int]]] = [ + ["bomb" if random() <= .2 else "number" for _ in range(10)] for _ in range(9)] + for y, row in enumerate(board): + for x, cell in enumerate(row): + if cell == "number": + # calculate bombs near it + to_check = [] + for xt in [x - 1, x, x + 1]: + for yt in [y - 1, y, y + 1]: + if xt != -1 and xt != 10 and yt != -1 and yt != 9: + to_check.append(board[yt][xt]) + + bombs = sum(map(self.is_bomb, to_check)) + board[y][x] = bombs + return board + @commands.command(name="minesweeper") async def minesweeper_command(self, ctx: commands.Context) -> None: """Start a game of minesweeper.""" @@ -21,7 +45,7 @@ class Minesweeper(commands.Cog): return # Add game to list - + await ctx.send(str(self.generate_board())) self.games[ctx.author] = { } -- cgit v1.2.3 From 51a3b6ddb044548519fcf4bb53c236ef3172ecc9 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Fri, 9 Aug 2019 19:00:10 +0200 Subject: added formating for discord (there was no bug) --- bot/seasons/evergreen/minesweeper.py | 38 ++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 39428000..64499111 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -20,7 +20,7 @@ class Minesweeper(commands.Cog): def generate_board(self) -> typing.List[typing.List[typing.Union[str, int]]]: """Generate a 2d array for the board.""" board: typing.List[typing.List[typing.Union[str, int]]] = [ - ["bomb" if random() <= .2 else "number" for _ in range(10)] for _ in range(9)] + ["bomb" if random() <= .2 else "number" for _ in range(10)] for _ in range(10)] for y, row in enumerate(board): for x, cell in enumerate(row): if cell == "number": @@ -28,13 +28,42 @@ class Minesweeper(commands.Cog): to_check = [] for xt in [x - 1, x, x + 1]: for yt in [y - 1, y, y + 1]: - if xt != -1 and xt != 10 and yt != -1 and yt != 9: + if xt != -1 and xt != 10 and yt != -1 and yt != 10: to_check.append(board[yt][xt]) bombs = sum(map(self.is_bomb, to_check)) board[y][x] = bombs return board + @staticmethod + def format_for_discord(board: typing.List[typing.List[typing.Union[str, int]]]): + """Format the board to a string for discord.""" + mapping = { + 0: ":stop_button:", + 1: ":one:", + 2: ":two:", + 3: ":three:", + 4: ":four:", + 5: ":five:", + 6: ":six:", + 7: ":seven:", + 8: ":eight:", + 9: ":nine:", + 10: ":keycap_ten:", + "bomb": ":bomb:" + } + + discord_msg = ":stop_button: :one::two::three::four::five::six::seven::eight::nine::keycap_ten:\n\n" + rows: typing.List[str] = [] + for row_number, row in enumerate(board): + new_row = mapping[row_number + 1] + " " + for cell in row: + new_row += mapping[cell] + rows.append(new_row) + + discord_msg += "\n".join(rows) + return discord_msg + @commands.command(name="minesweeper") async def minesweeper_command(self, ctx: commands.Context) -> None: """Start a game of minesweeper.""" @@ -45,9 +74,10 @@ class Minesweeper(commands.Cog): return # Add game to list - await ctx.send(str(self.generate_board())) + board = self.generate_board() + await ctx.send(self.format_for_discord(board)) self.games[ctx.author] = { - + "board": board } -- cgit v1.2.3 From 794a08ace5618c5d756e9caf105e234e1e64ca0e Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Fri, 9 Aug 2019 21:41:12 +0200 Subject: added extra stuff to `format_for_discord` and also added dm and channel message --- bot/seasons/evergreen/minesweeper.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 64499111..543eab39 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -36,7 +36,7 @@ class Minesweeper(commands.Cog): return board @staticmethod - def format_for_discord(board: typing.List[typing.List[typing.Union[str, int]]]): + def format_for_discord(board: typing.List[typing.List[typing.Union[str, int]]]) -> str: """Format the board to a string for discord.""" mapping = { 0: ":stop_button:", @@ -50,7 +50,9 @@ class Minesweeper(commands.Cog): 8: ":eight:", 9: ":nine:", 10: ":keycap_ten:", - "bomb": ":bomb:" + "bomb": ":bomb:", + "hidden": ":grey_question:", + "flag": ":triangular_flag_on_post:" } discord_msg = ":stop_button: :one::two::three::four::five::six::seven::eight::nine::keycap_ten:\n\n" @@ -75,9 +77,19 @@ class Minesweeper(commands.Cog): # Add game to list board = self.generate_board() - await ctx.send(self.format_for_discord(board)) + reveled_board = [["hidden" for _ in range(10)]for _ in range(10)] + + await ctx.send(f"{ctx.author.mention} is playing minesweeper") + chat_msg = await ctx.send(self.format_for_discord(reveled_board)) + + await ctx.author.send("play by typing: `.reveal x y` and `.flag x y`") + dm_msg = await ctx.author.send(self.format_for_discord(reveled_board)) + self.games[ctx.author] = { - "board": board + "board": board, + "reveled": reveled_board, + "dm_msg": dm_msg, + "chat_msg": chat_msg } -- cgit v1.2.3 From 4495cc3bf19fe67f5ae52d632324f3631a35d0b1 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Fri, 9 Aug 2019 23:49:45 +0200 Subject: changed format_for_discord, as suggested by Ava, to now have letters at the top instead of numbers --- bot/seasons/evergreen/minesweeper.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 543eab39..85339865 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -55,7 +55,9 @@ class Minesweeper(commands.Cog): "flag": ":triangular_flag_on_post:" } - discord_msg = ":stop_button: :one::two::three::four::five::six::seven::eight::nine::keycap_ten:\n\n" + discord_msg = ":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:\n\n" rows: typing.List[str] = [] for row_number, row in enumerate(board): new_row = mapping[row_number + 1] + " " @@ -77,12 +79,12 @@ class Minesweeper(commands.Cog): # Add game to list board = self.generate_board() - reveled_board = [["hidden" for _ in range(10)]for _ in range(10)] + reveled_board = [["hidden" for _ in range(10)] for _ in range(10)] await ctx.send(f"{ctx.author.mention} is playing minesweeper") chat_msg = await ctx.send(self.format_for_discord(reveled_board)) - await ctx.author.send("play by typing: `.reveal x y` and `.flag x y`") + await ctx.author.send("play by typing: `.reveal x y` or `.flag x y` \nclose the game with `.end`") dm_msg = await ctx.author.send(self.format_for_discord(reveled_board)) self.games[ctx.author] = { -- cgit v1.2.3 From b3e377cf105b1b1e9572c25aa186aa4d5caf57fe Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 00:31:31 +0200 Subject: added `.flag` command and a board reload function --- bot/seasons/evergreen/minesweeper.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 85339865..b05fc255 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -94,6 +94,32 @@ class Minesweeper(commands.Cog): "chat_msg": chat_msg } + @staticmethod + def get_cords(value1: str, value2: str) -> typing.Tuple[int, int]: + """Take in 2 values for the cords and turn them into numbers""" + if value1.isnumeric(): + return int(value1) - 1, ord(value2.lower()) - 97 + else: + return ord(value1.lower()) - 97, int(value2) - 1 + + async def reload_board(self, ctx: commands.Context) -> None: + """Update both playing boards.""" + game = self.games[ctx.author] + await game["dm_msg"].delete() + game["dm_msg"] = await ctx.author.send(self.format_for_discord(game["reveled"])) + await game["chat_msg"].edit(content=self.format_for_discord(game["reveled"])) + + @commands.dm_only() + @commands.command(name="flag") + async def flag_command(self, ctx: commands.Context, value1, value2) -> None: + """Place a flag on the board""" + x, y = self.get_cords(value1, value2) # ints + board = self.games[ctx.author]["reveled"] + if board[y][x] == "hidden": + board[y][x] = "flag" + + await self.reload_board(ctx) + def setup(bot: commands.Bot) -> None: """Cog load.""" -- cgit v1.2.3 From c65f2af7cdc4341e403c12bb639e43c3db18804a Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 01:46:18 +0200 Subject: added .reveal and won and lost commands --- bot/seasons/evergreen/minesweeper.py | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index b05fc255..39e84940 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -120,6 +120,59 @@ class Minesweeper(commands.Cog): await self.reload_board(ctx) + async def lost(self, ctx: commands.Context) -> None: + """The player lost the game""" + game = self.games[ctx.author] + game["reveled"] = game["board"] + await self.reload_board(ctx) + await ctx.author.send(":fire: You lost :fire: ") + await game["chat_msg"].channel.send(f":fire: {ctx.author.mention} just lost minesweeper :fire:") + del self.games[ctx.author] + print(self.games) + + async def won(self, ctx: commands.Context): + """The player won the game""" + game = self.games[ctx.author] + game["reveled"] = game["board"] + await self.reload_board(ctx) + await ctx.author.send(":tada: You won! :tada: ") + await game["chat_msg"].channel.send(f":tada: {ctx.author.mention} just won minesweeper :tada:") + del self.games[ctx.author] + print(self.games) + + def reveal(self, reveled: typing.List, board: typing.List, x: int, y: int) -> None: + """Used when a 0 is encountered to do a flood fill""" + for x_ in [x - 1, x, x + 1]: + for y_ in [y - 1, y, y + 1]: + if x_ == -1 or x_ == 10 or y_ == -1 or y_ == 10 or reveled[y_][x_] != "hidden": + continue + reveled[y_][x_] = board[y_][x_] + if board[y_][x_] == 0: + self.reveal(reveled, board, x_, y_) + + @commands.dm_only() + @commands.command(name="reveal") + async def reveal_command(self, ctx: commands.Context, value1, value2): + """Reveal a cell""" + x, y = self.get_cords(value1, value2) + game = self.games[ctx.author] + reveled = game["reveled"] + board = game["board"] + reveled[y][x] = board[y][x] + if board[y][x] == "bomb": + await self.lost(ctx) + elif board[y][x] == 0: + self.reveal(reveled, board, x, y) + + # check if won + for x_ in range(10): + for y_ in range(10): + if not (reveled[y_][x_] == "hidden" and board[y_][x_] == "bomb"): + await self.won(ctx) + break + + await self.reload_board(ctx) + def setup(bot: commands.Bot) -> None: """Cog load.""" -- cgit v1.2.3 From 01d132dcd5cb2612ff1c7ccd586b959c9d51c312 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 01:58:01 +0200 Subject: added `.end` command --- bot/seasons/evergreen/minesweeper.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 39e84940..e67a043b 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -128,7 +128,6 @@ class Minesweeper(commands.Cog): await ctx.author.send(":fire: You lost :fire: ") await game["chat_msg"].channel.send(f":fire: {ctx.author.mention} just lost minesweeper :fire:") del self.games[ctx.author] - print(self.games) async def won(self, ctx: commands.Context): """The player won the game""" @@ -138,7 +137,6 @@ class Minesweeper(commands.Cog): await ctx.author.send(":tada: You won! :tada: ") await game["chat_msg"].channel.send(f":tada: {ctx.author.mention} just won minesweeper :tada:") del self.games[ctx.author] - print(self.games) def reveal(self, reveled: typing.List, board: typing.List, x: int, y: int) -> None: """Used when a 0 is encountered to do a flood fill""" @@ -173,6 +171,17 @@ class Minesweeper(commands.Cog): await self.reload_board(ctx) + @commands.dm_only() + @commands.command(name="end") + async def end_command(self, ctx: commands.Context): + """End the current game""" + game = self.games[ctx.author] + game["reveled"] = game["board"] + await self.reload_board(ctx) + await ctx.author.send(":no_entry: you canceled the game :no_entry:") + await game["chat_msg"].channel.send(f"{ctx.author.mention} just canceled minesweeper") + del self.games[ctx.author] + def setup(bot: commands.Bot) -> None: """Cog load.""" -- cgit v1.2.3 From 93370a5d55909224a2abb3463f5a1ee5657f02c1 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 02:17:21 +0200 Subject: fixed issue with winning detection --- bot/seasons/evergreen/minesweeper.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index e67a043b..241aa81d 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -163,11 +163,17 @@ class Minesweeper(commands.Cog): self.reveal(reveled, board, x, y) # check if won + break_ = False for x_ in range(10): for y_ in range(10): - if not (reveled[y_][x_] == "hidden" and board[y_][x_] == "bomb"): - await self.won(ctx) + if reveled[y_][x_] == "hidden" and board[y_][x_] != "bomb": + break_ = True break + else: + await self.won(ctx) + break + if break_: + break await self.reload_board(ctx) -- cgit v1.2.3 From df8a68fae9877c1f2943045093fa4a40f0fcb293 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 02:30:36 +0200 Subject: added that you can provide a custom chance for bombs --- bot/seasons/evergreen/minesweeper.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 241aa81d..3c3ee011 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -17,10 +17,10 @@ class Minesweeper(commands.Cog): """Returns 1 if `cell` is a bomb if not 0""" return 1 if cell == "bomb" else 0 - def generate_board(self) -> typing.List[typing.List[typing.Union[str, int]]]: + def generate_board(self, bomb_chance: float) -> typing.List[typing.List[typing.Union[str, int]]]: """Generate a 2d array for the board.""" board: typing.List[typing.List[typing.Union[str, int]]] = [ - ["bomb" if random() <= .2 else "number" for _ in range(10)] for _ in range(10)] + ["bomb" if random() <= bomb_chance else "number" for _ in range(10)] for _ in range(10)] for y, row in enumerate(board): for x, cell in enumerate(row): if cell == "number": @@ -69,7 +69,7 @@ class Minesweeper(commands.Cog): return discord_msg @commands.command(name="minesweeper") - async def minesweeper_command(self, ctx: commands.Context) -> None: + async def minesweeper_command(self, ctx: commands.Context, bomb_chance: float = .2) -> None: """Start a game of minesweeper.""" if ctx.author in self.games.keys(): # Player is already playing msg = await ctx.send(f"{ctx.author.mention} you already have a game running") @@ -78,7 +78,7 @@ class Minesweeper(commands.Cog): return # Add game to list - board = self.generate_board() + board = self.generate_board(bomb_chance) reveled_board = [["hidden" for _ in range(10)] for _ in range(10)] await ctx.send(f"{ctx.author.mention} is playing minesweeper") -- cgit v1.2.3 From 90e89ecc5be19464f83f0943d21320948dccce17 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 02:51:09 +0200 Subject: fixed winning code again --- bot/seasons/evergreen/minesweeper.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 3c3ee011..e48e3bba 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -86,6 +86,7 @@ class Minesweeper(commands.Cog): await ctx.author.send("play by typing: `.reveal x y` or `.flag x y` \nclose the game with `.end`") dm_msg = await ctx.author.send(self.format_for_discord(reveled_board)) + await ctx.author.send(self.format_for_discord(board)) self.games[ctx.author] = { "board": board, @@ -169,11 +170,10 @@ class Minesweeper(commands.Cog): if reveled[y_][x_] == "hidden" and board[y_][x_] != "bomb": break_ = True break - else: - await self.won(ctx) - break if break_: break + else: + await self.won(ctx) await self.reload_board(ctx) -- cgit v1.2.3 From e08b45cee1a70d15ce1248564254f456a2dac6bf Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 03:00:46 +0200 Subject: removed debugging message --- bot/seasons/evergreen/minesweeper.py | 1 - 1 file changed, 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index e48e3bba..07a19cde 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -86,7 +86,6 @@ class Minesweeper(commands.Cog): await ctx.author.send("play by typing: `.reveal x y` or `.flag x y` \nclose the game with `.end`") dm_msg = await ctx.author.send(self.format_for_discord(reveled_board)) - await ctx.author.send(self.format_for_discord(board)) self.games[ctx.author] = { "board": board, -- cgit v1.2.3 From 4d35dd6bd23a905bf0ef741f66fd6a5d46b07d84 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 10:24:19 +0200 Subject: fixed bug in get_cords --- bot/seasons/evergreen/minesweeper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 07a19cde..e742d7d5 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -98,7 +98,7 @@ class Minesweeper(commands.Cog): def get_cords(value1: str, value2: str) -> typing.Tuple[int, int]: """Take in 2 values for the cords and turn them into numbers""" if value1.isnumeric(): - return int(value1) - 1, ord(value2.lower()) - 97 + return ord(value2.lower()) - 97, int(value1) - 1 else: return ord(value1.lower()) - 97, int(value2) - 1 -- cgit v1.2.3 From 5120dc9610869df302ba83e572aec029d35b370f Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 14:07:28 +0200 Subject: changed .flag and .reveal to be abel to run multiple cords at once --- bot/seasons/evergreen/minesweeper.py | 41 ++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index e742d7d5..ac1b287b 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -84,7 +84,7 @@ class Minesweeper(commands.Cog): await ctx.send(f"{ctx.author.mention} is playing minesweeper") chat_msg = await ctx.send(self.format_for_discord(reveled_board)) - await ctx.author.send("play by typing: `.reveal x y` or `.flag x y` \nclose the game with `.end`") + await ctx.author.send("play by typing: `.reveal xy xy ...` or `.flag xy xy ...` \nclose the game with `.end`") dm_msg = await ctx.author.send(self.format_for_discord(reveled_board)) self.games[ctx.author] = { @@ -111,12 +111,13 @@ class Minesweeper(commands.Cog): @commands.dm_only() @commands.command(name="flag") - async def flag_command(self, ctx: commands.Context, value1, value2) -> None: - """Place a flag on the board""" - x, y = self.get_cords(value1, value2) # ints + async def flag_command(self, ctx: commands.Context, *cords) -> None: + """Place multiple flags on the board""" board = self.games[ctx.author]["reveled"] - if board[y][x] == "hidden": - board[y][x] = "flag" + for cord in cords: + x, y = self.get_cords(cord[0], cord[1]) + if board[y][x] == "hidden": + board[y][x] = "flag" await self.reload_board(ctx) @@ -138,7 +139,7 @@ class Minesweeper(commands.Cog): await game["chat_msg"].channel.send(f":tada: {ctx.author.mention} just won minesweeper :tada:") del self.games[ctx.author] - def reveal(self, reveled: typing.List, board: typing.List, x: int, y: int) -> None: + def reveal_zeros(self, reveled: typing.List, board: typing.List, x: int, y: int) -> None: """Used when a 0 is encountered to do a flood fill""" for x_ in [x - 1, x, x + 1]: for y_ in [y - 1, y, y + 1]: @@ -146,21 +147,15 @@ class Minesweeper(commands.Cog): continue reveled[y_][x_] = board[y_][x_] if board[y_][x_] == 0: - self.reveal(reveled, board, x_, y_) + self.reveal_zeros(reveled, board, x_, y_) - @commands.dm_only() - @commands.command(name="reveal") - async def reveal_command(self, ctx: commands.Context, value1, value2): - """Reveal a cell""" - x, y = self.get_cords(value1, value2) - game = self.games[ctx.author] - reveled = game["reveled"] - board = game["board"] + async def reveal_one(self, ctx: commands.Context, reveled: typing.List, board: typing.List, x: int, y: int) -> None: + """Reveal one square.""" reveled[y][x] = board[y][x] if board[y][x] == "bomb": await self.lost(ctx) elif board[y][x] == 0: - self.reveal(reveled, board, x, y) + self.reveal_zeros(reveled, board, x, y) # check if won break_ = False @@ -173,9 +168,19 @@ class Minesweeper(commands.Cog): break else: await self.won(ctx) - await self.reload_board(ctx) + @commands.dm_only() + @commands.command(name="reveal") + async def reveal_command(self, ctx: commands.Context, *cords): + """Reveal multiple cells""" + game = self.games[ctx.author] + reveled = game["reveled"] + board = game["board"] + for cord in cords: + x, y = self.get_cords(cord[0], cord[1]) + await self.reveal_one(ctx, reveled, board, x, y) + @commands.dm_only() @commands.command(name="end") async def end_command(self, ctx: commands.Context): -- cgit v1.2.3 From deda7968e2509d2ccdad35674d98144deaa88b86 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 14:34:22 +0200 Subject: fixed a small bug --- bot/seasons/evergreen/minesweeper.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index ac1b287b..b1d27735 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -84,7 +84,8 @@ class Minesweeper(commands.Cog): await ctx.send(f"{ctx.author.mention} is playing minesweeper") chat_msg = await ctx.send(self.format_for_discord(reveled_board)) - await ctx.author.send("play by typing: `.reveal xy xy ...` or `.flag xy xy ...` \nclose the game with `.end`") + await ctx.author.send("play by typing: `.reveal xy xy ...` or `.flag xy xy ...` \nclose the game with `.end`\n" + "cords must be in format `") dm_msg = await ctx.author.send(self.format_for_discord(reveled_board)) self.games[ctx.author] = { @@ -97,10 +98,7 @@ class Minesweeper(commands.Cog): @staticmethod def get_cords(value1: str, value2: str) -> typing.Tuple[int, int]: """Take in 2 values for the cords and turn them into numbers""" - if value1.isnumeric(): - return ord(value2.lower()) - 97, int(value1) - 1 - else: - return ord(value1.lower()) - 97, int(value2) - 1 + return ord(value1.lower()) - 97, int(value2) - 1 async def reload_board(self, ctx: commands.Context) -> None: """Update both playing boards.""" @@ -115,7 +113,7 @@ class Minesweeper(commands.Cog): """Place multiple flags on the board""" board = self.games[ctx.author]["reveled"] for cord in cords: - x, y = self.get_cords(cord[0], cord[1]) + x, y = self.get_cords(cord[0], cord[1:]) if board[y][x] == "hidden": board[y][x] = "flag" @@ -178,7 +176,7 @@ class Minesweeper(commands.Cog): reveled = game["reveled"] board = game["board"] for cord in cords: - x, y = self.get_cords(cord[0], cord[1]) + x, y = self.get_cords(cord[0], cord[1:]) await self.reveal_one(ctx, reveled, board, x, y) @commands.dm_only() -- cgit v1.2.3 From 1cb1ec544a918d585bc2160c5a822906d6c0c1d7 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 15:06:45 +0200 Subject: changed thing after requests. --- bot/seasons/evergreen/minesweeper.py | 127 ++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 63 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index b1d27735..9cd35faa 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -1,42 +1,41 @@ import typing from random import random -import discord from discord.ext import commands +GameBoard = typing.List[typing.List[typing.Union[str, int]]] +DictOfGames = typing.Dict[int, typing.Dict] + class Minesweeper(commands.Cog): """Play a game of minesweeper.""" def __init__(self, bot: commands.Bot) -> None: - self.bot = bot - self.games: typing.Dict[discord.member, typing.Dict] = {} # Store the currently running games + self.games: DictOfGames = {} # Store the currently running games @staticmethod def is_bomb(cell: typing.Union[str, int]) -> int: """Returns 1 if `cell` is a bomb if not 0""" - return 1 if cell == "bomb" else 0 + return cell == "bomb" - def generate_board(self, bomb_chance: float) -> typing.List[typing.List[typing.Union[str, int]]]: + def generate_board(self, bomb_chance: float) -> GameBoard: """Generate a 2d array for the board.""" - board: typing.List[typing.List[typing.Union[str, int]]] = [ - ["bomb" if random() <= bomb_chance else "number" for _ in range(10)] for _ in range(10)] + board: GameBoard = [["bomb" if random() <= bomb_chance else "number" for _ in range(10)] for _ in range(10)] for y, row in enumerate(board): for x, cell in enumerate(row): if cell == "number": # calculate bombs near it - to_check = [] - for xt in [x - 1, x, x + 1]: - for yt in [y - 1, y, y + 1]: - if xt != -1 and xt != 10 and yt != -1 and yt != 10: - to_check.append(board[yt][xt]) + bombs = 0 + for x_ in [x - 1, x, x + 1]: + for y_ in [y - 1, y, y + 1]: + if x_ != -1 and x_ != 10 and y_ != -1 and y_ != 10 and board[y_][x_] == "bomb": + bombs += 1 - bombs = sum(map(self.is_bomb, to_check)) board[y][x] = bombs return board @staticmethod - def format_for_discord(board: typing.List[typing.List[typing.Union[str, int]]]) -> str: + def format_for_discord(board: GameBoard) -> str: """Format the board to a string for discord.""" mapping = { 0: ":stop_button:", @@ -55,9 +54,11 @@ class Minesweeper(commands.Cog): "flag": ":triangular_flag_on_post:" } - discord_msg = ":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:\n\n" + discord_msg = ( + ":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:\n\n" + ) rows: typing.List[str] = [] for row_number, row in enumerate(board): new_row = mapping[row_number + 1] + " " @@ -71,26 +72,27 @@ class Minesweeper(commands.Cog): @commands.command(name="minesweeper") async def minesweeper_command(self, ctx: commands.Context, bomb_chance: float = .2) -> None: """Start a game of minesweeper.""" - if ctx.author in self.games.keys(): # Player is already playing + if ctx.author.id in self.games.keys(): # Player is already playing msg = await ctx.send(f"{ctx.author.mention} you already have a game running") await msg.delete(delay=2) await ctx.message.delete(delay=2) return # Add game to list - board = self.generate_board(bomb_chance) - reveled_board = [["hidden" for _ in range(10)] for _ in range(10)] + board: GameBoard = self.generate_board(bomb_chance) + revealed_board: GameBoard = [["hidden" for _ in range(10)] for _ in range(10)] await ctx.send(f"{ctx.author.mention} is playing minesweeper") - chat_msg = await ctx.send(self.format_for_discord(reveled_board)) + chat_msg = await ctx.send(self.format_for_discord(revealed_board)) - await ctx.author.send("play by typing: `.reveal xy xy ...` or `.flag xy xy ...` \nclose the game with `.end`\n" - "cords must be in format `") - dm_msg = await ctx.author.send(self.format_for_discord(reveled_board)) + await ctx.author.send("play by typing: `.reveal xy [xy]` or `.flag xy [xy]` \n" + "close the game with `.end`\n" + "cords must be in format ``") + dm_msg = await ctx.author.send(self.format_for_discord(revealed_board)) - self.games[ctx.author] = { + self.games[ctx.author.id] = { "board": board, - "reveled": reveled_board, + "revealed": revealed_board, "dm_msg": dm_msg, "chat_msg": chat_msg } @@ -102,16 +104,16 @@ class Minesweeper(commands.Cog): async def reload_board(self, ctx: commands.Context) -> None: """Update both playing boards.""" - game = self.games[ctx.author] + game = self.games[ctx.author.id] await game["dm_msg"].delete() - game["dm_msg"] = await ctx.author.send(self.format_for_discord(game["reveled"])) - await game["chat_msg"].edit(content=self.format_for_discord(game["reveled"])) + game["dm_msg"] = await ctx.author.send(self.format_for_discord(game["revealed"])) + await game["chat_msg"].edit(content=self.format_for_discord(game["revealed"])) @commands.dm_only() @commands.command(name="flag") async def flag_command(self, ctx: commands.Context, *cords) -> None: """Place multiple flags on the board""" - board = self.games[ctx.author]["reveled"] + board: GameBoard = self.games[ctx.author.id]["revealed"] for cord in cords: x, y = self.get_cords(cord[0], cord[1:]) if board[y][x] == "hidden": @@ -121,74 +123,73 @@ class Minesweeper(commands.Cog): async def lost(self, ctx: commands.Context) -> None: """The player lost the game""" - game = self.games[ctx.author] - game["reveled"] = game["board"] + game = self.games[ctx.author.id] + game["revealed"] = game["board"] await self.reload_board(ctx) await ctx.author.send(":fire: You lost :fire: ") await game["chat_msg"].channel.send(f":fire: {ctx.author.mention} just lost minesweeper :fire:") - del self.games[ctx.author] + del self.games[ctx.author.id] - async def won(self, ctx: commands.Context): + async def won(self, ctx: commands.Context) -> None: """The player won the game""" - game = self.games[ctx.author] - game["reveled"] = game["board"] + game = self.games[ctx.author.id] + game["revealed"] = game["board"] await self.reload_board(ctx) await ctx.author.send(":tada: You won! :tada: ") await game["chat_msg"].channel.send(f":tada: {ctx.author.mention} just won minesweeper :tada:") - del self.games[ctx.author] + del self.games[ctx.author.id] - def reveal_zeros(self, reveled: typing.List, board: typing.List, x: int, y: int) -> None: + def reveal_zeros(self, revealed: GameBoard, board: GameBoard, x: int, y: int) -> None: """Used when a 0 is encountered to do a flood fill""" for x_ in [x - 1, x, x + 1]: for y_ in [y - 1, y, y + 1]: - if x_ == -1 or x_ == 10 or y_ == -1 or y_ == 10 or reveled[y_][x_] != "hidden": + if x_ == -1 or x_ == 10 or y_ == -1 or y_ == 10 or revealed[y_][x_] != "hidden": continue - reveled[y_][x_] = board[y_][x_] + revealed[y_][x_] = board[y_][x_] if board[y_][x_] == 0: - self.reveal_zeros(reveled, board, x_, y_) + self.reveal_zeros(revealed, board, x_, y_) + + async def check_if_won(self, ctx, revealed: GameBoard, board: GameBoard) -> None: + """Checks if a player has won""" + for x_ in range(10): + for y_ in range(10): + if revealed[y_][x_] == "hidden" and board[y_][x_] != "bomb": + return + else: + await self.won(ctx) - async def reveal_one(self, ctx: commands.Context, reveled: typing.List, board: typing.List, x: int, y: int) -> None: + async def reveal_one(self, ctx: commands.Context, revealed: GameBoard, board: GameBoard, x: int, y: int) -> None: """Reveal one square.""" - reveled[y][x] = board[y][x] + revealed[y][x] = board[y][x] if board[y][x] == "bomb": await self.lost(ctx) elif board[y][x] == 0: - self.reveal_zeros(reveled, board, x, y) + self.reveal_zeros(revealed, board, x, y) + await self.check_if_won(ctx, revealed, board) - # check if won - break_ = False - for x_ in range(10): - for y_ in range(10): - if reveled[y_][x_] == "hidden" and board[y_][x_] != "bomb": - break_ = True - break - if break_: - break - else: - await self.won(ctx) await self.reload_board(ctx) @commands.dm_only() @commands.command(name="reveal") - async def reveal_command(self, ctx: commands.Context, *cords): + async def reveal_command(self, ctx: commands.Context, *cords) -> None: """Reveal multiple cells""" - game = self.games[ctx.author] - reveled = game["reveled"] - board = game["board"] + game = self.games[ctx.author.id] + revealed: GameBoard = game["revealed"] + board: GameBoard = game["board"] for cord in cords: x, y = self.get_cords(cord[0], cord[1:]) - await self.reveal_one(ctx, reveled, board, x, y) + await self.reveal_one(ctx, revealed, board, x, y) @commands.dm_only() @commands.command(name="end") async def end_command(self, ctx: commands.Context): """End the current game""" - game = self.games[ctx.author] - game["reveled"] = game["board"] + game = self.games[ctx.author.id] + game["revealed"] = game["board"] await self.reload_board(ctx) await ctx.author.send(":no_entry: you canceled the game :no_entry:") await game["chat_msg"].channel.send(f"{ctx.author.mention} just canceled minesweeper") - del self.games[ctx.author] + del self.games[ctx.author.id] def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From 940af8928a9e4aebb0e81f94c26899f23e83ac08 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Sat, 10 Aug 2019 19:53:05 +0200 Subject: fixed bugs and turned get_cords into a converter --- bot/seasons/evergreen/minesweeper.py | 53 +++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 19 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 9cd35faa..9e7fad12 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -7,6 +7,24 @@ GameBoard = typing.List[typing.List[typing.Union[str, int]]] DictOfGames = typing.Dict[int, typing.Dict] +class CordConverter(commands.Converter): + """Converter for cords.""" + + async def convert(self, ctx, cord: str) -> typing.Tuple[int, int]: + """Take in a cord string and turn it into x, y""" + if not 2 <= len(cord) <= 3: + raise commands.ArgumentParsingError() + value1 = cord[0] + value2 = cord[1:] + if not value2.isdigit(): + raise commands.ArgumentParsingError() + x = ord(value1) - 97 + y = int(value2) - 1 + if (not 0 <= x <= 9) or (not 0 <= y <= 9): + raise commands.ArgumentParsingError() + return x, y + + class Minesweeper(commands.Cog): """Play a game of minesweeper.""" @@ -97,11 +115,6 @@ class Minesweeper(commands.Cog): "chat_msg": chat_msg } - @staticmethod - def get_cords(value1: str, value2: str) -> typing.Tuple[int, int]: - """Take in 2 values for the cords and turn them into numbers""" - return ord(value1.lower()) - 97, int(value2) - 1 - async def reload_board(self, ctx: commands.Context) -> None: """Update both playing boards.""" game = self.games[ctx.author.id] @@ -111,11 +124,10 @@ class Minesweeper(commands.Cog): @commands.dm_only() @commands.command(name="flag") - async def flag_command(self, ctx: commands.Context, *cords) -> None: + async def flag_command(self, ctx: commands.Context, *cords: CordConverter) -> None: """Place multiple flags on the board""" board: GameBoard = self.games[ctx.author.id]["revealed"] - for cord in cords: - x, y = self.get_cords(cord[0], cord[1:]) + for x, y in cords: if board[y][x] == "hidden": board[y][x] = "flag" @@ -149,38 +161,41 @@ class Minesweeper(commands.Cog): if board[y_][x_] == 0: self.reveal_zeros(revealed, board, x_, y_) - async def check_if_won(self, ctx, revealed: GameBoard, board: GameBoard) -> None: + async def check_if_won(self, ctx, revealed: GameBoard, board: GameBoard) -> bool: """Checks if a player has won""" for x_ in range(10): for y_ in range(10): if revealed[y_][x_] == "hidden" and board[y_][x_] != "bomb": - return + return True else: await self.won(ctx) + return False - async def reveal_one(self, ctx: commands.Context, revealed: GameBoard, board: GameBoard, x: int, y: int) -> None: + async def reveal_one(self, ctx: commands.Context, revealed: GameBoard, board: GameBoard, x: int, y: int) -> bool: """Reveal one square.""" revealed[y][x] = board[y][x] if board[y][x] == "bomb": await self.lost(ctx) + return False elif board[y][x] == 0: self.reveal_zeros(revealed, board, x, y) - await self.check_if_won(ctx, revealed, board) - - await self.reload_board(ctx) + return await self.check_if_won(ctx, revealed, board) @commands.dm_only() @commands.command(name="reveal") - async def reveal_command(self, ctx: commands.Context, *cords) -> None: + async def reveal_command(self, ctx: commands.Context, *cords: CordConverter) -> None: """Reveal multiple cells""" game = self.games[ctx.author.id] revealed: GameBoard = game["revealed"] board: GameBoard = game["board"] - for cord in cords: - x, y = self.get_cords(cord[0], cord[1:]) - await self.reveal_one(ctx, revealed, board, x, y) - @commands.dm_only() + reload_board = True + for x, y in cords: + if not await self.reveal_one(ctx, revealed, board, x, y): + reload_board = False + if reload_board: + await self.reload_board(ctx) + @commands.command(name="end") async def end_command(self, ctx: commands.Context): """End the current game""" -- cgit v1.2.3 From 13c81c808728b58b532fa19e5d1bd9abb0986943 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Tue, 13 Aug 2019 02:09:52 +0200 Subject: Apply suggestions from code review Co-Authored-By: Mark --- bot/seasons/evergreen/minesweeper.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 9e7fad12..30c871ee 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -139,7 +139,7 @@ class Minesweeper(commands.Cog): game["revealed"] = game["board"] await self.reload_board(ctx) await ctx.author.send(":fire: You lost :fire: ") - await game["chat_msg"].channel.send(f":fire: {ctx.author.mention} just lost minesweeper :fire:") + await game["chat_msg"].channel.send(f":fire: {ctx.author.mention} just lost Minesweeper! :fire:") del self.games[ctx.author.id] async def won(self, ctx: commands.Context) -> None: @@ -147,8 +147,8 @@ class Minesweeper(commands.Cog): game = self.games[ctx.author.id] game["revealed"] = game["board"] await self.reload_board(ctx) - await ctx.author.send(":tada: You won! :tada: ") - await game["chat_msg"].channel.send(f":tada: {ctx.author.mention} just won minesweeper :tada:") + await ctx.author.send(":tada: You won! :tada: ") + await game["chat_msg"].channel.send(f":tada: {ctx.author.mention} just won Minesweeper! :tada:") del self.games[ctx.author.id] def reveal_zeros(self, revealed: GameBoard, board: GameBoard, x: int, y: int) -> None: @@ -203,7 +203,7 @@ class Minesweeper(commands.Cog): game["revealed"] = game["board"] await self.reload_board(ctx) await ctx.author.send(":no_entry: you canceled the game :no_entry:") - await game["chat_msg"].channel.send(f"{ctx.author.mention} just canceled minesweeper") + await game["chat_msg"].channel.send(f"{ctx.author.mention} just canceled Minesweeper.") del self.games[ctx.author.id] -- cgit v1.2.3 From 1a05919ea87d8f8b64bc30dedfe7b112f2c58a94 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Tue, 13 Aug 2019 02:50:32 +0200 Subject: change after suggestions. --- bot/seasons/evergreen/minesweeper.py | 241 +++++++++++++++++++---------------- 1 file changed, 131 insertions(+), 110 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 9e7fad12..60e0c2ae 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -1,21 +1,42 @@ +import logging import typing +from dataclasses import dataclass from random import random +import discord from discord.ext import commands -GameBoard = typing.List[typing.List[typing.Union[str, int]]] -DictOfGames = typing.Dict[int, typing.Dict] - - -class CordConverter(commands.Converter): - """Converter for cords.""" - - async def convert(self, ctx, cord: str) -> typing.Tuple[int, int]: - """Take in a cord string and turn it into x, y""" - if not 2 <= len(cord) <= 3: +from bot.constants import Client + +MESSAGE_MAPPING = { + 0: ":stop_button:", + 1: ":one:", + 2: ":two:", + 3: ":three:", + 4: ":four:", + 5: ":five:", + 6: ":six:", + 7: ":seven:", + 8: ":eight:", + 9: ":nine:", + 10: ":keycap_ten:", + "bomb": ":bomb:", + "hidden": ":grey_question:", + "flag": ":triangular_flag_on_post:" +} + +log = logging.getLogger(__name__) + + +class CoordinateConverter(commands.Converter): + """Converter for Coordinates.""" + + async def convert(self, ctx, Coordinate: str) -> typing.Tuple[int, int]: + """Take in a Coordinate string and turn it into x, y""" + if not 2 <= len(Coordinate) <= 3: raise commands.ArgumentParsingError() - value1 = cord[0] - value2 = cord[1:] + value1 = Coordinate[0] + value2 = Coordinate[1:] if not value2.isdigit(): raise commands.ArgumentParsingError() x = ord(value1) - 97 @@ -25,53 +46,53 @@ class CordConverter(commands.Converter): return x, y +GameDict = typing.List[typing.List[typing.Union[str, int]]] + + +@dataclass +class Game: + """The data for a game.""" + + board: GameDict + revealed: GameDict + dm_msg: discord.message + chat_msg: discord.message + + +DictOfGames = typing.Dict[int, Game] + + class Minesweeper(commands.Cog): - """Play a game of minesweeper.""" + """Play a game of Minesweeper.""" def __init__(self, bot: commands.Bot) -> None: self.games: DictOfGames = {} # Store the currently running games @staticmethod - def is_bomb(cell: typing.Union[str, int]) -> int: - """Returns 1 if `cell` is a bomb if not 0""" - return cell == "bomb" + def get_neighbours(x: int, y: int) -> typing.Generator: + """Get all the neighbouring x and y including it self.""" + for x_ in [x - 1, x, x + 1]: + for y_ in [y - 1, y, y + 1]: + if x_ != -1 and x_ != 10 and y_ != -1 and y_ != 10: + yield x_, y_ - def generate_board(self, bomb_chance: float) -> GameBoard: + def generate_board(self, bomb_chance: float) -> GameDict: """Generate a 2d array for the board.""" - board: GameBoard = [["bomb" if random() <= bomb_chance else "number" for _ in range(10)] for _ in range(10)] + board: GameDict = [["bomb" if random() <= bomb_chance else "number" for _ in range(10)] for _ in range(10)] for y, row in enumerate(board): for x, cell in enumerate(row): if cell == "number": # calculate bombs near it bombs = 0 - for x_ in [x - 1, x, x + 1]: - for y_ in [y - 1, y, y + 1]: - if x_ != -1 and x_ != 10 and y_ != -1 and y_ != 10 and board[y_][x_] == "bomb": - bombs += 1 - + for x_, y_ in self.get_neighbours(x, y): + if board[y_][x_] == "bomb": + bombs += 1 board[y][x] = bombs return board @staticmethod - def format_for_discord(board: GameBoard) -> str: - """Format the board to a string for discord.""" - mapping = { - 0: ":stop_button:", - 1: ":one:", - 2: ":two:", - 3: ":three:", - 4: ":four:", - 5: ":five:", - 6: ":six:", - 7: ":seven:", - 8: ":eight:", - 9: ":nine:", - 10: ":keycap_ten:", - "bomb": ":bomb:", - "hidden": ":grey_question:", - "flag": ":triangular_flag_on_post:" - } - + def format_for_discord(board: GameDict) -> str: + """Format the board as a string for Discord.""" discord_msg = ( ":stop_button: :regional_indicator_a::regional_indicator_b::regional_indicator_c:" ":regional_indicator_d::regional_indicator_e::regional_indicator_f::regional_indicator_g:" @@ -79,9 +100,9 @@ class Minesweeper(commands.Cog): ) rows: typing.List[str] = [] for row_number, row in enumerate(board): - new_row = mapping[row_number + 1] + " " + new_row = MESSAGE_MAPPING[row_number + 1] + " " for cell in row: - new_row += mapping[cell] + new_row += MESSAGE_MAPPING[cell] rows.append(new_row) discord_msg += "\n".join(rows) @@ -89,124 +110,124 @@ class Minesweeper(commands.Cog): @commands.command(name="minesweeper") async def minesweeper_command(self, ctx: commands.Context, bomb_chance: float = .2) -> None: - """Start a game of minesweeper.""" - if ctx.author.id in self.games.keys(): # Player is already playing - msg = await ctx.send(f"{ctx.author.mention} you already have a game running") + """Start a game of Minesweeper.""" + if ctx.author.id in self.games: # Player is already playing + msg = await ctx.send(f"{ctx.author.mention} you already have a game running!") await msg.delete(delay=2) await ctx.message.delete(delay=2) return # Add game to list - board: GameBoard = self.generate_board(bomb_chance) - revealed_board: GameBoard = [["hidden" for _ in range(10)] for _ in range(10)] + board: GameDict = self.generate_board(bomb_chance) + revealed_board: GameDict = [["hidden"] * 10 for _ in range(10)] - await ctx.send(f"{ctx.author.mention} is playing minesweeper") + await ctx.send(f"{ctx.author.mention} is playing Minesweeper") chat_msg = await ctx.send(self.format_for_discord(revealed_board)) - await ctx.author.send("play by typing: `.reveal xy [xy]` or `.flag xy [xy]` \n" - "close the game with `.end`\n" - "cords must be in format ``") + await ctx.author.send( + f"Play by typing: `{Client.prefix}reveal xy [xy]` or `{Client.prefix}flag xy [xy]` \n" + "Close the game with `.end`\n" + "Coordinates must be in format ``" + ) dm_msg = await ctx.author.send(self.format_for_discord(revealed_board)) - self.games[ctx.author.id] = { - "board": board, - "revealed": revealed_board, - "dm_msg": dm_msg, - "chat_msg": chat_msg - } + self.games[ctx.author.id] = Game( + board=board, + revealed=revealed_board, + dm_msg=dm_msg, + chat_msg=chat_msg + ) - async def reload_board(self, ctx: commands.Context) -> None: + async def update_boards(self, ctx: commands.Context) -> None: """Update both playing boards.""" game = self.games[ctx.author.id] - await game["dm_msg"].delete() - game["dm_msg"] = await ctx.author.send(self.format_for_discord(game["revealed"])) - await game["chat_msg"].edit(content=self.format_for_discord(game["revealed"])) + await game.dm_msg.delete() + game.dm_msg = await ctx.author.send(self.format_for_discord(game.revealed)) + await game.chat_msg.edit(content=self.format_for_discord(game.revealed)) @commands.dm_only() @commands.command(name="flag") - async def flag_command(self, ctx: commands.Context, *cords: CordConverter) -> None: + async def flag_command(self, ctx: commands.Context, *Coordinates: CoordinateConverter) -> None: """Place multiple flags on the board""" - board: GameBoard = self.games[ctx.author.id]["revealed"] - for x, y in cords: + board: GameDict = self.games[ctx.author.id].revealed + for x, y in Coordinates: if board[y][x] == "hidden": board[y][x] = "flag" - await self.reload_board(ctx) + await self.update_boards(ctx) async def lost(self, ctx: commands.Context) -> None: """The player lost the game""" game = self.games[ctx.author.id] - game["revealed"] = game["board"] - await self.reload_board(ctx) - await ctx.author.send(":fire: You lost :fire: ") - await game["chat_msg"].channel.send(f":fire: {ctx.author.mention} just lost minesweeper :fire:") - del self.games[ctx.author.id] + game.revealed = game.board + await ctx.author.send(":fire: You lost! :fire: ") + await game.chat_msg.channel.send(f":fire: {ctx.author.mention} just lost minesweeper :fire:") async def won(self, ctx: commands.Context) -> None: """The player won the game""" game = self.games[ctx.author.id] - game["revealed"] = game["board"] - await self.reload_board(ctx) + game.revealed = game.board await ctx.author.send(":tada: You won! :tada: ") - await game["chat_msg"].channel.send(f":tada: {ctx.author.mention} just won minesweeper :tada:") - del self.games[ctx.author.id] - - def reveal_zeros(self, revealed: GameBoard, board: GameBoard, x: int, y: int) -> None: - """Used when a 0 is encountered to do a flood fill""" - for x_ in [x - 1, x, x + 1]: - for y_ in [y - 1, y, y + 1]: - if x_ == -1 or x_ == 10 or y_ == -1 or y_ == 10 or revealed[y_][x_] != "hidden": - continue - revealed[y_][x_] = board[y_][x_] - if board[y_][x_] == 0: - self.reveal_zeros(revealed, board, x_, y_) - - async def check_if_won(self, ctx, revealed: GameBoard, board: GameBoard) -> bool: + await game.chat_msg.channel.send(f":tada: {ctx.author.mention} just won minesweeper :tada:") + + def reveal_zeros(self, revealed: GameDict, board: GameDict, x: int, y: int) -> None: + """Recursively reveal adjacent cells when a 0 cell is encountered.""" + for x_, y_ in self.get_neighbours(x, y): + if revealed[y_][x_] != "hidden": + continue + revealed[y_][x_] = board[y_][x_] + if board[y_][x_] == 0: + self.reveal_zeros(revealed, board, x_, y_) + + async def check_if_won(self, ctx, revealed: GameDict, board: GameDict) -> bool: """Checks if a player has won""" - for x_ in range(10): - for y_ in range(10): - if revealed[y_][x_] == "hidden" and board[y_][x_] != "bomb": - return True + for x in range(10): + for y in range(10): + if revealed[y][x] == "hidden" and board[y][x] != "bomb": + return False else: await self.won(ctx) - return False + return True - async def reveal_one(self, ctx: commands.Context, revealed: GameBoard, board: GameBoard, x: int, y: int) -> bool: + async def reveal_one(self, ctx: commands.Context, revealed: GameDict, board: GameDict, x: int, y: int) -> bool: """Reveal one square.""" revealed[y][x] = board[y][x] if board[y][x] == "bomb": await self.lost(ctx) - return False + return True # game ended elif board[y][x] == 0: self.reveal_zeros(revealed, board, x, y) - return await self.check_if_won(ctx, revealed, board) + won = await self.check_if_won(ctx, revealed, board) + return won @commands.dm_only() @commands.command(name="reveal") - async def reveal_command(self, ctx: commands.Context, *cords: CordConverter) -> None: + async def reveal_command(self, ctx: commands.Context, *Coordinates: CoordinateConverter) -> None: """Reveal multiple cells""" game = self.games[ctx.author.id] - revealed: GameBoard = game["revealed"] - board: GameBoard = game["board"] - - reload_board = True - for x, y in cords: - if not await self.reveal_one(ctx, revealed, board, x, y): - reload_board = False - if reload_board: - await self.reload_board(ctx) + revealed: GameDict = game.revealed + board: GameDict = game.board + + for x, y in Coordinates: + if await self.reveal_one(ctx, revealed, board, x, y): # game ended + await self.update_boards(ctx) + del self.games[ctx.author.id] + break + else: + await self.update_boards(ctx) @commands.command(name="end") async def end_command(self, ctx: commands.Context): """End the current game""" game = self.games[ctx.author.id] - game["revealed"] = game["board"] - await self.reload_board(ctx) + game.revealed = game.board + await self.update_boards(ctx) await ctx.author.send(":no_entry: you canceled the game :no_entry:") - await game["chat_msg"].channel.send(f"{ctx.author.mention} just canceled minesweeper") + await game.chat_msg.channel.send(f"{ctx.author.mention} just canceled minesweeper") del self.games[ctx.author.id] def setup(bot: commands.Bot) -> None: - """Cog load.""" + """Load the Minesweeper cog.""" bot.add_cog(Minesweeper(bot)) + log.info("minesweeper cog loaded") -- cgit v1.2.3 From 9896148f12a38590f7727a65033591ecaa2fa646 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Tue, 13 Aug 2019 04:29:07 +0200 Subject: fixed commit issue. --- bot/seasons/evergreen/minesweeper.py | 231 +++++++++++++++++++---------------- 1 file changed, 128 insertions(+), 103 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index f6c1d35a..60e0c2ae 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -1,21 +1,42 @@ +import logging import typing +from dataclasses import dataclass from random import random +import discord from discord.ext import commands -GameBoard = typing.List[typing.List[typing.Union[str, int]]] -DictOfGames = typing.Dict[int, typing.Dict] - - -class CordConverter(commands.Converter): - """Converter for cords.""" - - async def convert(self, ctx, cord: str) -> typing.Tuple[int, int]: - """Take in a cord string and turn it into x, y""" - if not 2 <= len(cord) <= 3: +from bot.constants import Client + +MESSAGE_MAPPING = { + 0: ":stop_button:", + 1: ":one:", + 2: ":two:", + 3: ":three:", + 4: ":four:", + 5: ":five:", + 6: ":six:", + 7: ":seven:", + 8: ":eight:", + 9: ":nine:", + 10: ":keycap_ten:", + "bomb": ":bomb:", + "hidden": ":grey_question:", + "flag": ":triangular_flag_on_post:" +} + +log = logging.getLogger(__name__) + + +class CoordinateConverter(commands.Converter): + """Converter for Coordinates.""" + + async def convert(self, ctx, Coordinate: str) -> typing.Tuple[int, int]: + """Take in a Coordinate string and turn it into x, y""" + if not 2 <= len(Coordinate) <= 3: raise commands.ArgumentParsingError() - value1 = cord[0] - value2 = cord[1:] + value1 = Coordinate[0] + value2 = Coordinate[1:] if not value2.isdigit(): raise commands.ArgumentParsingError() x = ord(value1) - 97 @@ -25,53 +46,53 @@ class CordConverter(commands.Converter): return x, y +GameDict = typing.List[typing.List[typing.Union[str, int]]] + + +@dataclass +class Game: + """The data for a game.""" + + board: GameDict + revealed: GameDict + dm_msg: discord.message + chat_msg: discord.message + + +DictOfGames = typing.Dict[int, Game] + + class Minesweeper(commands.Cog): - """Play a game of minesweeper.""" + """Play a game of Minesweeper.""" def __init__(self, bot: commands.Bot) -> None: self.games: DictOfGames = {} # Store the currently running games @staticmethod - def is_bomb(cell: typing.Union[str, int]) -> int: - """Returns 1 if `cell` is a bomb if not 0""" - return cell == "bomb" + def get_neighbours(x: int, y: int) -> typing.Generator: + """Get all the neighbouring x and y including it self.""" + for x_ in [x - 1, x, x + 1]: + for y_ in [y - 1, y, y + 1]: + if x_ != -1 and x_ != 10 and y_ != -1 and y_ != 10: + yield x_, y_ - def generate_board(self, bomb_chance: float) -> GameBoard: + def generate_board(self, bomb_chance: float) -> GameDict: """Generate a 2d array for the board.""" - board: GameBoard = [["bomb" if random() <= bomb_chance else "number" for _ in range(10)] for _ in range(10)] + board: GameDict = [["bomb" if random() <= bomb_chance else "number" for _ in range(10)] for _ in range(10)] for y, row in enumerate(board): for x, cell in enumerate(row): if cell == "number": # calculate bombs near it bombs = 0 - for x_ in [x - 1, x, x + 1]: - for y_ in [y - 1, y, y + 1]: - if x_ != -1 and x_ != 10 and y_ != -1 and y_ != 10 and board[y_][x_] == "bomb": - bombs += 1 - + for x_, y_ in self.get_neighbours(x, y): + if board[y_][x_] == "bomb": + bombs += 1 board[y][x] = bombs return board @staticmethod - def format_for_discord(board: GameBoard) -> str: - """Format the board to a string for discord.""" - mapping = { - 0: ":stop_button:", - 1: ":one:", - 2: ":two:", - 3: ":three:", - 4: ":four:", - 5: ":five:", - 6: ":six:", - 7: ":seven:", - 8: ":eight:", - 9: ":nine:", - 10: ":keycap_ten:", - "bomb": ":bomb:", - "hidden": ":grey_question:", - "flag": ":triangular_flag_on_post:" - } - + def format_for_discord(board: GameDict) -> str: + """Format the board as a string for Discord.""" discord_msg = ( ":stop_button: :regional_indicator_a::regional_indicator_b::regional_indicator_c:" ":regional_indicator_d::regional_indicator_e::regional_indicator_f::regional_indicator_g:" @@ -79,9 +100,9 @@ class Minesweeper(commands.Cog): ) rows: typing.List[str] = [] for row_number, row in enumerate(board): - new_row = mapping[row_number + 1] + " " + new_row = MESSAGE_MAPPING[row_number + 1] + " " for cell in row: - new_row += mapping[cell] + new_row += MESSAGE_MAPPING[cell] rows.append(new_row) discord_msg += "\n".join(rows) @@ -89,120 +110,124 @@ class Minesweeper(commands.Cog): @commands.command(name="minesweeper") async def minesweeper_command(self, ctx: commands.Context, bomb_chance: float = .2) -> None: - """Start a game of minesweeper.""" - if ctx.author.id in self.games.keys(): # Player is already playing - msg = await ctx.send(f"{ctx.author.mention} you already have a game running") + """Start a game of Minesweeper.""" + if ctx.author.id in self.games: # Player is already playing + msg = await ctx.send(f"{ctx.author.mention} you already have a game running!") await msg.delete(delay=2) await ctx.message.delete(delay=2) return # Add game to list - board: GameBoard = self.generate_board(bomb_chance) - revealed_board: GameBoard = [["hidden" for _ in range(10)] for _ in range(10)] + board: GameDict = self.generate_board(bomb_chance) + revealed_board: GameDict = [["hidden"] * 10 for _ in range(10)] - await ctx.send(f"{ctx.author.mention} is playing minesweeper") + await ctx.send(f"{ctx.author.mention} is playing Minesweeper") chat_msg = await ctx.send(self.format_for_discord(revealed_board)) - await ctx.author.send("play by typing: `.reveal xy [xy]` or `.flag xy [xy]` \n" - "close the game with `.end`\n" - "cords must be in format ``") + await ctx.author.send( + f"Play by typing: `{Client.prefix}reveal xy [xy]` or `{Client.prefix}flag xy [xy]` \n" + "Close the game with `.end`\n" + "Coordinates must be in format ``" + ) dm_msg = await ctx.author.send(self.format_for_discord(revealed_board)) - self.games[ctx.author.id] = { - "board": board, - "revealed": revealed_board, - "dm_msg": dm_msg, - "chat_msg": chat_msg - } + self.games[ctx.author.id] = Game( + board=board, + revealed=revealed_board, + dm_msg=dm_msg, + chat_msg=chat_msg + ) - async def reload_board(self, ctx: commands.Context) -> None: + async def update_boards(self, ctx: commands.Context) -> None: """Update both playing boards.""" game = self.games[ctx.author.id] - await game["dm_msg"].delete() - game["dm_msg"] = await ctx.author.send(self.format_for_discord(game["revealed"])) - await game["chat_msg"].edit(content=self.format_for_discord(game["revealed"])) + await game.dm_msg.delete() + game.dm_msg = await ctx.author.send(self.format_for_discord(game.revealed)) + await game.chat_msg.edit(content=self.format_for_discord(game.revealed)) @commands.dm_only() @commands.command(name="flag") - async def flag_command(self, ctx: commands.Context, *cords: CordConverter) -> None: + async def flag_command(self, ctx: commands.Context, *Coordinates: CoordinateConverter) -> None: """Place multiple flags on the board""" - board: GameBoard = self.games[ctx.author.id]["revealed"] - for x, y in cords: + board: GameDict = self.games[ctx.author.id].revealed + for x, y in Coordinates: if board[y][x] == "hidden": board[y][x] = "flag" - await self.reload_board(ctx) + await self.update_boards(ctx) async def lost(self, ctx: commands.Context) -> None: """The player lost the game""" game = self.games[ctx.author.id] game.revealed = game.board await ctx.author.send(":fire: You lost! :fire: ") - await game.chat_msg.channel.send(f":fire: {ctx.author.mention} just lost Minesweeper! :fire:") + await game.chat_msg.channel.send(f":fire: {ctx.author.mention} just lost minesweeper :fire:") async def won(self, ctx: commands.Context) -> None: """The player won the game""" game = self.games[ctx.author.id] game.revealed = game.board await ctx.author.send(":tada: You won! :tada: ") - await game.chat_msg.channel.send(f":tada: {ctx.author.mention} just won Minesweeper! :tada:") - - def reveal_zeros(self, revealed: GameBoard, board: GameBoard, x: int, y: int) -> None: - """Used when a 0 is encountered to do a flood fill""" - for x_ in [x - 1, x, x + 1]: - for y_ in [y - 1, y, y + 1]: - if x_ == -1 or x_ == 10 or y_ == -1 or y_ == 10 or revealed[y_][x_] != "hidden": - continue - revealed[y_][x_] = board[y_][x_] - if board[y_][x_] == 0: - self.reveal_zeros(revealed, board, x_, y_) - - async def check_if_won(self, ctx, revealed: GameBoard, board: GameBoard) -> bool: + await game.chat_msg.channel.send(f":tada: {ctx.author.mention} just won minesweeper :tada:") + + def reveal_zeros(self, revealed: GameDict, board: GameDict, x: int, y: int) -> None: + """Recursively reveal adjacent cells when a 0 cell is encountered.""" + for x_, y_ in self.get_neighbours(x, y): + if revealed[y_][x_] != "hidden": + continue + revealed[y_][x_] = board[y_][x_] + if board[y_][x_] == 0: + self.reveal_zeros(revealed, board, x_, y_) + + async def check_if_won(self, ctx, revealed: GameDict, board: GameDict) -> bool: """Checks if a player has won""" - for x_ in range(10): - for y_ in range(10): - if revealed[y_][x_] == "hidden" and board[y_][x_] != "bomb": - return True + for x in range(10): + for y in range(10): + if revealed[y][x] == "hidden" and board[y][x] != "bomb": + return False else: await self.won(ctx) - return False + return True - async def reveal_one(self, ctx: commands.Context, revealed: GameBoard, board: GameBoard, x: int, y: int) -> bool: + async def reveal_one(self, ctx: commands.Context, revealed: GameDict, board: GameDict, x: int, y: int) -> bool: """Reveal one square.""" revealed[y][x] = board[y][x] if board[y][x] == "bomb": await self.lost(ctx) - return False + return True # game ended elif board[y][x] == 0: self.reveal_zeros(revealed, board, x, y) - return await self.check_if_won(ctx, revealed, board) + won = await self.check_if_won(ctx, revealed, board) + return won @commands.dm_only() @commands.command(name="reveal") - async def reveal_command(self, ctx: commands.Context, *cords: CordConverter) -> None: + async def reveal_command(self, ctx: commands.Context, *Coordinates: CoordinateConverter) -> None: """Reveal multiple cells""" game = self.games[ctx.author.id] - revealed: GameBoard = game["revealed"] - board: GameBoard = game["board"] - - reload_board = True - for x, y in cords: - if not await self.reveal_one(ctx, revealed, board, x, y): - reload_board = False - if reload_board: - await self.reload_board(ctx) + revealed: GameDict = game.revealed + board: GameDict = game.board + + for x, y in Coordinates: + if await self.reveal_one(ctx, revealed, board, x, y): # game ended + await self.update_boards(ctx) + del self.games[ctx.author.id] + break + else: + await self.update_boards(ctx) @commands.command(name="end") async def end_command(self, ctx: commands.Context): """End the current game""" game = self.games[ctx.author.id] - game["revealed"] = game["board"] - await self.reload_board(ctx) + game.revealed = game.board + await self.update_boards(ctx) await ctx.author.send(":no_entry: you canceled the game :no_entry:") - await game.chat_msg.channel.send(f"{ctx.author.mention} just canceled Minesweeper") + await game.chat_msg.channel.send(f"{ctx.author.mention} just canceled minesweeper") del self.games[ctx.author.id] def setup(bot: commands.Bot) -> None: - """Cog load.""" + """Load the Minesweeper cog.""" bot.add_cog(Minesweeper(bot)) + log.info("minesweeper cog loaded") -- cgit v1.2.3 From 5bfbd5a07896736a03a5e07625acfa6f6b47a073 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Tue, 13 Aug 2019 04:58:22 +0200 Subject: Apply suggestions from code review Co-Authored-By: Mark --- bot/seasons/evergreen/minesweeper.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 60e0c2ae..9ca36d57 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -126,8 +126,8 @@ class Minesweeper(commands.Cog): await ctx.author.send( f"Play by typing: `{Client.prefix}reveal xy [xy]` or `{Client.prefix}flag xy [xy]` \n" - "Close the game with `.end`\n" - "Coordinates must be in format ``" + f"Close the game with `{Client.prefix}end`\n" + "Coordinates must be in the format ``" ) dm_msg = await ctx.author.send(self.format_for_discord(revealed_board)) @@ -160,15 +160,15 @@ class Minesweeper(commands.Cog): """The player lost the game""" game = self.games[ctx.author.id] game.revealed = game.board - await ctx.author.send(":fire: You lost! :fire: ") - await game.chat_msg.channel.send(f":fire: {ctx.author.mention} just lost minesweeper :fire:") + await ctx.author.send(":fire: You lost! :fire:") + await game.chat_msg.channel.send(f":fire: {ctx.author.mention} just lost Minesweeper! :fire:") async def won(self, ctx: commands.Context) -> None: """The player won the game""" game = self.games[ctx.author.id] game.revealed = game.board - await ctx.author.send(":tada: You won! :tada: ") - await game.chat_msg.channel.send(f":tada: {ctx.author.mention} just won minesweeper :tada:") + await ctx.author.send(":tada: You won! :tada:") + await game.chat_msg.channel.send(f":tada: {ctx.author.mention} just won Minesweeper! :tada:") def reveal_zeros(self, revealed: GameDict, board: GameDict, x: int, y: int) -> None: """Recursively reveal adjacent cells when a 0 cell is encountered.""" @@ -183,7 +183,7 @@ class Minesweeper(commands.Cog): """Checks if a player has won""" for x in range(10): for y in range(10): - if revealed[y][x] == "hidden" and board[y][x] != "bomb": + if revealed[y][x] == "hidden": return False else: await self.won(ctx) @@ -222,12 +222,12 @@ class Minesweeper(commands.Cog): game = self.games[ctx.author.id] game.revealed = game.board await self.update_boards(ctx) - await ctx.author.send(":no_entry: you canceled the game :no_entry:") - await game.chat_msg.channel.send(f"{ctx.author.mention} just canceled minesweeper") + await ctx.author.send(":no_entry: You canceled the game. :no_entry:") + await game.chat_msg.channel.send(f"{ctx.author.mention} just canceled Minesweeper.") del self.games[ctx.author.id] def setup(bot: commands.Bot) -> None: """Load the Minesweeper cog.""" bot.add_cog(Minesweeper(bot)) - log.info("minesweeper cog loaded") + log.info("Minesweeper cog loaded") -- cgit v1.2.3 From 293624295803f0442d6e65451a250560e559eea8 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Tue, 13 Aug 2019 05:12:46 +0200 Subject: change after suggestions. --- bot/seasons/evergreen/minesweeper.py | 68 ++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 30 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 60e0c2ae..3bd2f431 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -31,42 +31,46 @@ log = logging.getLogger(__name__) class CoordinateConverter(commands.Converter): """Converter for Coordinates.""" - async def convert(self, ctx, Coordinate: str) -> typing.Tuple[int, int]: - """Take in a Coordinate string and turn it into x, y""" - if not 2 <= len(Coordinate) <= 3: + async def convert(self, ctx, coordinate: str) -> typing.Tuple[int, int]: + """Take in a coordinate string and turn it into x, y""" + if not 2 <= len(coordinate) <= 3: raise commands.ArgumentParsingError() - value1 = Coordinate[0] - value2 = Coordinate[1:] + + value1 = coordinate[0] + value2 = coordinate[1:] + if not value2.isdigit(): raise commands.ArgumentParsingError() + x = ord(value1) - 97 y = int(value2) - 1 + if (not 0 <= x <= 9) or (not 0 <= y <= 9): raise commands.ArgumentParsingError() return x, y -GameDict = typing.List[typing.List[typing.Union[str, int]]] +GameBoard = typing.List[typing.List[typing.Union[str, int]]] @dataclass class Game: """The data for a game.""" - board: GameDict - revealed: GameDict + board: GameBoard + revealed: GameBoard dm_msg: discord.message chat_msg: discord.message -DictOfGames = typing.Dict[int, Game] +GamesDict = typing.Dict[int, Game] class Minesweeper(commands.Cog): """Play a game of Minesweeper.""" def __init__(self, bot: commands.Bot) -> None: - self.games: DictOfGames = {} # Store the currently running games + self.games: GamesDict = {} # Store the currently running games @staticmethod def get_neighbours(x: int, y: int) -> typing.Generator: @@ -76,9 +80,9 @@ class Minesweeper(commands.Cog): if x_ != -1 and x_ != 10 and y_ != -1 and y_ != 10: yield x_, y_ - def generate_board(self, bomb_chance: float) -> GameDict: + def generate_board(self, bomb_chance: float) -> GameBoard: """Generate a 2d array for the board.""" - board: GameDict = [["bomb" if random() <= bomb_chance else "number" for _ in range(10)] for _ in range(10)] + board: GameBoard = [["bomb" if random() <= bomb_chance else "number" for _ in range(10)] for _ in range(10)] for y, row in enumerate(board): for x, cell in enumerate(row): if cell == "number": @@ -91,7 +95,7 @@ class Minesweeper(commands.Cog): return board @staticmethod - def format_for_discord(board: GameDict) -> str: + def format_for_discord(board: GameBoard) -> str: """Format the board as a string for Discord.""" discord_msg = ( ":stop_button: :regional_indicator_a::regional_indicator_b::regional_indicator_c:" @@ -118,8 +122,8 @@ class Minesweeper(commands.Cog): return # Add game to list - board: GameDict = self.generate_board(bomb_chance) - revealed_board: GameDict = [["hidden"] * 10 for _ in range(10)] + board: GameBoard = self.generate_board(bomb_chance) + revealed_board: GameBoard = [["hidden"] * 10 for _ in range(10)] await ctx.send(f"{ctx.author.mention} is playing Minesweeper") chat_msg = await ctx.send(self.format_for_discord(revealed_board)) @@ -147,10 +151,10 @@ class Minesweeper(commands.Cog): @commands.dm_only() @commands.command(name="flag") - async def flag_command(self, ctx: commands.Context, *Coordinates: CoordinateConverter) -> None: + async def flag_command(self, ctx: commands.Context, *coordinates: CoordinateConverter) -> None: """Place multiple flags on the board""" - board: GameDict = self.games[ctx.author.id].revealed - for x, y in Coordinates: + board: GameBoard = self.games[ctx.author.id].revealed + for x, y in coordinates: if board[y][x] == "hidden": board[y][x] = "flag" @@ -170,7 +174,7 @@ class Minesweeper(commands.Cog): await ctx.author.send(":tada: You won! :tada: ") await game.chat_msg.channel.send(f":tada: {ctx.author.mention} just won minesweeper :tada:") - def reveal_zeros(self, revealed: GameDict, board: GameDict, x: int, y: int) -> None: + def reveal_zeros(self, revealed: GameBoard, board: GameBoard, x: int, y: int) -> None: """Recursively reveal adjacent cells when a 0 cell is encountered.""" for x_, y_ in self.get_neighbours(x, y): if revealed[y_][x_] != "hidden": @@ -179,7 +183,7 @@ class Minesweeper(commands.Cog): if board[y_][x_] == 0: self.reveal_zeros(revealed, board, x_, y_) - async def check_if_won(self, ctx, revealed: GameDict, board: GameDict) -> bool: + async def check_if_won(self, ctx, revealed: GameBoard, board: GameBoard) -> bool: """Checks if a player has won""" for x in range(10): for y in range(10): @@ -189,26 +193,29 @@ class Minesweeper(commands.Cog): await self.won(ctx) return True - async def reveal_one(self, ctx: commands.Context, revealed: GameDict, board: GameDict, x: int, y: int) -> bool: - """Reveal one square.""" + async def reveal_one(self, ctx: commands.Context, revealed: GameBoard, board: GameBoard, x: int, y: int) -> bool: + """ + Reveal one square. + + return is True if the game ended, breaking the loop in `reveal_command` and deleting the game + """ revealed[y][x] = board[y][x] if board[y][x] == "bomb": await self.lost(ctx) return True # game ended elif board[y][x] == 0: self.reveal_zeros(revealed, board, x, y) - won = await self.check_if_won(ctx, revealed, board) - return won + return await self.check_if_won(ctx, revealed, board) @commands.dm_only() @commands.command(name="reveal") - async def reveal_command(self, ctx: commands.Context, *Coordinates: CoordinateConverter) -> None: + async def reveal_command(self, ctx: commands.Context, *coordinates: CoordinateConverter) -> None: """Reveal multiple cells""" game = self.games[ctx.author.id] - revealed: GameDict = game.revealed - board: GameDict = game.board + revealed: GameBoard = game.revealed + board: GameBoard = game.board - for x, y in Coordinates: + for x, y in coordinates: if await self.reveal_one(ctx, revealed, board, x, y): # game ended await self.update_boards(ctx) del self.games[ctx.author.id] @@ -222,8 +229,9 @@ class Minesweeper(commands.Cog): game = self.games[ctx.author.id] game.revealed = game.board await self.update_boards(ctx) - await ctx.author.send(":no_entry: you canceled the game :no_entry:") - await game.chat_msg.channel.send(f"{ctx.author.mention} just canceled minesweeper") + new_msg = f":no_entry: Game canceled :no_entry:\n{self.format_for_discord(game.revealed)}" + await game.dm_msg.edit(content=new_msg) + await game.chat_msg.edit(content=new_msg) del self.games[ctx.author.id] -- cgit v1.2.3 From a6bcd09015fc37464aec953f1c385f061cebe351 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Tue, 13 Aug 2019 05:24:58 +0200 Subject: changed from using `format_discord` to use the content of the last message. --- bot/seasons/evergreen/minesweeper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index e0cb9b13..19486033 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -229,7 +229,7 @@ class Minesweeper(commands.Cog): game = self.games[ctx.author.id] game.revealed = game.board await self.update_boards(ctx) - new_msg = f":no_entry: Game canceled :no_entry:\n{self.format_for_discord(game.revealed)}" + new_msg = f":no_entry: Game canceled :no_entry:\n{game.dm_msg.content}" await game.dm_msg.edit(content=new_msg) await game.chat_msg.edit(content=new_msg) del self.games[ctx.author.id] -- cgit v1.2.3 From 00647b2a00e0392563ee768fc84ef57d0502e01f Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Tue, 13 Aug 2019 19:22:30 +0200 Subject: Apply suggestions from code review Co-Authored-By: Ava --- bot/seasons/evergreen/minesweeper.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 19486033..65d293c9 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -34,19 +34,19 @@ class CoordinateConverter(commands.Converter): async def convert(self, ctx, coordinate: str) -> typing.Tuple[int, int]: """Take in a coordinate string and turn it into x, y""" if not 2 <= len(coordinate) <= 3: - raise commands.ArgumentParsingError() + raise commands.BadArgument('Invalid co-ordinate provided') - value1 = coordinate[0] + digit, letter = sorted(coordinate.lower()) value2 = coordinate[1:] if not value2.isdigit(): - raise commands.ArgumentParsingError() + raise commands.BadArgument - x = ord(value1) - 97 + x = ord(value1) - ord('a') y = int(value2) - 1 if (not 0 <= x <= 9) or (not 0 <= y <= 9): - raise commands.ArgumentParsingError() + raise commands.BadArgument return x, y @@ -59,8 +59,8 @@ class Game: board: GameBoard revealed: GameBoard - dm_msg: discord.message - chat_msg: discord.message + dm_msg: discord.Message + chat_msg: discord.Message GamesDict = typing.Dict[int, Game] @@ -116,7 +116,7 @@ class Minesweeper(commands.Cog): async def minesweeper_command(self, ctx: commands.Context, bomb_chance: float = .2) -> None: """Start a game of Minesweeper.""" if ctx.author.id in self.games: # Player is already playing - msg = await ctx.send(f"{ctx.author.mention} you already have a game running!") + msg = await ctx.send(f"{ctx.author.mention} you already have a game running!", delete_after=2) await msg.delete(delay=2) await ctx.message.delete(delay=2) return -- cgit v1.2.3 From 0b3687b799d633eef12cd48ea4a6f0cae35080f8 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Tue, 13 Aug 2019 20:19:49 +0200 Subject: changed after suggestions. --- bot/seasons/evergreen/minesweeper.py | 93 +++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 34 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 19486033..d43233d4 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -36,14 +36,13 @@ class CoordinateConverter(commands.Converter): if not 2 <= len(coordinate) <= 3: raise commands.ArgumentParsingError() - value1 = coordinate[0] - value2 = coordinate[1:] + digit, letter = sorted(coordinate.lower()) - if not value2.isdigit(): + if not letter.isdigit(): raise commands.ArgumentParsingError() - x = ord(value1) - 97 - y = int(value2) - 1 + x = ord(letter.lower()) - 97 + y = int(digit) - 1 if (not 0 <= x <= 9) or (not 0 <= y <= 9): raise commands.ArgumentParsingError() @@ -61,6 +60,7 @@ class Game: revealed: GameBoard dm_msg: discord.message chat_msg: discord.message + activated_on_server: bool GamesDict = typing.Dict[int, Game] @@ -72,8 +72,13 @@ class Minesweeper(commands.Cog): def __init__(self, bot: commands.Bot) -> None: self.games: GamesDict = {} # Store the currently running games + @commands.group(name='minesweeper', aliases=('ms',), invoke_without_command=True) + async def minesweeper_group(self, ctx: commands.Context): + """Commands for Playing Minesweeper""" + await ctx.send_help(ctx.command) + @staticmethod - def get_neighbours(x: int, y: int) -> typing.Generator: + def get_neighbours(x: int, y: int) -> typing.Generator[typing.Tuple[int, int], None, None]: """Get all the neighbouring x and y including it self.""" for x_ in [x - 1, x, x + 1]: for y_ in [y - 1, y, y + 1]: @@ -82,7 +87,12 @@ class Minesweeper(commands.Cog): def generate_board(self, bomb_chance: float) -> GameBoard: """Generate a 2d array for the board.""" - board: GameBoard = [["bomb" if random() <= bomb_chance else "number" for _ in range(10)] for _ in range(10)] + board: GameBoard = [ + [ + "bomb" if random() <= bomb_chance else "number" + for _ in range(10) + ] for _ in range(10) + ] for y, row in enumerate(board): for x, cell in enumerate(row): if cell == "number": @@ -102,22 +112,20 @@ class Minesweeper(commands.Cog): ":regional_indicator_d::regional_indicator_e::regional_indicator_f::regional_indicator_g:" ":regional_indicator_h::regional_indicator_i::regional_indicator_j:\n\n" ) - rows: typing.List[str] = [] + rows = [] for row_number, row in enumerate(board): - new_row = MESSAGE_MAPPING[row_number + 1] + " " - for cell in row: - new_row += MESSAGE_MAPPING[cell] + new_row = f"{MESSAGE_MAPPING[row_number + 1]} " + new_row += "".join(MESSAGE_MAPPING[cell] for cell in row) rows.append(new_row) discord_msg += "\n".join(rows) return discord_msg - @commands.command(name="minesweeper") - async def minesweeper_command(self, ctx: commands.Context, bomb_chance: float = .2) -> None: + @minesweeper_group.command(name="start") + async def start_command(self, ctx: commands.Context, bomb_chance: float = .2) -> None: """Start a game of Minesweeper.""" if ctx.author.id in self.games: # Player is already playing - msg = await ctx.send(f"{ctx.author.mention} you already have a game running!") - await msg.delete(delay=2) + await ctx.send(f"{ctx.author.mention} you already have a game running!") await ctx.message.delete(delay=2) return @@ -125,13 +133,15 @@ class Minesweeper(commands.Cog): board: GameBoard = self.generate_board(bomb_chance) revealed_board: GameBoard = [["hidden"] * 10 for _ in range(10)] - await ctx.send(f"{ctx.author.mention} is playing Minesweeper") - chat_msg = await ctx.send(self.format_for_discord(revealed_board)) + if ctx.guild: + await ctx.send(f"{ctx.author.mention} is playing Minesweeper") + chat_msg = await ctx.send(self.format_for_discord(revealed_board)) + else: + chat_msg = None await ctx.author.send( f"Play by typing: `{Client.prefix}reveal xy [xy]` or `{Client.prefix}flag xy [xy]` \n" f"Close the game with `{Client.prefix}end`\n" - "Coordinates must be in format ``" ) dm_msg = await ctx.author.send(self.format_for_discord(revealed_board)) @@ -139,7 +149,8 @@ class Minesweeper(commands.Cog): board=board, revealed=revealed_board, dm_msg=dm_msg, - chat_msg=chat_msg + chat_msg=chat_msg, + activated_on_server=ctx.guild is not None ) async def update_boards(self, ctx: commands.Context) -> None: @@ -147,10 +158,11 @@ class Minesweeper(commands.Cog): game = self.games[ctx.author.id] await game.dm_msg.delete() game.dm_msg = await ctx.author.send(self.format_for_discord(game.revealed)) - await game.chat_msg.edit(content=self.format_for_discord(game.revealed)) + if game.activated_on_server: + await game.chat_msg.edit(content=self.format_for_discord(game.revealed)) @commands.dm_only() - @commands.command(name="flag") + @minesweeper_group.command(name="flag") async def flag_command(self, ctx: commands.Context, *coordinates: CoordinateConverter) -> None: """Place multiple flags on the board""" board: GameBoard = self.games[ctx.author.id].revealed @@ -165,14 +177,16 @@ class Minesweeper(commands.Cog): game = self.games[ctx.author.id] game.revealed = game.board await ctx.author.send(":fire: You lost! :fire:") - await game.chat_msg.channel.send(f":fire: {ctx.author.mention} just lost Minesweeper! :fire:") + if game.activated_on_server: + await game.chat_msg.channel.send(f":fire: {ctx.author.mention} just lost Minesweeper! :fire:") async def won(self, ctx: commands.Context) -> None: """The player won the game""" game = self.games[ctx.author.id] game.revealed = game.board await ctx.author.send(":tada: You won! :tada:") - await game.chat_msg.channel.send(f":tada: {ctx.author.mention} just won Minesweeper! :tada:") + if game.activated_on_server: + await game.chat_msg.channel.send(f":tada: {ctx.author.mention} just won Minesweeper! :tada:") def reveal_zeros(self, revealed: GameBoard, board: GameBoard, x: int, y: int) -> None: """Recursively reveal adjacent cells when a 0 cell is encountered.""" @@ -185,15 +199,24 @@ class Minesweeper(commands.Cog): async def check_if_won(self, ctx, revealed: GameBoard, board: GameBoard) -> bool: """Checks if a player has won""" - for x in range(10): - for y in range(10): - if revealed[y][x] == "hidden": - return False + if any( + revealed[y][x] in ["hidden", "flag"] and board[y][x] != "bomb" + for x in range(10) + for y in range(10) + ): + return False else: await self.won(ctx) return True - async def reveal_one(self, ctx: commands.Context, revealed: GameBoard, board: GameBoard, x: int, y: int) -> bool: + async def reveal_one( + self, + ctx: commands.Context, + revealed: GameBoard, + board: GameBoard, + x: int, + y: int + ) -> bool: """ Reveal one square. @@ -202,13 +225,13 @@ class Minesweeper(commands.Cog): revealed[y][x] = board[y][x] if board[y][x] == "bomb": await self.lost(ctx) - return True # game ended + return True elif board[y][x] == 0: self.reveal_zeros(revealed, board, x, y) return await self.check_if_won(ctx, revealed, board) @commands.dm_only() - @commands.command(name="reveal") + @minesweeper_group.command(name="reveal") async def reveal_command(self, ctx: commands.Context, *coordinates: CoordinateConverter) -> None: """Reveal multiple cells""" game = self.games[ctx.author.id] @@ -216,22 +239,24 @@ class Minesweeper(commands.Cog): board: GameBoard = game.board for x, y in coordinates: - if await self.reveal_one(ctx, revealed, board, x, y): # game ended + # reveal_one returns True if the revealed cell is a bomb or the player won., ending the game + if await self.reveal_one(ctx, revealed, board, x, y): await self.update_boards(ctx) del self.games[ctx.author.id] break else: await self.update_boards(ctx) - @commands.command(name="end") + @minesweeper_group.command(name="end") async def end_command(self, ctx: commands.Context): - """End the current game""" + """End your current game""" game = self.games[ctx.author.id] game.revealed = game.board await self.update_boards(ctx) new_msg = f":no_entry: Game canceled :no_entry:\n{game.dm_msg.content}" await game.dm_msg.edit(content=new_msg) - await game.chat_msg.edit(content=new_msg) + if game.activated_on_server: + await game.chat_msg.edit(content=new_msg) del self.games[ctx.author.id] -- cgit v1.2.3 From 95bea08cb90975962ceb25af7180334d25254999 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Tue, 13 Aug 2019 22:26:25 +0200 Subject: Apply suggestions from code review Co-Authored-By: Thomas Petersson --- bot/seasons/evergreen/minesweeper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index e005bbb9..b742512d 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -239,7 +239,7 @@ class Minesweeper(commands.Cog): board: GameBoard = game.board for x, y in coordinates: - # reveal_one returns True if the revealed cell is a bomb or the player won., ending the game + # reveal_one returns True if the revealed cell is a bomb or the player won, ending the game if await self.reveal_one(ctx, revealed, board, x, y): await self.update_boards(ctx) del self.games[ctx.author.id] -- cgit v1.2.3 From 3fffa3a0a5f8d819ecd11baf5b0907f983a737f0 Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Wed, 14 Aug 2019 02:12:48 +0200 Subject: Apply suggestions from code review Co-Authored-By: Mark --- bot/seasons/evergreen/minesweeper.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index b742512d..27ca9675 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -38,7 +38,7 @@ class CoordinateConverter(commands.Converter): digit, letter = sorted(coordinate.lower()) - if not letter.isdigit(): + if not digit.isdigit(): raise commands.BadArgument x = ord(letter) - ord('a') @@ -140,8 +140,8 @@ class Minesweeper(commands.Cog): chat_msg = None await ctx.author.send( - f"Play by typing: `{Client.prefix}reveal xy [xy]` or `{Client.prefix}flag xy [xy]` \n" - f"Close the game with `{Client.prefix}end`\n" + f"Play by typing: `{Client.prefix}ms reveal xy [xy]` or `{Client.prefix}ms flag xy [xy]` \n" + f"Close the game with `{Client.prefix}ms end`\n" ) dm_msg = await ctx.author.send(self.format_for_discord(revealed_board)) -- cgit v1.2.3 From 6a7aec50e891557c08e42b473fc3770f04537a1c Mon Sep 17 00:00:00 2001 From: vivax3794 <51753506+vivax3794@users.noreply.github.com> Date: Wed, 14 Aug 2019 09:39:41 +0200 Subject: added header to message. so the board looks correct on compact mode. --- bot/seasons/evergreen/minesweeper.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/seasons/evergreen/minesweeper.py b/bot/seasons/evergreen/minesweeper.py index 27ca9675..9333bb68 100644 --- a/bot/seasons/evergreen/minesweeper.py +++ b/bot/seasons/evergreen/minesweeper.py @@ -135,7 +135,7 @@ class Minesweeper(commands.Cog): if ctx.guild: await ctx.send(f"{ctx.author.mention} is playing Minesweeper") - chat_msg = await ctx.send(self.format_for_discord(revealed_board)) + chat_msg = await ctx.send(f"Here's there board!\n{self.format_for_discord(revealed_board)}") else: chat_msg = None @@ -143,7 +143,7 @@ class Minesweeper(commands.Cog): f"Play by typing: `{Client.prefix}ms reveal xy [xy]` or `{Client.prefix}ms flag xy [xy]` \n" f"Close the game with `{Client.prefix}ms end`\n" ) - dm_msg = await ctx.author.send(self.format_for_discord(revealed_board)) + dm_msg = await ctx.author.send(f"Here's your board!\n{self.format_for_discord(revealed_board)}") self.games[ctx.author.id] = Game( board=board, @@ -157,9 +157,9 @@ class Minesweeper(commands.Cog): """Update both playing boards.""" game = self.games[ctx.author.id] await game.dm_msg.delete() - game.dm_msg = await ctx.author.send(self.format_for_discord(game.revealed)) + game.dm_msg = await ctx.author.send(f"Here's your board!\n{self.format_for_discord(game.revealed)}") if game.activated_on_server: - await game.chat_msg.edit(content=self.format_for_discord(game.revealed)) + await game.chat_msg.edit(content=f"Here's there board!\n{self.format_for_discord(game.revealed)}") @commands.dm_only() @minesweeper_group.command(name="flag") -- cgit v1.2.3