aboutsummaryrefslogtreecommitdiffstats
path: root/bot/seasons/evergreen/minesweeper.py
diff options
context:
space:
mode:
authorGravatar vivax3794 <[email protected]>2019-08-10 15:06:45 +0200
committerGravatar vivax3794 <[email protected]>2019-08-10 15:06:45 +0200
commit1cb1ec544a918d585bc2160c5a822906d6c0c1d7 (patch)
tree56cdf8c92784488ccf9535acb85aac77d3595ee9 /bot/seasons/evergreen/minesweeper.py
parentfixed a small bug (diff)
changed thing after requests.
Diffstat (limited to 'bot/seasons/evergreen/minesweeper.py')
-rw-r--r--bot/seasons/evergreen/minesweeper.py127
1 files changed, 64 insertions, 63 deletions
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 `<letter><number>")
- 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 `<letter><number>`")
+ 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: