mirror of
https://github.com/neoarz/Syntrel.git
synced 2025-12-25 11:40:12 +01:00
feat: create minesweeper game with v2 components
Introduces a new button-based Minesweeper mini-game in cogs/fun/minesweeper.py and registers it in the help command. Updates bot status messages in bot.py. Improves hackban embed formatting and adds author info in cogs/moderation/hackban.py.
This commit is contained in:
203
cogs/fun/minesweeper.py
Normal file
203
cogs/fun/minesweeper.py
Normal file
@@ -0,0 +1,203 @@
|
||||
import random
|
||||
from itertools import repeat
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from discord.ext.commands import Context
|
||||
|
||||
|
||||
class RowButton(discord.ui.Button):
|
||||
def __init__(self, ctx, label, custom_id, bombs, board):
|
||||
super().__init__(label=label, style=discord.ButtonStyle.grey, custom_id=custom_id)
|
||||
self.ctx = ctx
|
||||
self.bombs = bombs
|
||||
self.board = board
|
||||
|
||||
async def callback(self, interaction):
|
||||
assert self.view is not None
|
||||
view: MsView = self.view
|
||||
await interaction.response.defer()
|
||||
if interaction.user.id != self.ctx.author.id:
|
||||
return await interaction.followup.send(
|
||||
"You cannot interact with these buttons.", ephemeral=True
|
||||
)
|
||||
|
||||
b_id = self.custom_id
|
||||
if int(b_id[5:]) in view.moves:
|
||||
return await interaction.followup.send("That part is already taken.", ephemeral=True)
|
||||
if int(b_id[5:]) in self.bombs:
|
||||
await view.RevealBombs(b_id, view.board)
|
||||
else:
|
||||
count = []
|
||||
rawpos = int(b_id[5:])
|
||||
pos = view.GetBoardPos(rawpos)
|
||||
|
||||
def checkpos(count, rawpos, pos):
|
||||
pos = view.GetBoardPos(rawpos)
|
||||
if not rawpos - 1 in self.bombs or pos == 0:
|
||||
count.append(rawpos - 1)
|
||||
if not rawpos + 1 in self.bombs or pos == 4:
|
||||
count.append(rawpos + 1)
|
||||
if not rawpos - 6 in self.bombs or pos == 0:
|
||||
count.append(rawpos - 6)
|
||||
if not rawpos - 4 in self.bombs or pos == 4:
|
||||
count.append(rawpos - 4)
|
||||
if not rawpos + 6 in self.bombs or pos == 4:
|
||||
count.append(rawpos + 6)
|
||||
if not rawpos + 4 in self.bombs or pos == 0:
|
||||
count.append(rawpos + 4)
|
||||
if not rawpos - 5 in self.bombs:
|
||||
count.append(rawpos - 5)
|
||||
if not rawpos + 5 in self.bombs:
|
||||
count.append(rawpos + 5)
|
||||
return count
|
||||
|
||||
count = checkpos(count, rawpos, pos)
|
||||
number = 8-len(count)
|
||||
self.label = str(number) if number > 0 else "0"
|
||||
self.style = discord.ButtonStyle.green
|
||||
pos = int(b_id[5:])
|
||||
view.board[view.GetBoardRow(pos)][
|
||||
view.GetBoardPos(pos)
|
||||
] = str(number) if number > 0 else "0"
|
||||
view.moves.append(pos)
|
||||
if len(view.moves) + len(self.bombs) == 25:
|
||||
await interaction.edit_original_response(view=view)
|
||||
await view.EndGame()
|
||||
|
||||
await interaction.edit_original_response(view=view)
|
||||
|
||||
|
||||
class MsView(discord.ui.View):
|
||||
def __init__(self, ctx, options, bombs, board):
|
||||
super().__init__()
|
||||
for i, op in enumerate(options):
|
||||
self.add_item(RowButton(ctx, op, f"block{i}", bombs, board))
|
||||
self.board = board
|
||||
self.bombs = bombs
|
||||
self.moves = []
|
||||
self.ctx = ctx
|
||||
self.message = None
|
||||
|
||||
async def EndGame(self):
|
||||
embed = discord.Embed(
|
||||
title="Minesweeper",
|
||||
description="Game Ended. You won!",
|
||||
color=0x00FF00
|
||||
)
|
||||
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
|
||||
await self.message.edit(embed=embed, view=self)
|
||||
for button in self.children:
|
||||
button.disabled = True
|
||||
pos = int(button.custom_id[5:])
|
||||
if pos in self.bombs:
|
||||
button.label = "💣"
|
||||
button.style = discord.ButtonStyle.red
|
||||
self.board[self.GetBoardRow(pos)][self.GetBoardPos(pos)] = "💣"
|
||||
|
||||
def GetBoardRow(self, pos):
|
||||
if pos in [0, 1, 2, 3, 4]:
|
||||
return 0
|
||||
if pos in [5, 6, 7, 8, 9]:
|
||||
return 1
|
||||
if pos in [10, 11, 12, 13, 14]:
|
||||
return 2
|
||||
if pos in [15, 16, 17, 18, 19]:
|
||||
return 3
|
||||
if pos in [20, 21, 22, 23, 24]:
|
||||
return 4
|
||||
return False
|
||||
|
||||
def GetBoardPos(self, pos):
|
||||
if pos in [0, 1, 2, 3, 4]:
|
||||
return pos
|
||||
if pos in [5, 6, 7, 8, 9]:
|
||||
for i, num in enumerate(range(5, 10)):
|
||||
if pos == num:
|
||||
return i
|
||||
if pos in [10, 11, 12, 13, 14]:
|
||||
for i, num in enumerate(range(10, 15)):
|
||||
if pos == num:
|
||||
return i
|
||||
if pos in [15, 16, 17, 18, 19]:
|
||||
for i, num in enumerate(range(15, 20)):
|
||||
if pos == num:
|
||||
return i
|
||||
if pos in [20, 21, 22, 23, 24]:
|
||||
for i, num in enumerate(range(20, 25)):
|
||||
if pos == num:
|
||||
return i
|
||||
return False
|
||||
|
||||
async def RevealBombs(self, b_id, board):
|
||||
bombemo = "💣"
|
||||
embed = discord.Embed(
|
||||
title="Minesweeper",
|
||||
description="💥 BOOM! You hit a bomb! Game Over!",
|
||||
color=0xE02B2B
|
||||
)
|
||||
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
|
||||
await self.message.edit(embed=embed, view=self)
|
||||
|
||||
for button in self.children:
|
||||
button.disabled = True
|
||||
if button.custom_id == b_id:
|
||||
button.label = bombemo
|
||||
button.style = discord.ButtonStyle.red
|
||||
pos = int(b_id[5:])
|
||||
self.board[self.GetBoardRow(pos)][self.GetBoardPos(pos)] = bombemo
|
||||
|
||||
for button in self.children:
|
||||
if int(button.custom_id[5:]) in self.bombs:
|
||||
button.label = bombemo
|
||||
button.style = discord.ButtonStyle.red
|
||||
pos = int(button.custom_id[5:])
|
||||
self.board[self.GetBoardRow(pos)][
|
||||
self.GetBoardPos(pos)
|
||||
] = bombemo
|
||||
|
||||
|
||||
class Minesweeper(commands.Cog, name="minesweeper"):
|
||||
def __init__(self, bot) -> None:
|
||||
self.bot = bot
|
||||
|
||||
@commands.hybrid_command(
|
||||
name="minesweeper",
|
||||
description="Play a buttoned minesweeper mini-game."
|
||||
)
|
||||
async def minesweeper(self, context: Context) -> None:
|
||||
"""
|
||||
Play a buttoned minesweeper mini-game.
|
||||
:param context: The hybrid command context.
|
||||
"""
|
||||
board = [["឵឵ "] * 5 for _ in range(5)] # Unicode block character, usually doesnt show up in Discord or github, search up invisible character on google
|
||||
bombs = 0
|
||||
bombpositions = []
|
||||
for x in repeat(None, random.randint(4, 11)):
|
||||
random_index = random.randint(0, 24)
|
||||
if random_index not in bombpositions and random_index not in [
|
||||
0, 4, 20, 24
|
||||
]:
|
||||
bombpositions.append(random_index)
|
||||
bombs += 1
|
||||
|
||||
def ExtractBlocks():
|
||||
new_b = []
|
||||
for x in board:
|
||||
for y in x:
|
||||
new_b.append(y)
|
||||
return new_b
|
||||
|
||||
embed = discord.Embed(
|
||||
title="Minesweeper",
|
||||
description=f"💣 Total Bombs: `{len(bombpositions)}`\n\nClick the buttons to reveal the grid. Avoid the bombs!",
|
||||
color=0x7289DA
|
||||
)
|
||||
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
|
||||
|
||||
view = MsView(context, ExtractBlocks(), bombpositions, board)
|
||||
message = await context.send(embed=embed, view=view)
|
||||
view.message = message
|
||||
|
||||
|
||||
async def setup(bot) -> None:
|
||||
await bot.add_cog(Minesweeper(bot))
|
||||
Reference in New Issue
Block a user