Skip to main content

Rock Paper Scissors

This goes over how to implement a simple rock paper scissors game as a Slash Command.

Here's what the result will look like.

Game Logic

Let's write some code to define the rules of rock paper scissors.

I'm going to imagine I have a Selection class which represents a player's choice of rock, paper, or scissors. Defining constants like this allows your IDE to autocomplete them, so you can't accidentally misspell something later and get a confusing bug.

Selection.ROCK = Selection("rock")
Selection.PAPER = Selection("paper")
Selection.SCISSORS = Selection("scissors")

Now let's actually define that Selection class so the code compiles. This must go above the constant definitions we just wrote since they reference the class. The interpreter must know a class exists before it can be used.

This code simply saves the string we pass in when we create the object.

class Selection:
def __init__(self, name): = name

The other advantage of making a class for this is it allows us to attach behaviour to our data. For example, lets start by defining a method to check if our choice ties with another choice. According to the rules of rock paper scissors, this is very easy. We just check if the two selections are the same. Make sure you put this function goes inside the class definition you made above.

def ties(self, other):
return self == other

Now let's define a new method to check if our selection beats another one. If this returns true, we win! This method simply goes through the options for which selection we could be and checks if the other selection passed in is the one we would beat.

Notice that if self is none of those three options we would fall out the end of the method and return None. That can never happen because we only ever define three Selection objects that can be used.

def beats(self, other):
if self == Selection.ROCK:
return other == Selection.SCISSORS
elif self == Selection.PAPER:
return other == Selection.ROCK
elif self == Selection.SCISSORS:
return other == Selection.PAPER

Extension Challenge: Add a new Selection option to the game. For example, let someone choose "Gun" to beat any other choice.

Slash Command With Buttons

Now we want to allow the user to start a Rock Paper Scissors game from within discord. They'll do this by typing /game and then clicking a button to choose which option they select.

UI View

This class will extend discord.ui.View which allows us to pass it to our slash command to define its buttons.

Each method with the @discord.ui.button annotation defines a button that will show under the slash command response. When the button is clicked, the method will be called. The parameters of the annotation control how the button will look in the discord client. The display text will be emoji and then label. The color is decided by style (see options).

Each of our buttons will simply call the end_game method (which we haven't defined yet) with the corresponding Selection object. We also pass it the interaction object which will allow us to send a response back to the user in discord.

Notice how similar each button definition is, all we're changing is the display text and the Selection used.

class GameView(discord.ui.View):
@discord.ui.button(label="Rock", style=discord.ButtonStyle.primary, emoji="🪨")
async def choose_rock(self, button, interaction):
await end_game(interaction, Selection.ROCK)

@discord.ui.button(label="Paper", style=discord.ButtonStyle.primary, emoji="📄")
async def choose_paper(self, button, interaction):
await end_game(interaction, Selection.PAPER)

@discord.ui.button(label="Scissors", style=discord.ButtonStyle.primary, emoji="✂️")
async def choose_scissors(self, button, interaction):
await end_game(interaction, Selection.SCISSORS)


The @bot.slash_command annotation defines a new slash command. A user can invoke it by typing a / and then the name parameter. The description will be shown in the UI to let them know what the command does.

The method gets called when they invoke the command. We respond with some text and add our buttons underneath by passing a new object of the GameView as the view parameter.

@bot.slash_command(name="game", description="Play rock paper scissors")
async def start_game(ctx):
await ctx.respond("Hey. let's play a game!", view=GameView())

End Game Logic

This function will be called when the user presses one of our buttons.

async def end_game(interaction, player_choice):

First, randomly choose a Selection for the computer to play. You must import random at the top of your file

options = [Selection.ROCK, Selection.PAPER, Selection.SCISSORS]
computer_choice = options[random.randrange(len(options))]

Then, create a response string to let the user know the game state.

The .format call injects its arguments in the string in place of each {}.

response = "{} chose {} and the computer chose {}. \n".format(interaction.user,,

Use the Game Logic methods we defined earlier to add the result of the game to the response string.

response += "You win!"
elif player_choice.ties(computer_choice):
response += "You tie."
response += "You lose."

Finally, send that response as a message to discord. You can only call response.send_message once, that's why we combined all the information into one string.

await interaction.response.send_message(response)

Extension Challenge: Currently, you can keep playing new games by pressing the buttons on the bot's game message. Try removing the bot's initial message, or the buttons, when the game ends, so you have to explicitly start a new game with the slash command to play again.