nerd_dice 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/main.yml +3 -3
- data/.rubocop.yml +181 -14
- data/CHANGELOG.md +66 -4
- data/Gemfile +2 -2
- data/Gemfile.lock +47 -51
- data/README.md +178 -6
- data/bin/generate_checksums +2 -2
- data/bin/nerd_dice_benchmark +112 -16
- data/certs/msducheminjr.pem +24 -25
- 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 +5 -6
- data.tar.gz.sig +0 -0
- metadata +57 -47
- metadata.gz.sig +0 -0
data/README.md
CHANGED
@@ -4,6 +4,9 @@
|
|
4
4
|
# NerdDice
|
5
5
|
Nerd dice allows you to roll polyhedral dice and add bonuses as you would in a tabletop roleplaying game. You can choose to roll multiple dice and keep a specified number of dice such as rolling 4d6 and dropping the lowest for ability scores or rolling with advantage and disadvantage if those mechanics exist in your game.
|
6
6
|
|
7
|
+
## Educational Videos By Stateless Code
|
8
|
+
The end-to-end process of developing this gem has been captured as [instructional videos](https://www.youtube.com/playlist?list=PL9kkbu1kLUeOnUtMpAnJOCtHdThx1Efkt). The videos are in a one-take style so that the mistakes along the way have troubleshooting and the concepts used to develop the gem are explained as they are covered.
|
9
|
+
|
7
10
|
## Installation
|
8
11
|
|
9
12
|
Add this line to your application's Gemfile:
|
@@ -28,7 +31,17 @@ You can customize the behavior of NerdDice via a configuration block as below or
|
|
28
31
|
NerdDice.configure do | config|
|
29
32
|
|
30
33
|
# number of ability scores to place in an ability score array
|
31
|
-
config.ability_score_array_size = 6
|
34
|
+
config.ability_score_array_size = 6 # must duck-type to positive Integer
|
35
|
+
|
36
|
+
# number of sides for each ability score Die
|
37
|
+
config.ability_score_number_of_sides = 6 # must duck-type to positive Integer
|
38
|
+
|
39
|
+
# total number of dice rolled for each ability score
|
40
|
+
config.ability_score_dice_rolled = 4 # must duck-type to positive Integer
|
41
|
+
|
42
|
+
# highest(n) dice from the total number of dice rolled that are included in the ability score total
|
43
|
+
# CANNOT EXCEED ability_score_dice_rolled see Note below
|
44
|
+
config.ability_score_dice_kept = 3 # must duck-type to positive Integer
|
32
45
|
|
33
46
|
# randomization technique options are:
|
34
47
|
# :securerandom => Uses SecureRandom.rand(). Good entropy, medium speed.
|
@@ -43,26 +56,167 @@ NerdDice.configure do | config|
|
|
43
56
|
# 1 very slow and heavy pressure on processor and memory but very high entropy
|
44
57
|
# 1000 would refresh the object every 1000 times you call rand()
|
45
58
|
config.refresh_seed_interval = nil # don't refresh the seed
|
59
|
+
# Background and foreground die colors are string values. By default these correspond to the constants in the class
|
60
|
+
# Defaults: DEFAULT_BACKGROUND_COLOR = "#0000DD" DEFAULT_FOREGROUND_COLOR = "#DDDDDD"
|
61
|
+
# It is recommended but not enforced that these should be valid CSS color property attributes
|
62
|
+
config.die_background_color = "red"
|
63
|
+
config.die_foreground_color = "#000"
|
46
64
|
end
|
47
65
|
```
|
66
|
+
**Note:** You cannot set `ability_score_dice_kept` greater than `ability_score_dice_rolled`. If you try to set `ability_score_dice_kept` higher than `ability_score_dice_rolled`, an error will be raised. If you set `ability_score_dice_rolled` _lower_ than the existing value of `ability_score_dice_kept`, no error will be thrown, but `ability_score_dice_kept` will be _**modified**_ to match `ability_score_dice_rolled` and a warning will be printed.
|
48
67
|
|
49
68
|
### Rolling a number of dice and adding a bonus
|
69
|
+
You can use two different methods to roll dice. The `total_dice` method returns an `Integer` representing the total of the dice plus any applicable bonuses. The `total_dice` method does not support chaining additional methods like `highest`, `lowest`, `with_advantage`, `with_disadvantage`. The `roll_dice` method returns a `DiceSet` collection object, and allows for chaining the methods mentioned above and iterating over the individual `Die` objects. `NerdDice.roll_dice.total` and `NerdDice.total_dice` are roughly equivalent.
|
70
|
+
|
50
71
|
```ruby
|
51
72
|
# roll a single d4
|
52
73
|
NerdDice.total_dice(4) # => return random Integer between 1-4
|
74
|
+
NerdDice.roll_dice(4) # => return a DiceSet with one 4-sided Die with a value between 1-4
|
75
|
+
NerdDice.roll_dice(4).total # => return random Integer between 1-4
|
53
76
|
|
54
77
|
# roll 3d6
|
55
78
|
NerdDice.total_dice(6, 3) # => return Integer total of three 6-sided dice
|
79
|
+
NerdDice.roll_dice(6, 3) # => return a DiceSet with three 6-sided Die objects, each with values between 1-6
|
80
|
+
NerdDice.roll_dice(6, 3).total # => return Integer total of three 6-sided dice
|
56
81
|
|
57
82
|
# roll a d20 and add 5 to the value
|
58
|
-
NerdDice.total_dice(20, bonus: 5)
|
83
|
+
NerdDice.total_dice(20, bonus: 5) # rolls a d20 and adds the bonus to the total => Integer
|
84
|
+
NerdDice.roll_dice(20, bonus: 5) # return a DiceSet with one 20-sided Die with a value between 1-20 and a bonus attribute of 5
|
85
|
+
NerdDice.roll_dice(20, bonus: 5).total # rolls a d20 and adds the bonus to the total => Integer
|
59
86
|
|
87
|
+
# without changing the config at the module level
|
60
88
|
# roll a d20 and overide the configured randomization_technique one time
|
61
|
-
|
62
|
-
|
89
|
+
NerdDice.total_dice(20, randomization_technique: :randomized) # => Integer
|
90
|
+
# roll a d20 and overide the configured randomization_technique for the DiceSet object will persist on the DiceSet object for subsequent rerolls
|
91
|
+
NerdDice.roll_dice(20, randomization_technique: :randomized) # => DiceSet with randomization_technique: :randomized
|
63
92
|
```
|
64
93
|
__NOTE:__ If provided, the bonus must respond to `:to_i` or an `ArgumentError` will be raised
|
65
94
|
|
95
|
+
### Taking actions on the dice as objects using the DiceSet object
|
96
|
+
The `NerdDice.roll_dice` method or the `NerdDice::DiceSet.new` methods return a collection object with an array of one or more `Die` objects. There are properties on both the `DiceSet` object and the `Die` object. Applicable properties are cascaded from the `DiceSet` to the `Die` objects in the collection by default.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
# These are equivalent
|
100
|
+
dice_set = NerdDice.roll_dice(6, 3, bonus: 2, randomization_technique: :randomized, damage_type: 'psychic', foreground_color: '#FFF', background_color: '#0FF')
|
101
|
+
# => NerdDice::DiceSet
|
102
|
+
dice_set = NerdDice::DiceSet.new(6, 3, bonus: 2, randomization_technique: :randomized, damage_type: 'psychic', foreground_color: '#FFF', background_color: '#0FF')
|
103
|
+
# => NerdDice::DiceSet
|
104
|
+
```
|
105
|
+
#### Available options for NerdDice::DiceSet objects
|
106
|
+
There are a number of options that can be provided when initializing a `NerdDice::DiceSet` object after specifying the mandatory number of sides and the optional number of dice \(default: 1\). The list below provides the options and indicates whether they are cascaded to the Die objects in the collection.
|
107
|
+
* `bonus` \(Duck-type Integer, _default: 0_\): Bonus or penalty to apply to the total after all dice are rolled. _**Not applied** to Die objects_
|
108
|
+
* `randomization_technique` \(Symbol, _default: nil_\): Randomization technique override to use for the `DiceSet`. If `nil` it will use the value in `NerdDice.configuration`. _**Applied** to Die objects by default with ability modify_
|
109
|
+
* `damage_type` \(String, _default: nil_\): Optional string indicating the damage type associated with the dice for systems where it is relevant. _**Applied** to Die objects by default with ability modify_
|
110
|
+
* `foreground_color` \(String, _default: `NerdDice.configuration.die_foreground_color`_\): Intended foreground color to apply to the dice in the `DiceSet`. Should be a valid CSS color but is not validated or enforced and doesn\'t currently have any real functionality associated with it. _**Applied** to Die objects by default with ability modify_
|
111
|
+
* `background_color` \(String, _default: `NerdDice.configuration.die_background_color`_\): Intended background color to apply to the dice in the `DiceSet`. Should be a valid CSS color but is not validated or enforced and doesn\'t currently have any real functionality associated with it. _**Applied** to Die objects by default with ability modify_
|
112
|
+
|
113
|
+
#### Properties of individual Die objects
|
114
|
+
When initialized from a `DiceSet` object most of the properties of the `Die` object are inherited from the `DiceSet` object. In addition, there is an `is_included_in_total` public attribute that can be set to indicate whether the value of that particular die should be included in the total for its parent `DiceSet`. This property always starts out as true when the `Die` is initialized, but can be set to false.
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
# six sided die
|
118
|
+
die = NerdDice::Die.new(6, randomization_technique: :randomized, damage_type: 'psychic', foreground_color: '#FFF', background_color: '#0FF')
|
119
|
+
die.is_included_in_total # => true
|
120
|
+
die.included_in_total? # => true
|
121
|
+
die.is_included_in_total = false
|
122
|
+
die.included_in_total? # => false
|
123
|
+
|
124
|
+
# value property
|
125
|
+
die.value # => Integer between 1 and number_of_sides
|
126
|
+
die.roll # => Integer. Rolls/rerolls the Die and sets value to the result of the roll. Returns the new value
|
127
|
+
```
|
128
|
+
#### Iterating through dices in a DiceSet
|
129
|
+
The `DiceSet` class mixes in the `Enumerable` module and the `Die` object mixes in the `Comparable` module. This allows you to iterate over the dice in the collection. The `sort` method on the dice will return the die objects in ascending value from lowest to highest.
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
dice_set = NerdDice.roll_dice(6, 3) # => NerdDice::DiceSet
|
133
|
+
dice_set.dice => Array of Die objects
|
134
|
+
dice_set.length # => 3. (dice_set.dice.length)
|
135
|
+
dice_set[0] # => NerdDice::Die (first element of dice array)
|
136
|
+
# take actions on each die
|
137
|
+
dice_set.each do |die|
|
138
|
+
# print the current value
|
139
|
+
puts "Die value before reroll is #{die.value}"
|
140
|
+
# set the foreground_color of the die
|
141
|
+
die.foreground_color = ["gray", "#FF0000#", "#d9d9d9", "green"].shuffle.first
|
142
|
+
# reroll the die
|
143
|
+
die.roll
|
144
|
+
# print the new value
|
145
|
+
puts "Die value after reroll is #{die.value}"
|
146
|
+
# do other things
|
147
|
+
end
|
148
|
+
```
|
149
|
+
#### Methods and method chaining on the DiceSet
|
150
|
+
Since the DiceSet is an object, you can call methods that operate on the result returned and allow for things like the 5e advantage/disadvantage mechanic, the ability to re-roll all of the dice in the `DiceSet`, or to mark them all as included in the total.
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
##############################################
|
154
|
+
# highest/with_advantage and lowest/with_disadvantage methods
|
155
|
+
# assuming 4d6 with values of [1, 3, 4, 6]
|
156
|
+
##############################################
|
157
|
+
dice_set = NerdDice.roll_dice(6, 4)
|
158
|
+
# the 6, 4, and 3 will have is_included_in_total true while the 1 has it false
|
159
|
+
dice_set.highest(3) # => Returns the existing DiceSet object with the changes made to dice inclusion
|
160
|
+
dice_set.with_advantage(3) # => Alias of highest method
|
161
|
+
# calling total after highest/with_advantage for this DiceSet
|
162
|
+
dice_set.total # => 13
|
163
|
+
# same DiceSet using lowest. The 1, 3, and 4 will have is_included_in_total true while the 6 has it false
|
164
|
+
dice_set.lowest(3) # => Returns the existing DiceSet object with the changes made to dice inclusion
|
165
|
+
dice_set.with_disadvantage(3) # => Alias of lowest method
|
166
|
+
# calling total after lowest/with_disadvantage for this DiceSet
|
167
|
+
dice_set.total # => 8
|
168
|
+
# you can chain these methods (assumes the same seed as the above examples)
|
169
|
+
NerdDice.roll_dice(6, 4).with_advantage(3).total # => 13
|
170
|
+
NerdDice.roll_dice(6, 4).lowest(3).total # => 8
|
171
|
+
|
172
|
+
# reroll_all! method
|
173
|
+
dice_set = NerdDice.roll_dice(6, 4)
|
174
|
+
dice_set.reroll_all! # rerolls each of the Die objects in the collection and re-includes them in the total
|
175
|
+
|
176
|
+
# include_all_dice! method
|
177
|
+
dice_set.include_all_dice! # resets is_included_in_total to true for all Die objects
|
178
|
+
```
|
179
|
+
|
180
|
+
### Rolling Ability Scores
|
181
|
+
You can call `roll_ability_scores` or `total_ability_scores` to get back an array of `DiceSet` objects or `Integer` objects, respectively. The `total_ability_scores` method calls `total` on each `DiceSet` and returns those numbers with one value per ability score. The `Configuration` object defaults to 6 ability scores using a methodology of __4d6 drop the lowest__ by default.
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
# return an array of DiceSet objects including info about the discarded dice
|
185
|
+
#
|
186
|
+
NerdDice.roll_ability_scores
|
187
|
+
#=> [DiceSet0, DiceSet1, ...]
|
188
|
+
# => DiceSet0 hash representation { total: 12, dice: [
|
189
|
+
# {value: 2, is_included_in_total: true},
|
190
|
+
# {value: 6, is_included_in_total: true},
|
191
|
+
# {value: 4, is_included_in_total: true},
|
192
|
+
# {value: 1, is_included_in_total: false}
|
193
|
+
# ]}
|
194
|
+
# if you want to get back DiceSet objects that you can interact with
|
195
|
+
|
196
|
+
# just return an array of totaled ability scores
|
197
|
+
NerdDice.total_ability_scores
|
198
|
+
#=> [12, 14, 13, 15, 10, 8]
|
199
|
+
```
|
200
|
+
|
201
|
+
Both methods can be called without arguments to use the values specified in `NerdDice.configuration` or passed a set of options.
|
202
|
+
```ruby
|
203
|
+
|
204
|
+
# total_dice and roll_dice take the same set of options
|
205
|
+
NerdDice.roll_ability_scores(
|
206
|
+
ability_score_array_size: 7,
|
207
|
+
ability_score_number_of_sides: 8,
|
208
|
+
ability_score_dice_rolled: 5,
|
209
|
+
ability_score_dice_kept: 4,
|
210
|
+
randomization_technique: :randomized,
|
211
|
+
foreground_color: "#FF0000",
|
212
|
+
background_color: "#FFFFFF"
|
213
|
+
)
|
214
|
+
# => [DiceSet0, DiceSet1, ...] with 7 ability scores that each roll 5d8 dropping the lowest
|
215
|
+
# or if called with total_ability_scores
|
216
|
+
# => [27, 17, 21, 17, 23, 13, 27]
|
217
|
+
```
|
218
|
+
**Note:** If you try to call this method with `ability_score_dice_kept` greater than `ability_score_dice_rolled` an error will be raised.
|
219
|
+
|
66
220
|
### Manually setting or refreshing the random generator seed
|
67
221
|
For randomization techniques other than `:securerandom` you can manually set or refresh the generator's seed by calling the `refresh_seed!` method. This is automatically called at the interval specified in `NerdDice.configuration.refresh_seed_interval` if it is not nil.
|
68
222
|
|
@@ -80,6 +234,23 @@ NerdDice.refresh_seed!(randomization_technique: :randomized,
|
|
80
234
|
```
|
81
235
|
__NOTE:__ Ability to specify a seed it primarily provided for testing purposes. This makes all random numbers generated _transparently deterministic_ and should not be used if you want behavior approximating randomness.
|
82
236
|
|
237
|
+
### Utility Methods
|
238
|
+
|
239
|
+
#### Harvesting Totals from DiceSets
|
240
|
+
The `harvest_totals` method take any collection of objects where each element responds to `total` and return an array of the results of the total method.
|
241
|
+
```ruby
|
242
|
+
ability_score_array = NerdDice.roll_ability_scores
|
243
|
+
# => Array of 6 DiceSet objects
|
244
|
+
|
245
|
+
# Arguments:
|
246
|
+
# collection (Enumerable) a collection where each element responds to total
|
247
|
+
#
|
248
|
+
# Return (Array) => Data type of each element will be whatever is returned by total method
|
249
|
+
totals_array = NerdDice.harvest_totals(totals_array)
|
250
|
+
# => [15, 14, 13, 12, 10, 8]
|
251
|
+
# yes, it just happened to be the standard array by amazing coincidence
|
252
|
+
```
|
253
|
+
|
83
254
|
## Development
|
84
255
|
|
85
256
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -88,8 +259,9 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
88
259
|
|
89
260
|
## Contributing
|
90
261
|
|
91
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/statelesscode/nerd_dice/issues. We welcome and encourage your participation in this open-source project. We welcome those of all backgrounds and abilities, but we refuse to adopt the Contributor Covenant for reasons outlined in [BURN_THE_CONTRIBUTOR_COVENANT_WITH_FIRE.md](BURN_THE_CONTRIBUTOR_COVENANT_WITH_FIRE.md)
|
262
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/statelesscode/nerd_dice/issues. We welcome and encourage your participation in this open-source project. We welcome those of all backgrounds and abilities, but we refuse to adopt the Contributor Covenant for reasons outlined in [BURN_THE_CONTRIBUTOR_COVENANT_WITH_FIRE.md](https://github.com/statelesscode/nerd_dice/blob/master/BURN_THE_CONTRIBUTOR_COVENANT_WITH_FIRE.md)
|
263
|
+
|
92
264
|
|
93
265
|
## Unlicense, License, and Copyright
|
94
266
|
|
95
|
-
The document is dual-licensed under the [MIT](https://opensource.org/licenses/MIT) license and the [UNLICENSE](https://unlicense.org/) \(with strong preference toward the UNLICENSE\)\. The content is released under [CC0](https://creativecommons.org/share-your-work/public-domain/cc0/) \(no rights reserved\). You are free to include it in its original form or modified with or without modification in your own project\.
|
267
|
+
The document is dual-licensed under the [MIT](https://opensource.org/licenses/MIT) license and the [UNLICENSE](https://unlicense.org/) \(with strong preference toward the UNLICENSE\)\. The content is released under [CC0](https://creativecommons.org/share-your-work/public-domain/cc0/) \(no rights reserved\). You are free to include it in its original form or modified with or without additional modification in your own project\.
|
data/bin/generate_checksums
CHANGED
@@ -7,7 +7,7 @@ version = ARGV[0]
|
|
7
7
|
built_gem_path = "pkg/nerd_dice-#{version}.gem"
|
8
8
|
checksum = Digest::SHA512.new.hexdigest(File.read(built_gem_path))
|
9
9
|
checksum_path = "checksum/nerd_dice-#{version}.gem.sha512"
|
10
|
-
File.
|
10
|
+
File.open(checksum_path, "w") { |f| f.write(checksum) }
|
11
11
|
sha256 = Digest::SHA256.new.hexdigest(File.read(built_gem_path))
|
12
12
|
checksum_256_path = "checksum/nerd_dice-#{version}.gem.sha256"
|
13
|
-
File.
|
13
|
+
File.open(checksum_256_path, "w") { |f| f.write(sha256) }
|
data/bin/nerd_dice_benchmark
CHANGED
@@ -8,14 +8,24 @@ require "nerd_dice"
|
|
8
8
|
n = 50_000
|
9
9
|
|
10
10
|
RATIOS = {
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
19
29
|
}.freeze
|
20
30
|
|
21
31
|
def check_against_baseline!(baseline_value, test_value)
|
@@ -44,22 +54,22 @@ securerandom_baseline = baselines[1].real
|
|
44
54
|
puts "Roll d1000s"
|
45
55
|
total_dice_d1000_results = Benchmark.bmbm do |x|
|
46
56
|
# NerdDice.total_dice securerandom
|
47
|
-
x.report("
|
57
|
+
x.report("total_dice_securerandom") do
|
48
58
|
NerdDice.configuration.randomization_technique = :securerandom
|
49
59
|
n.times { NerdDice.total_dice(1000) }
|
50
60
|
end
|
51
61
|
|
52
|
-
x.report("
|
62
|
+
x.report("total_dice_random_rand") do
|
53
63
|
NerdDice.configuration.randomization_technique = :random_rand
|
54
64
|
n.times { NerdDice.total_dice(1000) }
|
55
65
|
end
|
56
66
|
|
57
|
-
x.report("
|
67
|
+
x.report("total_dice_random_object") do
|
58
68
|
NerdDice.configuration.randomization_technique = :random_object
|
59
69
|
n.times { NerdDice.total_dice(1000) }
|
60
70
|
end
|
61
71
|
|
62
|
-
x.report("
|
72
|
+
x.report("total_dice_randomized") do
|
63
73
|
NerdDice.configuration.randomization_technique = :randomized
|
64
74
|
n.times { NerdDice.total_dice(1000) }
|
65
75
|
end
|
@@ -74,25 +84,57 @@ check_against_baseline! random_rand_baseline, total_dice_random_object
|
|
74
84
|
total_dice_randomized = total_dice_d1000_results[3]
|
75
85
|
check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), total_dice_randomized
|
76
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
|
+
|
77
119
|
puts "Roll 3d6"
|
78
120
|
total_dice_3d6_results = Benchmark.bmbm do |x|
|
79
121
|
# NerdDice.total_dice securerandom
|
80
|
-
x.report("
|
122
|
+
x.report("total_dice_securerandom_3d6") do
|
81
123
|
NerdDice.configuration.randomization_technique = :securerandom
|
82
124
|
n.times { NerdDice.total_dice(6, 3) }
|
83
125
|
end
|
84
126
|
|
85
|
-
x.report("
|
127
|
+
x.report("total_dice_random_rand_3d6") do
|
86
128
|
NerdDice.configuration.randomization_technique = :random_rand
|
87
129
|
n.times { NerdDice.total_dice(6, 3) }
|
88
130
|
end
|
89
131
|
|
90
|
-
x.report("
|
132
|
+
x.report("total_dice_random_object_3d6") do
|
91
133
|
NerdDice.configuration.randomization_technique = :random_object
|
92
134
|
n.times { NerdDice.total_dice(6, 3) }
|
93
135
|
end
|
94
136
|
|
95
|
-
x.report("
|
137
|
+
x.report("total_dice_randomized_3d6") do
|
96
138
|
NerdDice.configuration.randomization_technique = :randomized
|
97
139
|
n.times { NerdDice.total_dice(6, 3) }
|
98
140
|
end
|
@@ -106,3 +148,57 @@ total_dice_3d6_random_object = total_dice_3d6_results[2]
|
|
106
148
|
check_against_baseline! random_rand_baseline, total_dice_3d6_random_object
|
107
149
|
total_dice_3d6_randomized = total_dice_3d6_results[3]
|
108
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
|
data/certs/msducheminjr.pem
CHANGED
@@ -1,27 +1,26 @@
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
t+NX7PDOWx4k
|
2
|
+
MIIETTCCArWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB1zdGF0
|
3
|
+
ZWxlc3Njb2RlL0RDPWdtYWlsL0RDPWNvbTAeFw0yMDEyMDYyMzQ1NTZaFw0yMTEy
|
4
|
+
MDYyMzQ1NTZaMCgxJjAkBgNVBAMMHXN0YXRlbGVzc2NvZGUvREM9Z21haWwvREM9
|
5
|
+
Y29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyHIMJi0o3bwBZsx5
|
6
|
+
TQ35XByFsdDRsro3T+0NY7EAILtOiU04o9C2NPOp/RQE7BXQgMjGebwp6bT6QvzN
|
7
|
+
6noV4jPL7Fi5pWw08QygG7f+73YUBb+8d8o+3xGrC+UO5h1PZEtVcZwUWUG18QBE
|
8
|
+
fbDinQT6P4IDQoZwhfrPCB+aBfUyQp4Ok7oD7MEWqsq9SjrSxqxfk4+oZdXUySe7
|
9
|
+
Vi5vnzVQ5uFf56NHwWnNKCzJzmH84mBO5MzHaQpHNzKGJPoUmzLU5RBlCH6YXqBG
|
10
|
+
KhXTMUDBWKJmJ3RDry/FpGgJLKu4wzFRYjXla6IjeKozWGuPNNJ+2mesXKhsX7bo
|
11
|
+
vVCzRxPEupbEg/0FkJiWpiGlSPOdd6oJiwX8E6rlEeV605xrbOQewkbovHkYTMtG
|
12
|
+
+NH+u08x0z4Oj71kmDLwuj812uS0mtrCg2VhiYO0ZCQ4XrwBsBfK+/MtMlR+o6sG
|
13
|
+
/zvz/vHVJKaLTQxRp5oGo4QH6HfbOnwzTkXdZnt5AlN31ErJAgMBAAGjgYEwfzAJ
|
14
|
+
BgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUC7seYydsGO6O1qT4nVVD
|
15
|
+
G/LkiHYwIgYDVR0RBBswGYEXc3RhdGVsZXNzY29kZUBnbWFpbC5jb20wIgYDVR0S
|
16
|
+
BBswGYEXc3RhdGVsZXNzY29kZUBnbWFpbC5jb20wDQYJKoZIhvcNAQELBQADggGB
|
17
|
+
ADPRFRB1cjqdcE2O0jtqiDRmrR62uEYBiUbkRPVhyoEp/cK0TVhAs9mGWAyCWu0M
|
18
|
+
LewUeqNTUvQ9MgvagcKcnxa2RTjdrP3nGnwpStMr9bm3ArNJEzvWEs0Eusk9y73x
|
19
|
+
fjy0qH2pw5WPfWcKYlDehMXqOP+a4udYsz0YSNiI8qEfkDCSqTJN11d5kSjVjwGB
|
20
|
+
xkauxDT68j1JZRjPmQl3dl+DCgxkoziWX2mFTPLfGg5vZ0t6gmhdUtLvJtNIo0IX
|
21
|
+
477E5UjmE1+rULQp/fsH6n5+H+t2eCED41ST+gkKbaQBUfIuUaCmdHz9sJaIIBw2
|
22
|
+
6ordFa1nrLV4w5Uf6qYFnWVhIWX4GToyZSPO2s0DPYp3PWFJ4VtzKa2vp1TR5ZEA
|
23
|
+
dkij2eQ9M8bzWWmW+A7RNaI0CzLl967bKGBSaMVCsZGBarggWD8UwJnBhTuOPZGR
|
24
|
+
WQ4faXJSevxT+x9TgyUNJINPkz/KqreClzdL83cwxPzFFQto7zF6zMCsj0slqJjW
|
25
|
+
EQ==
|
27
26
|
-----END CERTIFICATE-----
|
@@ -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
|