Reputation: 17
I'm trying to implement a feature in my program that the user would be able to add or subtract a randomly generated number using a specific sided die. The foundation of my code is posted here:
import discord
import random
DND_1d20 = range(1, 21)
# Roll d20
if message.content == ";roll 1d20":
response = random.choice(DND_1d20)
response_str = "You rolled {0}".format(response)
if response_str == "You rolled 20":
await message.channel.send("**Critical Hit!**\n You rolled 20")
if response_str == "You rolled 1":
await message.channel.send("**Critical Fail!**\n You rolled 1")
I would like the user to be able to specify a dice roll ";1d20" BUT also have the ability to add ";1d20+(x)" or subtract ";1d20-(x)" any number (x) from the generated dice roll. The logic would look something like this
-user ";1d20+2" Lets say the random number generated would be 6. Since the user wants to add 2 to the random number we generated, the outcome would be 8.
-bot "You rolled 8"
# Roll d20
if message.content == ";roll 1d20":
response = random.choice(DND_1d20)
response_str = "You rolled {0}".format(response)
if response_str == "You rolled 20":
await message.channel.send("**Critical Hit!**\n You rolled 20")
if response_str == "You rolled 1":
await message.channel.send("**Critical Fail!**\n You rolled 1")
else:
if message.content == "-":
How would I go about doing this? I am really confused on where to start. I dont think the code above is right, because the message would have to exactly be a "-". Also, how would I incorporate the value (x), since it could be a vast array of numbers, or the +/- signs from the user input?
Any help is appreciated!
Upvotes: 0
Views: 538
Reputation: 61032
Here's a more advanced solution using a library called lark
to define a grammar for these dice expressions (cribbed from this question), parse those expressions into syntax trees, then evaluate those trees. Make a file named dice_grammar.py
with this string:
grammar="""
start: _expr
_expr: add
| subtract
| roll
| NUMBER
add: _expr "+" _expr
subtract: _expr "-" _expr
roll: [NUMBER] ("d"|"D") (NUMBER|PERCENT)
NUMBER: ("0".."9")+
PERCENT: "%"
%ignore " "
"""
If you're not familiar with grammars like this, don't panic. All this is showing is that we can roll dice, add, and subtract. We can then have a dice_transformer.py
to consume the trees the parser will produce:
from lark import Transformer, v_args
from random import randint
class DiceTransformer(Transformer):
PERCENT = lambda self, percent: 100
NUMBER = int
def __init__(self):
super().__init__(visit_tokens=True)
@v_args(inline=True)
def start(self, expr):
return expr
@v_args(inline=True)
def add(self, left, right):
return left + right
@v_args(inline=True)
def subtract(self, left, right):
return left - right
@v_args(inline=True)
def roll(self, qty, size):
qty = qty or 1
return sum(randint(1, size) for _ in range(qty))
and a dice_bot.py
that uses these to evaluate dice expressions from the user:
from discord.ext import commands
from lark import Lark
from lark.exceptions import LarkError
from dice_grammar import grammar
from dice_transformer import DiceTransformer
bot = commands.Bot(";")
parser = Lark(grammar, maybe_placeholders=True)
transformer = DiceTransformer()
@bot.command()
async def roll(ctx, *, expression):
try:
tree = parser.parse(expression)
except LarkError:
await ctx.send("Bad Expression")
return
print(tree.pretty()) # Log the roll
result = transformer.transform(tree)
await ctx.send(f"You rolled: {result}")
bot.run("token")
This allows us to ask for the computation of more complicated rolls like
;roll 2d6 +7 + d% - 3d4
On the advice of Erez in the comments, I changed my answer to use lark.Transformer
. You should be able to see my original code in the edit history of this answer.
Upvotes: 1