1

I have a game that is basically two commands, test and test2.
test makes you generate a word that you have to guess in test2, and if you miss the word 6 times you lose.

from collections import defaultdict

word = ""
guessesLeft = 6
blanks = []
guessedLetters = []
lettersFound = 0

bot = commands.Bot(command_prefix=("!"))

bot.gamex = defaultdict(bool)

@bot.command()
async def test(ctx, *, message):

    await ctx.message.delete()

    global word, guessesLeft, blanks, lettersFound, guessedLetters
    if not bot.gamex[ctx.guild.id]:

        word = message.lower()

        blanks = []
        guessedLetters = []
        lettersFound = 0
        guessesLeft = 6

        bot.gamex[ctx.guild.id] = True

        for i in range(0, len(word)):
            blanks .append("-")
        print(i)

        await ctx.send(embed=discord.Embed(title="hangman:  " + " ".join(blanks)))

@bot.command()
async def test2(ctx, *, guess):

    global word, guessesLeft, blanks, lettersFound, guessedLetters

    if bot.gamex[ctx.guild.id]:
        if str.isalpha(guess) and len(guess) is 1 and str.lower(guess) not in guessedLetters:
            if str.lower(guess) in word:
                await ctx.send(guess + " is in the word.  Good job!")
                for i in range(0, len(word)):
                    if word[i] == str.lower(guess):
                        blanks[i] = str.lower(guess)
                        lettersFound += 1

            else:
                await ctx.send(guess + " is NOT in the word.")
                guessesLeft -= 1

            guessedLetters.append(str.lower(guess))
            await ctx.send(" ".join(blanks))
            await ctx.send("Guessed letters: " + " ".join(guessedLetters))
            await ctx.send("Guesses left: " + str(guessesLeft))

            if guessesLeft == 0:
                await ctx.send("No guesses left.  You lose!")
                bot.gamex[ctx.guild.id] = False
            if lettersFound == len(word)-1:
                await ctx.send("You've won!  The word was: " + word)
                bot.gamex[ctx.guild.id] = False

It's a hangman game, but the game variables are mixing on every server the bot is on, if I guess a word on one server, it appears on another server, I want each server to be individual and have commands individual.
Only those in the global are mixing.
What would the command look like so that the variables don't get mixed up between the servers?

Lucas Tesch
  • 137
  • 1
  • 10

1 Answers1

2

Make a class that represents the state of the game, and replace your gamex mapping with a mapping of guild ids to games:

games = {}

class Game:
    def __init__(self, word, guesses=6):
        self.word = word.lower()
        self.blanks = ["-"]*len(word)
        self.guessedLetters = []
        self.lettersFound = 0
        self.guessesLeft = guesses

Then in your commands, you get the Game storing the state for that guild.

@bot.command()
async def create_game(ctx, *, word):
    await ctx.message.delete()
    if ctx.guild.id in games:
        await ctx.send("Game already in progress")
    else:
        games[ctx.guild.id] = Game(word)
    await ctx.send(embed=discord.Embed(title="hangman:  " + " ".join(games[ctx.guild.id].blanks)))

And you would call del games[ctx.guild.id] to remove entries when the game is complete.

A well-designed Game object would mean that the logic about how the game is played would be pulled out of your commands and into the Game object. Ideally, you would be able to take the Game class from this code and use it to implement the same game in a browser or other interface with minimal changes.

Patrick Haugh
  • 59,226
  • 13
  • 88
  • 96
  • games[ctx.guild.id].blanks dont show the words with "-", dont get nothing. I need to use @commands.command() instead of @bot.command(), but how can I will call a variable guessedLetters in another @commands.command() ? – Lucas Tesch Sep 13 '19 at 02:05
  • Do you see an error? If not, then `games[ctx.guild.id].blanks` refers to some value. What is it? The `games` dictionary needs to exist outside of the scope of the commands, so that it shared between the commands. If you're using cogs you can make it an attribute of the cog. – Patrick Haugh Sep 13 '19 at 02:54