Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added guess the number game #1405

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions bot/exts/fun/guess_number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import random

from discord import Message
from discord.ext import commands

from bot.bot import Bot


class Difficulty(commands.Converter):
"""Class used to convert the `difficulty` parameter."""

EASY = ("e", "eas", "easy")
MEDIUM = ("m", "med", ",medium")
HARD = ("h", "hard")

async def convert(self, ctx: commands.Context, diff: str) -> str:
"""Converts the provided `difficulty` into the corresponding string."""
if diff.lower() in self.EASY:
return "easy"

if diff.lower() in self.MEDIUM:
return "medium"

if diff.lower() in self.HARD:
return "hard"

raise commands.BadArgument(f"{diff!r} is not a valid difficulty.")


class GuessNumber(commands.Cog):
"""Cog for the GuessNumber command."""

def __init__(self, bot: Bot):
self.bot = bot
self.active_games = {}

@commands.command(name="guessnumber", aliases=("gn", "numbergame"))
async def guess_number(self, ctx: commands.Context, difficulty: Difficulty = "medium") -> None:
"""Starts a new game of guessing the number with default difficulty set to medium."""
# Duplicate game check
if ctx.author.id in self.active_games:
await ctx.send("You already have an active game. Finish that one before starting a new one.")
return

if difficulty == "easy":
sarzz2 marked this conversation as resolved.
Show resolved Hide resolved
secret_number = random.randint(1, 50)
await ctx.send("I am thinking of a number between 1 and 50. Try to guess!")
elif difficulty == "medium":
secret_number = random.randint(1, 100)
await ctx.send("I am thinking of a number between 1 and 100. Try to guess!")
elif difficulty == "hard":
secret_number = random.randint(1, 200)
await ctx.send("I am thinking of a number between 1 and 200. Try to guess!")
else:
await ctx.send("Invalid difficulty mode.")
sarzz2 marked this conversation as resolved.
Show resolved Hide resolved

self.active_games[ctx.author.id] = secret_number

def check(msg: Message) -> bool:
return msg.author == ctx.author and msg.channel == ctx.channel

tries = 5
while tries > 0:
try:
user_guess = await self.bot.wait_for(
"message",
timeout=30.0,
check=check
)
except TimeoutError:
self.active_games.pop(ctx.author.id)
await ctx.send("Timeout!")
sarzz2 marked this conversation as resolved.
Show resolved Hide resolved
return

if not user_guess.content.isdigit():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isdigit would break on some instances as it takes unicode into account.

For example, if you call '²'.isdigit(), it'll return True.
Instead, wrap it in a try.except block where you try to convert it into an integer by calling int(content)

await ctx.send(f"**Invalid guess**, Please guess a number. Try again, You've {tries} left.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would look better in an Embed IMO.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure here whether we should just quit on invalid numbers, or otherwise set a counter for the number of invalid tries a user can have, otherwise this could keep on going forever. I think both are fine.

What i'm sure of though, is that we shouldn't let a backdoor that'll keep the command running forever.


elif int(user_guess.content) == self.active_games[ctx.author.id]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should make the conversion only once, before anything else, then keep on using the converted number if successfull. The conversion should be done like I indicated in my previous comment.

await ctx.channel.send(
f"Congratulations {ctx.author}! You guessed the correct number.")
self.active_games.pop(ctx.author.id)
return
# when 0 tries left for the user
else:
tries = tries - 1
if tries == 0:
await ctx.channel.send(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can go into the while loop's else block, which separates the end game code from the rest & makes it clearer & less indented.

f"Incorrect, You lost. I was thinking of number {self.active_games[ctx.author.id]}")
self.active_games.pop(ctx.author.id)
return

if int(user_guess.content) < self.active_games[ctx.author.id]:
low_high = "lower"
sarzz2 marked this conversation as resolved.
Show resolved Hide resolved
else:
low_high = "higher"
await ctx.channel.send(f"Incorrect! Number guessed is {low_high} than what I'm thinking. "
f"You have {tries} tries left.")


async def setup(bot: Bot) -> None:
"""Loads the cog."""
await bot.add_cog(GuessNumber(bot))