Skip to content

Instantly share code, notes, and snippets.

@jeremyf
Last active September 11, 2015 23:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremyf/2cd28ef0467ed9402535 to your computer and use it in GitHub Desktop.
Save jeremyf/2cd28ef0467ed9402535 to your computer and use it in GitHub Desktop.
# A simulation for various dice rolling mechanisms
# For more information on how it was used. http://takeonrules.com/2015/09/10/running-a-fifth-edition-character-funnel/
#
# $ ruby random_stat_methods.rb
#
# I use `ruby random_stat_methods.rb | pbcopy` then paste that into a Google Spreadsheet to generate a chart.
class Simulation
def initialize
@scenarios = {}
end
def bonus_for(*values)
((values.inject(0) {|v,m| m += v} - 10) / 2).round
end
private :bonus_for
def roll
rand(6) + 1
end
private :roll
def label_for(scenario:)
@scenarios.fetch(scenario, scenario.to_s)
end
WORST_BONUS_POSSIBLE = -5 * 6
def scenario_1
@scenarios[__callee__] = "12 columns of 3d6 straight down"
highest_bonus = WORST_BONUS_POSSIBLE
(1..12).each do |iteration|
current_bonus = 0
(1..6).each do |stat|
current_bonus += bonus_for(roll,roll,roll)
end
highest_bonus = current_bonus if current_bonus > highest_bonus
end
highest_bonus
end
def _scenario_2
@scenarios[__callee__] = "4d6 straight down"
current_bonus = 0
(1..6).each do |stat|
rolls = [roll,roll,roll, roll].sort.reverse[0..2]
current_bonus += bonus_for(*rolls)
end
current_bonus
end
def scenario_3
@scenarios[__callee__] = "4d6 straight down, optionally replace one with an 8"
bonuses = []
(1..6).each do |stat|
rolls = [roll,roll,roll, roll].sort.reverse[0..2]
bonuses << bonus_for(*rolls)
end
bonuses << -1
bonuses.sort.reverse[0..5].inject(0) { |v,m| m += v }
end
def _scenario_4
@scenarios[__callee__] = "4d6 straight down, optionally replace one with a 10"
bonuses = []
(1..6).each do |stat|
rolls = [roll,roll,roll, roll].sort.reverse[0..2]
bonuses << bonus_for(*rolls)
end
bonuses << 0
bonuses.sort.reverse[0..5].inject(0) { |v,m| m += v }
end
def _scenario_5
@scenarios[__callee__] = "4d6 straight down, optionally replace one with a 7"
bonuses = []
(1..6).each do |stat|
rolls = [roll,roll,roll, roll].sort.reverse[0..2]
bonuses << bonus_for(*rolls)
end
bonuses << -2
bonuses.sort.reverse[0..5].inject(0) { |v,m| m += v }
end
end
SIMULATIONS = (ENV['SIMULATIONS'] || 10_000).to_i
results = {}
simulation = Simulation.new
scenarios = simulation.methods.grep(/^scenario/)
scenarios.each_with_object(results) do |scenario_name, object|
object[scenario_name] = {}
(1..SIMULATIONS).each do |i|
bonus = simulation.public_send(scenario_name)
object[scenario_name][bonus] ||= 0
object[scenario_name][bonus] += 1
end
object
end
min = 24
max = -24
results.values.each do |value|
sorted = value.keys.sort
max = sorted[-1] if sorted[-1] > max
min = sorted[0] if sorted[0] < min
end
print "Modifier\t"
print scenarios.map { |scenario| simulation.label_for(scenario: scenario) }.join("\t")
print "\n"
(min..max).each do |i|
print "#{i}"
scenarios.each do |scenario_name|
print "\t#{results[scenario_name][i] || 0}"
end
print "\n"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment