tabletop-companion/app/services/dice_roller.rb

73 lines
1.6 KiB
Ruby
Raw Normal View History

2024-06-11 13:55:39 +00:00
# frozen_string_literal: true
class DiceRoller
2024-06-20 07:26:33 +00:00
attr_reader :dice
attr_reader :result
2024-06-11 13:55:39 +00:00
def initialize(roll_command, stat: nil)
@roll_command = roll_command
@stat = stat&.value
2024-06-20 07:26:33 +00:00
@dice = []
2024-06-11 13:55:39 +00:00
end
def roll
result = 0
operator = nil
roll_command_parts.each do |part|
case part
when /\A\d*d\d+\z/
operator.nil? ? (result += roll_dice(part)) : (result = result.send(operator, roll_dice(part)))
when /\A\d+\z/
operator.nil? ? (result += part.to_i) : (result = result.send(operator, part.to_i))
when "self"
operator.nil? ? (result += @stat) : (result = result.send(operator, @stat))
when /\A[+\-*\/]\z/
operator = part
end
end
result
end
def valid?
return if @roll_command.blank?
# No repeated math operators
return false if @roll_command.match?(/[+\-*\/]{2,}/)
# No leading or trailing math operators
return false if @roll_command.match?(/\A[+\-*\/]/) || @roll_command.match?(/[+\-*\/]\z/)
@roll_command.match?(
/
\A(
(\d*d\d*) |
([+\-*\/]) |
(\d+) |
(self)
)*\z/xi,
)
end
private
def roll_command_parts
@roll_command.scan(/([+\-*\/])|(\d*d\d+)|(\d+)|(self)/xi)
.flatten
.compact_blank
end
def roll_dice(command)
parts = command.downcase.split("d").compact_blank
die_type = parts.last
dice_number = parts.length > 1 ? parts.first.to_i : 1
result = 0
dice_number.times do
2024-06-20 07:26:33 +00:00
roll = rand(1..die_type.to_i)
result += roll
dice << [ die_type, result ]
2024-06-11 13:55:39 +00:00
end
result
end
end