# Button game

> Build rock, paper, scissors with buttons. Only the player can click, and the game ends on its own if they walk away.

You will make `/rps`. The bot shows three buttons. The player picks one, the bot picks one, and the reply shows who won.

> You picked **rock**, I picked **scissors**. You win!

This guide uses a **View**. A View is a set of buttons that lives inside one run of a command. The buttons, the code that runs on a click, and the result all stay in the same command. You do not need an event for it.

## 1. Create the command

Open **Create → Slash Command** and switch to **Advanced** at the top of the form.

| Field | Value |
|---|---|
| Command Name | `rps` |
| Description | `Play rock, paper, scissors` |

Leave the **Content / Reply Message** box empty. The code writes the reply.

## 2. Add the buttons

Open **Pre-hook** and paste:

```python
class Game(View):
    def __init__(self, user_id):
        self.user_id = user_id   # only this member can click
        self.pick = None

    async def choose(self, interaction, pick):
        await defer(interaction, action="update")
        self.pick = pick
        self.stop()   # ends the game; the post-hook runs next

    @button(label="Rock", emoji="🪨", style="secondary", custom_id="rock")
    async def rock(self, interaction, component):
        await self.choose(interaction, "rock")

    @button(label="Paper", emoji="📄", style="secondary", custom_id="paper")
    async def paper(self, interaction, component):
        await self.choose(interaction, "paper")

    @button(label="Scissors", emoji="✂️", style="secondary", custom_id="scissors")
    async def scissors(self, interaction, component):
        await self.choose(interaction, "scissors")

game = Game(user_id=user.id)
game.interaction = interaction
set_view(game)
set_content(f"{user.mention}, pick one!")
```

What each part does:

| Part | Job |
|---|---|
| `class Game(View)` | Makes a new set of buttons. |
| `self.user_id = user_id` | Only the member who ran `/rps` can click. Other clicks are ignored. |
| `@button(...)` | Adds one button. The function under it runs on a click. |
| `defer(interaction, action="update")` | Tells Discord "click received" within its 3-second limit. |
| `self.stop()` | Ends the View. No code after it in that function runs. |
| `set_view(game)` | Puts the buttons on the reply and waits for clicks. |

> **Watch out:** Do not call `super().__init__()` in your View, and do not call `game.wait()` yourself. `set_view` does the waiting for you.

## 3. Show the result

Open **Post-hook** and paste:

```python
if game.pick is None:
    result = "Too slow! The game ended."
else:
    bot_pick = random(["rock", "paper", "scissors"])
    beats = {"rock": "scissors", "paper": "rock", "scissors": "paper"}
    if game.pick == bot_pick:
        outcome = "It's a tie!"
    elif beats[game.pick] == bot_pick:
        outcome = "You win!"
    else:
        outcome = "I win!"
    result = f"You picked **{game.pick}**, I picked **{bot_pick}**. {outcome}"

await respond_interaction(interaction, content=result)
```

The post-hook runs after the View ends. That happens after a click, or after **3 minutes with no click**. If the time runs out, `game.pick` is still `None`.

`respond_interaction` changes the reply text and removes the buttons.

## 4. Try it

Save, then run `/rps` in your server. Click a button.

Ask a friend to click your buttons. Nothing happens for them, because of `user_id`.

## Make it better

### Keep score

Save wins with a member variable. Add this to the post-hook, just before the `respond_interaction` line:

```python
if game.pick is not None and outcome == "You win!":
    wins = int(member_var("rps_wins", 0)) + 1
    update_member_var("rps_wins", wins)
    result = f"{result} You have {wins} wins."
```

Member variables are saved as text, so `int(...)` turns the value back into a number. See [Saving data](https://ccbot.app/docs/concepts/saving-data).

## Learn more

- [Buttons and menus](https://ccbot.app/docs/concepts/buttons-and-menus) explains Views and when to use an event instead.
- [Views](https://ccbot.app/docs/reference/views) lists every View tool, like `update_component` and `disable_all_components`.
- [Interactions](https://ccbot.app/docs/reference/interactions) covers `defer` and `respond_interaction`.
