nerd_dice 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/main.yml +67 -0
- data/.rubocop.yml +66 -0
- data/CHANGELOG.md +29 -1
- data/Gemfile.lock +41 -20
- data/README.md +179 -5
- data/bin/nerd_dice_benchmark +204 -0
- data/checksum/nerd_dice-0.2.0.gem.sha256 +1 -0
- data/checksum/nerd_dice-0.2.0.gem.sha512 +1 -0
- data/lib/nerd_dice/class_methods/configure.rb +50 -0
- data/lib/nerd_dice/class_methods/execute_die_roll.rb +47 -0
- data/lib/nerd_dice/class_methods/harvest_totals.rb +35 -0
- data/lib/nerd_dice/class_methods/refresh_seed.rb +83 -0
- data/lib/nerd_dice/class_methods/roll_ability_scores.rb +73 -0
- data/lib/nerd_dice/class_methods/roll_dice.rb +45 -0
- data/lib/nerd_dice/class_methods/total_ability_scores.rb +52 -0
- data/lib/nerd_dice/class_methods/total_dice.rb +44 -0
- data/lib/nerd_dice/class_methods.rb +30 -0
- data/lib/nerd_dice/configuration.rb +46 -2
- data/lib/nerd_dice/dice_set.rb +166 -0
- data/lib/nerd_dice/die.rb +51 -0
- data/lib/nerd_dice/sets_randomization_technique.rb +19 -0
- data/lib/nerd_dice/version.rb +1 -1
- data/lib/nerd_dice.rb +9 -159
- data/nerd_dice.gemspec +6 -4
- data.tar.gz.sig +0 -0
- metadata +64 -20
- metadata.gz.sig +3 -4
- data/.travis.yml +0 -6
@@ -0,0 +1,204 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "benchmark"
|
6
|
+
require "nerd_dice"
|
7
|
+
|
8
|
+
n = 50_000
|
9
|
+
|
10
|
+
RATIOS = {
|
11
|
+
total_dice_securerandom: 2.1,
|
12
|
+
total_dice_random_rand: 11.1,
|
13
|
+
total_dice_random_object: 13.0,
|
14
|
+
total_dice_randomized: 5.5,
|
15
|
+
total_dice_securerandom_3d6: 5.5,
|
16
|
+
total_dice_random_rand_3d6: 30.0,
|
17
|
+
total_dice_random_object_3d6: 25.5,
|
18
|
+
total_dice_randomized_3d6: 15.5,
|
19
|
+
roll_dice_securerandom: 4.0,
|
20
|
+
roll_dice_random_rand: 42.0,
|
21
|
+
roll_dice_random_object: 44.0,
|
22
|
+
roll_dice_randomized: 14.5,
|
23
|
+
roll_dice_securerandom_3d6: 13.0,
|
24
|
+
roll_dice_random_rand_3d6: 79.0,
|
25
|
+
roll_dice_random_object_3d6: 86.0,
|
26
|
+
roll_dice_randomized_3d6: 26.5,
|
27
|
+
roll_ability_scores_randomized: 26.5,
|
28
|
+
total_ability_scores_randomized: 26.5
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
def check_against_baseline!(baseline_value, test_value)
|
32
|
+
ratio = RATIOS[test_value.label.to_sym]
|
33
|
+
error_message = "Failed benchmark for #{test_value.label}. "
|
34
|
+
error_message += "Allowed ratio was #{ratio} actual ratio was #{test_value.real / baseline_value}"
|
35
|
+
raise NerdDice::Error, error_message if test_value.real > baseline_value * ratio
|
36
|
+
end
|
37
|
+
|
38
|
+
puts "Set baseline"
|
39
|
+
baselines = Benchmark.bmbm do |x|
|
40
|
+
# Random.rand()
|
41
|
+
x.report("Random.rand") do # standard rand()
|
42
|
+
n.times { Random.rand(1000) }
|
43
|
+
end
|
44
|
+
|
45
|
+
# SecureRandom.rand()
|
46
|
+
x.report("Sec.rand") do
|
47
|
+
n.times { SecureRandom.rand(1000) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
random_rand_baseline = baselines[0].real
|
52
|
+
securerandom_baseline = baselines[1].real
|
53
|
+
|
54
|
+
puts "Roll d1000s"
|
55
|
+
total_dice_d1000_results = Benchmark.bmbm do |x|
|
56
|
+
# NerdDice.total_dice securerandom
|
57
|
+
x.report("total_dice_securerandom") do
|
58
|
+
NerdDice.configuration.randomization_technique = :securerandom
|
59
|
+
n.times { NerdDice.total_dice(1000) }
|
60
|
+
end
|
61
|
+
|
62
|
+
x.report("total_dice_random_rand") do
|
63
|
+
NerdDice.configuration.randomization_technique = :random_rand
|
64
|
+
n.times { NerdDice.total_dice(1000) }
|
65
|
+
end
|
66
|
+
|
67
|
+
x.report("total_dice_random_object") do
|
68
|
+
NerdDice.configuration.randomization_technique = :random_object
|
69
|
+
n.times { NerdDice.total_dice(1000) }
|
70
|
+
end
|
71
|
+
|
72
|
+
x.report("total_dice_randomized") do
|
73
|
+
NerdDice.configuration.randomization_technique = :randomized
|
74
|
+
n.times { NerdDice.total_dice(1000) }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
total_dice_securerandom = total_dice_d1000_results[0]
|
79
|
+
check_against_baseline! securerandom_baseline, total_dice_securerandom
|
80
|
+
total_dice_random_rand = total_dice_d1000_results[1]
|
81
|
+
check_against_baseline! random_rand_baseline, total_dice_random_rand
|
82
|
+
total_dice_random_object = total_dice_d1000_results[2]
|
83
|
+
check_against_baseline! random_rand_baseline, total_dice_random_object
|
84
|
+
total_dice_randomized = total_dice_d1000_results[3]
|
85
|
+
check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), total_dice_randomized
|
86
|
+
|
87
|
+
roll_dice_d1000_results = Benchmark.bmbm do |x|
|
88
|
+
# NerdDice.roll_dice securerandom
|
89
|
+
x.report("roll_dice_securerandom") do
|
90
|
+
NerdDice.configuration.randomization_technique = :securerandom
|
91
|
+
n.times { NerdDice.roll_dice(1000) }
|
92
|
+
end
|
93
|
+
|
94
|
+
x.report("roll_dice_random_rand") do
|
95
|
+
NerdDice.configuration.randomization_technique = :random_rand
|
96
|
+
n.times { NerdDice.roll_dice(1000) }
|
97
|
+
end
|
98
|
+
|
99
|
+
x.report("roll_dice_random_object") do
|
100
|
+
NerdDice.configuration.randomization_technique = :random_object
|
101
|
+
n.times { NerdDice.roll_dice(1000) }
|
102
|
+
end
|
103
|
+
|
104
|
+
x.report("roll_dice_randomized") do
|
105
|
+
NerdDice.configuration.randomization_technique = :randomized
|
106
|
+
n.times { NerdDice.roll_dice(1000) }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
roll_dice_securerandom = roll_dice_d1000_results[0]
|
111
|
+
check_against_baseline! securerandom_baseline, roll_dice_securerandom
|
112
|
+
roll_dice_random_rand = roll_dice_d1000_results[1]
|
113
|
+
check_against_baseline! random_rand_baseline, roll_dice_random_rand
|
114
|
+
roll_dice_random_object = roll_dice_d1000_results[2]
|
115
|
+
check_against_baseline! random_rand_baseline, roll_dice_random_object
|
116
|
+
roll_dice_randomized = roll_dice_d1000_results[3]
|
117
|
+
check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), roll_dice_randomized
|
118
|
+
|
119
|
+
puts "Roll 3d6"
|
120
|
+
total_dice_3d6_results = Benchmark.bmbm do |x|
|
121
|
+
# NerdDice.total_dice securerandom
|
122
|
+
x.report("total_dice_securerandom_3d6") do
|
123
|
+
NerdDice.configuration.randomization_technique = :securerandom
|
124
|
+
n.times { NerdDice.total_dice(6, 3) }
|
125
|
+
end
|
126
|
+
|
127
|
+
x.report("total_dice_random_rand_3d6") do
|
128
|
+
NerdDice.configuration.randomization_technique = :random_rand
|
129
|
+
n.times { NerdDice.total_dice(6, 3) }
|
130
|
+
end
|
131
|
+
|
132
|
+
x.report("total_dice_random_object_3d6") do
|
133
|
+
NerdDice.configuration.randomization_technique = :random_object
|
134
|
+
n.times { NerdDice.total_dice(6, 3) }
|
135
|
+
end
|
136
|
+
|
137
|
+
x.report("total_dice_randomized_3d6") do
|
138
|
+
NerdDice.configuration.randomization_technique = :randomized
|
139
|
+
n.times { NerdDice.total_dice(6, 3) }
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
total_dice_3d6_securerandom = total_dice_3d6_results[0]
|
144
|
+
check_against_baseline! securerandom_baseline, total_dice_3d6_securerandom
|
145
|
+
total_dice_3d6_random_rand = total_dice_3d6_results[1]
|
146
|
+
check_against_baseline! random_rand_baseline, total_dice_3d6_random_rand
|
147
|
+
total_dice_3d6_random_object = total_dice_3d6_results[2]
|
148
|
+
check_against_baseline! random_rand_baseline, total_dice_3d6_random_object
|
149
|
+
total_dice_3d6_randomized = total_dice_3d6_results[3]
|
150
|
+
check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), total_dice_3d6_randomized
|
151
|
+
|
152
|
+
roll_dice_3d6_results = Benchmark.bmbm do |x|
|
153
|
+
# NerdDice.roll_dice securerandom
|
154
|
+
x.report("roll_dice_securerandom_3d6") do
|
155
|
+
NerdDice.configuration.randomization_technique = :securerandom
|
156
|
+
n.times { NerdDice.roll_dice(6, 3) }
|
157
|
+
end
|
158
|
+
|
159
|
+
x.report("roll_dice_random_rand_3d6") do
|
160
|
+
NerdDice.configuration.randomization_technique = :random_rand
|
161
|
+
n.times { NerdDice.roll_dice(6, 3) }
|
162
|
+
end
|
163
|
+
|
164
|
+
x.report("roll_dice_random_object_3d6") do
|
165
|
+
NerdDice.configuration.randomization_technique = :random_object
|
166
|
+
n.times { NerdDice.roll_dice(6, 3) }
|
167
|
+
end
|
168
|
+
|
169
|
+
x.report("roll_dice_randomized_3d6") do
|
170
|
+
NerdDice.configuration.randomization_technique = :randomized
|
171
|
+
n.times { NerdDice.roll_dice(6, 3) }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
roll_dice_3d6_securerandom = roll_dice_3d6_results[0]
|
176
|
+
check_against_baseline! securerandom_baseline, roll_dice_3d6_securerandom
|
177
|
+
roll_dice_3d6_random_rand = roll_dice_3d6_results[1]
|
178
|
+
check_against_baseline! random_rand_baseline, roll_dice_3d6_random_rand
|
179
|
+
roll_dice_3d6_random_object = roll_dice_3d6_results[2]
|
180
|
+
check_against_baseline! random_rand_baseline, roll_dice_3d6_random_object
|
181
|
+
roll_dice_3d6_randomized = roll_dice_3d6_results[3]
|
182
|
+
check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), roll_dice_3d6_randomized
|
183
|
+
|
184
|
+
puts "Setting n down to 5,000 due to more intensive methods"
|
185
|
+
n = 5_000
|
186
|
+
|
187
|
+
puts "Roll and total ability scores"
|
188
|
+
roll_ability_scores_results = Benchmark.bmbm do |x|
|
189
|
+
x.report("roll_ability_scores_randomized") do
|
190
|
+
NerdDice.configuration.randomization_technique = :randomized
|
191
|
+
n.times { NerdDice.roll_ability_scores }
|
192
|
+
end
|
193
|
+
|
194
|
+
x.report("total_ability_scores_randomized") do
|
195
|
+
NerdDice.configuration.randomization_technique = :randomized
|
196
|
+
n.times { NerdDice.total_ability_scores }
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
roll_ability_scores_randomized = roll_ability_scores_results[0]
|
201
|
+
check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), roll_ability_scores_randomized
|
202
|
+
total_ability_scores_randomized = roll_ability_scores_results[1]
|
203
|
+
check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)),
|
204
|
+
total_ability_scores_randomized
|
@@ -0,0 +1 @@
|
|
1
|
+
0a2d4765e24c21fecf99229b0cc4fad806ca256d2187c45c442b25771af1b9cc
|
@@ -0,0 +1 @@
|
|
1
|
+
e345190f870eabd2a4fd6993f1a1d70d008ef8e6464767ba5697a46f7c4d6912c78a18039cec06c18dd6f0ee9f425453c078f780d36ccf65043ec3f7fba790a2
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#############################
|
4
|
+
# Configuration class methods
|
5
|
+
#############################
|
6
|
+
# Usage:
|
7
|
+
# NerdDice.configure takes a block and yields the NerdDice::Configuration
|
8
|
+
# properties:
|
9
|
+
# If you wanted to configure several properties in a block:
|
10
|
+
# <tt>
|
11
|
+
# NerdDice.configure do |config|
|
12
|
+
# config.randomization_technique = :randomized
|
13
|
+
# config.die_background_color = "#FF0000"
|
14
|
+
# end
|
15
|
+
# </tt>
|
16
|
+
#
|
17
|
+
# NerdDice.configuration returns the NerdDice::Configuration object and lets you
|
18
|
+
# set properties on the NerdDice::Configuration object without using a block:
|
19
|
+
# <tt>
|
20
|
+
# config = NerdDice.configuration
|
21
|
+
# config.randomization_technique = :randomized
|
22
|
+
# config.die_background_color = "#FF0000"
|
23
|
+
# </tt>
|
24
|
+
module NerdDice
|
25
|
+
class << self
|
26
|
+
############################
|
27
|
+
# configure class method
|
28
|
+
############################
|
29
|
+
# Arguments: None
|
30
|
+
# Expects and yields to a block where configuration is specified.
|
31
|
+
# See README and NerdDice::Configuration class for config options
|
32
|
+
# Return (NerdDice::Configuration) the Configuration object tied to the
|
33
|
+
# @configuration class instance variable
|
34
|
+
def configure
|
35
|
+
yield configuration
|
36
|
+
configuration
|
37
|
+
end
|
38
|
+
|
39
|
+
############################
|
40
|
+
# configuration class method
|
41
|
+
############################
|
42
|
+
# Arguments: None
|
43
|
+
# Provides the lazy-loaded class instance variable @configuration
|
44
|
+
# Return (NerdDice::Configuration) the Configuration object tied to the
|
45
|
+
# @configuration class instance variable
|
46
|
+
def configuration
|
47
|
+
@configuration ||= Configuration.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
###############################
|
4
|
+
# execute_die_roll class method
|
5
|
+
###############################
|
6
|
+
# Usage:
|
7
|
+
# If you wanted to execute a single d4 die roll without a Die object, you would execute:
|
8
|
+
# <tt>NerdDice.execute_die_roll(4)</tt>
|
9
|
+
#
|
10
|
+
# If you wanted to execute a die roll with a different randomization technique
|
11
|
+
# than the one in NerdDice.configuration, you can supply an optional second argument
|
12
|
+
# <tt>NerdDice.execute_die_roll(4, :randomized)</tt>
|
13
|
+
module NerdDice
|
14
|
+
class << self
|
15
|
+
# Arguments:
|
16
|
+
# number_of_sides (Integer) => the number of sides of the die to roll
|
17
|
+
# using_generator (Symbol) => must be one of the symbols in
|
18
|
+
# RANDOMIZATION_TECHNIQUES or nil
|
19
|
+
#
|
20
|
+
# Return (Integer) => Value of the single die rolled
|
21
|
+
def execute_die_roll(number_of_sides, using_generator = nil)
|
22
|
+
@count_since_last_refresh ||= 0
|
23
|
+
gen = get_number_generator(using_generator)
|
24
|
+
result = gen.rand(number_of_sides) + 1
|
25
|
+
increment_and_evalutate_refresh_seed
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def get_number_generator(using_generator = nil)
|
32
|
+
using_generator ||= configuration.randomization_technique
|
33
|
+
case using_generator
|
34
|
+
when :securerandom then SecureRandom
|
35
|
+
when :random_rand then Random
|
36
|
+
when :random_object then @random_object ||= Random.new
|
37
|
+
when :randomized then random_generator
|
38
|
+
else raise ArgumentError, "Unrecognized generator. Must be one of #{RANDOMIZATION_TECHNIQUES.join(', ')}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def random_generator
|
43
|
+
gen = RANDOMIZATION_TECHNIQUES.reject { |el| el == :randomized }.sample
|
44
|
+
get_number_generator(gen)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
############################
|
4
|
+
# harvest_totals method
|
5
|
+
############################
|
6
|
+
# Usage:
|
7
|
+
# This method will take any collection of objects where each element responds to
|
8
|
+
# :total and return an array of the results of the total method.
|
9
|
+
#
|
10
|
+
# Example
|
11
|
+
# <tt>
|
12
|
+
# ability_score_array = NerdDice.roll_ability_scores
|
13
|
+
# => Array of 6 DiceSet objects
|
14
|
+
# totals_array = NerdDice.harvest_totals(totals_array)
|
15
|
+
# => [15, 14, 13, 12, 10, 8]
|
16
|
+
# # yes, it just happened to be the standard array by amazing coincidence
|
17
|
+
# </tt>
|
18
|
+
module NerdDice
|
19
|
+
class << self
|
20
|
+
# Arguments:
|
21
|
+
# collection (Enumerable) a collection where each element responds to total
|
22
|
+
#
|
23
|
+
# Return (Array) => Data type of each element will be whatever is returned by total method
|
24
|
+
def harvest_totals(collection)
|
25
|
+
collection.map(&:total)
|
26
|
+
rescue NoMethodError => e
|
27
|
+
specific_message =
|
28
|
+
case e.message
|
29
|
+
when /`total'/ then "Each element must respond to :total."
|
30
|
+
when /`map'/ then "Argument must respond to :map."
|
31
|
+
end
|
32
|
+
specific_message ? raise(ArgumentError, "You must provide a valid collection. #{specific_message}") : raise
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
############################
|
4
|
+
# refresh_seed! class method
|
5
|
+
############################
|
6
|
+
# Usage:
|
7
|
+
# NerdDice.refresh_seed! by default will refresh the seed for the generator
|
8
|
+
# configured in NerdDice.configuration. It can also be used with arguments
|
9
|
+
# to set a particular seed for use with deterministic testing. It sets
|
10
|
+
# the count_since_last_refresh to 0 whenever called.
|
11
|
+
#
|
12
|
+
# It cannot refresh or manipulate the seed for SecureRandom
|
13
|
+
#
|
14
|
+
# <tt>NerdDice.refresh_seed!</tt>
|
15
|
+
#
|
16
|
+
# With options
|
17
|
+
# <tt>
|
18
|
+
# previous_seed_data = NerdDice.refresh_seed!(
|
19
|
+
# randomization_technique: :randomized,
|
20
|
+
# random_rand_seed: 1337,
|
21
|
+
# random_object_seed: 24601
|
22
|
+
# )
|
23
|
+
# </tt>
|
24
|
+
module NerdDice
|
25
|
+
class << self
|
26
|
+
# Options: (none required)
|
27
|
+
# randomization_technique (Symbol) => must be one of the symbols in
|
28
|
+
# RANDOMIZATION_TECHNIQUES if specified
|
29
|
+
# random_rand_seed (Integer) => Seed to set for Random
|
30
|
+
# random_object_seed (Integer) => Seed to set for new Random object
|
31
|
+
# Return (Hash or nil) => Previous values of generator seeds that were refreshed
|
32
|
+
def refresh_seed!(**opts)
|
33
|
+
technique, random_rand_new_seed, random_object_new_seed = parse_refresh_options(opts)
|
34
|
+
@count_since_last_refresh = 0
|
35
|
+
return nil if technique == :securerandom
|
36
|
+
|
37
|
+
reset_appropriate_seeds!(technique, random_rand_new_seed, random_object_new_seed)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def parse_refresh_options(opts)
|
43
|
+
[
|
44
|
+
opts[:randomization_technique] || configuration.randomization_technique,
|
45
|
+
opts[:random_rand_seed],
|
46
|
+
opts[:random_object_seed]
|
47
|
+
]
|
48
|
+
end
|
49
|
+
|
50
|
+
# rubocop:disable Metrics/MethodLength
|
51
|
+
def reset_appropriate_seeds!(technique, random_rand_new_seed, random_object_new_seed)
|
52
|
+
return_hash = {}
|
53
|
+
case technique
|
54
|
+
when :random_rand
|
55
|
+
return_hash[:random_rand_prior_seed] = refresh_random_rand_seed!(random_rand_new_seed)
|
56
|
+
when :random_object
|
57
|
+
return_hash[:random_object_prior_seed] = refresh_random_object_seed!(random_object_new_seed)
|
58
|
+
when :randomized
|
59
|
+
return_hash[:random_rand_prior_seed] = refresh_random_rand_seed!(random_rand_new_seed)
|
60
|
+
return_hash[:random_object_prior_seed] = refresh_random_object_seed!(random_object_new_seed)
|
61
|
+
end
|
62
|
+
return_hash
|
63
|
+
end
|
64
|
+
# rubocop:enable Metrics/MethodLength
|
65
|
+
|
66
|
+
def refresh_random_rand_seed!(new_seed)
|
67
|
+
new_seed ? Random.srand(new_seed) : Random.srand
|
68
|
+
end
|
69
|
+
|
70
|
+
def refresh_random_object_seed!(new_seed)
|
71
|
+
old_seed = @random_object&.seed
|
72
|
+
@random_object = new_seed ? Random.new(new_seed) : Random.new
|
73
|
+
old_seed
|
74
|
+
end
|
75
|
+
|
76
|
+
def increment_and_evalutate_refresh_seed
|
77
|
+
@count_since_last_refresh += 1
|
78
|
+
return unless configuration.refresh_seed_interval
|
79
|
+
|
80
|
+
refresh_seed! if @count_since_last_refresh >= configuration.refresh_seed_interval
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
############################
|
4
|
+
# roll_ability_scores method
|
5
|
+
############################
|
6
|
+
# Usage:
|
7
|
+
# If you wanted to get an array of DiceSet objects with your ability scores and
|
8
|
+
# default configuration you would execute:
|
9
|
+
# <tt>ability_score_array = NerdDice.roll_ability_scores</tt>
|
10
|
+
#
|
11
|
+
# If you wanted to specify configuration for the current operation without
|
12
|
+
# modifying the NerdDice.configuration, you can supply options for both the
|
13
|
+
# ability_score configuration and the properties of the DiceSet objects returned.
|
14
|
+
# Properties are specified in the method comment
|
15
|
+
# <tt>
|
16
|
+
# ability_score_array = NerdDice.roll_ability_scores(
|
17
|
+
# ability_score_array_size: 7,
|
18
|
+
# ability_score_number_of_sides: 8,
|
19
|
+
# ability_score_dice_rolled: 5,
|
20
|
+
# ability_score_dice_kept: 4,
|
21
|
+
# randomization_technique: :randomized,
|
22
|
+
# foreground_color: "#FF0000",
|
23
|
+
# background_color: "#FFFFFF"
|
24
|
+
# )
|
25
|
+
# </tt>
|
26
|
+
module NerdDice
|
27
|
+
class << self
|
28
|
+
# Arguments:
|
29
|
+
# opts (options Hash, DEFAULT: {}) any options you wish to include
|
30
|
+
# ABILITY SCORE OPTIONS
|
31
|
+
# :ability_score_array_size DEFAULT NerdDice.configuration.ability_score_array_size
|
32
|
+
# :ability_score_number_of_sides DEFAULT NerdDice.configuration.ability_score_number_of_sides
|
33
|
+
# :ability_score_dice_rolled DEFAULT NerdDice.configuration.ability_score_dice_rolled
|
34
|
+
# :ability_score_dice_kept DEFAULT NerdDice.configuration.ability_score_dice_kept
|
35
|
+
#
|
36
|
+
# DICE SET OPTIONS
|
37
|
+
# :randomization_technique (Symbol) => must be one of the symbols in
|
38
|
+
# RANDOMIZATION_TECHNIQUES or nil
|
39
|
+
# :foreground_color (String) => should resolve to a valid CSS color (format flexible)
|
40
|
+
# :background_color (String) => should resolve to a valid CSS color (format flexible)
|
41
|
+
#
|
42
|
+
# Return (Array of NerdDice::DiceSet) => One NerdDice::DiceSet element for each ability score
|
43
|
+
# rubocop:disable Metrics/MethodLength
|
44
|
+
def roll_ability_scores(**opts)
|
45
|
+
dice_opts = opts.reject { |key, _value| key.to_s.match?(/\Aability_score_[a-z_]+\z/) }
|
46
|
+
ability_score_options = interpret_ability_score_options(opts)
|
47
|
+
ability_score_array = []
|
48
|
+
ability_score_options[:ability_score_array_size].times do
|
49
|
+
ability_score_array << roll_dice(
|
50
|
+
ability_score_options[:ability_score_number_of_sides],
|
51
|
+
ability_score_options[:ability_score_dice_rolled],
|
52
|
+
**dice_opts
|
53
|
+
).highest(
|
54
|
+
ability_score_options[:ability_score_dice_kept]
|
55
|
+
)
|
56
|
+
end
|
57
|
+
ability_score_array
|
58
|
+
end
|
59
|
+
# rubocop:enable Metrics/MethodLength
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def interpret_ability_score_options(opts)
|
64
|
+
return_hash = {}
|
65
|
+
ABILITY_SCORE_KEYS.each { |key| return_hash[key] = parse_ability_score_option(opts, key) }
|
66
|
+
return_hash
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_ability_score_option(option_hash, option_key)
|
70
|
+
option_hash[option_key] || configuration.send(option_key.to_s)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|