[Discord Bot] 02. Dice Rolling Bot
Create a Discord chat bot for rolling dice using Python3
Do you know about TTRPG? One of the most well-known is probably Dungeons & Dragons (D&D).
After watching hololive EN play, I thought, “Let’s create a dice rolling bot and give it a try.”
Requirements Discussion
- Ability to roll multiple dice
- Customizable number of sides on the dice
- Success determination calculation
Command format
!roll 5D10>8
This means: roll 5 ten-sided dice, and success is determined if the result is greater than or equal to 8.
Code
# Import the Discord.py library
import discord
# Import the random library
import random
# Obtain the Discord client object for operations
client = discord.Client()
# Invoke the event library
@client.event
# When the bot is ready, display a message in the terminal
async def on_ready():
print(f'Logged in as {client.user}')
# Invoke the event library
@client.event
# When a message is received
async def on_message(message):
# Exclude messages sent by the bot itself to avoid an infinite loop
if message.author == client.user:
return
# Default error message
error = []
# Process input text
content = message.content.replace(' ', '').lower()
# If the message starts with "!roll"
if message.content.startswith('!roll'):
content = content.replace('!roll', '')
# Dice quantity calculation
dice_count = content.split('d')[0]
try:
dice_count = int(dice_count)
except ValueError:
error.append('The number of dice rolled must be an integer!')
# Dice type determination
content = content.split('d')[1]
dice_type = content.split('>')[0]
try:
dice_type = int(dice_type)
except ValueError:
error.append('Dice type must be an integer!')
# Success determination
if '>' in content:
success = content.split('>')[1]
try:
success = int(success)
except ValueError:
error.append('Success condition must be an integer!')
else:
success = 0
if len(error) == 0:
success_count = 0
result_msg = ''
# Roll the dice
results = [random.randint(1, dice_type) for _ in range(dice_count)]
for result in results:
if success > 0 and result >= success:
success_count += 1
result_msg += f'`{result}`, '
await message.channel.send(result_msg)
if success > 0:
await message.channel.send(f'Success: `{success_count}`')
else:
await message.channel.send(error)
# TOKEN obtained on the "BOT" page in Discord Developer
client.run('')
Code Explanation
Basic usage of discord.py
has been covered before, so we won’t repeat it here. We’ll focus on explaining the logic.
Input Message Detection
We use
message.content.startswith('!roll')
to only respond to messages starting with ‘!roll’. To ensure case insensitivity and handle spaces, we use
message.content.replace(' ', '').lower()
to remove spaces and convert the message to lowercase.
Now, the program processes the message as if the user had input ‘!roll5d10’.
Dice Quantity Calculation
The logic is similar to before. We extract the number of dice by splitting the content around ’d’ and taking the first value.
We use
content.replace('!roll', '')
to remove ‘!roll’ as it’s only a trigger for the bot and doesn’t affect the dice rolling result.
We use
content.split('d')[0]
to get the number of dice. We then try to convert it to an integer, catching a ValueError if it’s not a valid number.
Dice Type Determination
Similar to quantity calculation, but this time we extract the logic between ’d’ and ‘>’ to determine the type of dice.
Again, we try to convert it to an integer and catch a ValueError if needed.
Success Determination
We check if ‘>’ is present in the content. If it is, we extract the success condition after ‘>’.
We try to convert it to an integer, catching a ValueError if needed.
Rolling the Dice
If there are no errors, we roll the dice using
results = [random.randint(1, dice_type) for _ in range(dice_count)]
We iterate through the results, formatting them for Discord output, and count successful rolls if a success condition is specified.
Finally, we send the result and success count to Discord. If there are errors, we send the error message instead.
Improvement Directions
While the bot’s requirements are met, there are areas for optimization.
Function Splitting
The logic is currently written together.
It would be better to split it into separate functions for easier testing and future adjustments.
Input Logic Optimization
The input logic is too simple, and unexpected user inputs might not be handled correctly.
For example, ‘!roll6D10d5’ will currently be processed the same as ‘!roll6D10’.
Proper handling of such cases should be considered.