Skip to content

Instantly share code, notes, and snippets.

@crueber
Created October 29, 2012 04:37
Show Gist options
  • Save crueber/3971546 to your computer and use it in GitHub Desktop.
Save crueber/3971546 to your computer and use it in GitHub Desktop.
Ruby Expression based Die Roller - Accepts plus, minus, numeric dice and variable number of dice
# The MIT License
# Copyright (c) 2012 Christopher WJ Rueber
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or substantial
# portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
# TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
class Fixnum
def d(sides=6)
rolls = []
self.times { rolls.push(1 + rand(sides)) }
{ rolls: rolls, total: rolls.inject(:+) }
end
end
# Usage: 5.d(20)
# This module is maint to be used as a mix-in where needed
module Dice
DICE_REGEX = /([\+-]?)(\d*[d]?\d*|\d*)/
STANDARD_DIE_SIDES = [2, 3, 4, 6, 8, 10, 12, 20, 100, 1000]
def self.roll(formula)
raise "die formula must be a string" unless formula.class == String
formula = formula.gsub(' ', '').downcase
raise "formula may only contain numbers, d, +, and -." unless /[d\d\+-]*/.match(formula).to_s == formula
results = []
formula.scan(DICE_REGEX).each do |exp|
operator = exp[0]
dice = exp[1]
next if operator.blank? and dice.blank?
operator = operator.empty? ? '+' : operator
possible_dice = dice.split('d').delete_if {|x| x.blank? }
if possible_dice.size == 1
if possible_dice[0] == dice
results.push "#{operator}#{possible_dice[0]}".to_i
else
raise "must specify both a number of dice and the sides: 1d20"
end
elsif possible_dice.size == 2
number_of_dice = possible_dice[0].blank? ? 1 : possible_dice[0].to_i
die_sides = possible_dice[1].to_i
die_result = number_of_dice.d(die_sides)
die_result[:rolls].each {|roll| results.push "#{operator}#{roll}".to_i }
else
raise "this die expression is not possible"
end
end
{ individualResults: results, total: results.inject(:+) }
end
end
# examples:
# Dice.roll "1d20"
# Dice.roll "20d20"
# Dice.roll "6d6"
# Dice.roll "1d20+12"
# Dice.roll "1d20+3d10+2d6"
# Dice.roll "1d20-10"
# Dice.roll "1d20"
@crueber
Copy link
Author

crueber commented Oct 29, 2012

I went digging for a die roller ... Well, I was going to say today- But that's just not true. I've been idly looking around for an expression based die roller for a while that I could just use and plug in to my code. After being lazy for far too long, I just decided to write my own. It's not fancy, but your average table top RPGs use a pretty standard xDy, with additions or subtractions. As I alter my code to handle more situations, I'll keep it updated here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment