nerd_dice 0.1.0 → 0.4.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/workflows/main.yml +67 -0
  4. data/.rubocop.yml +114 -0
  5. data/CHANGELOG.md +76 -2
  6. data/Gemfile +2 -2
  7. data/Gemfile.lock +54 -32
  8. data/README.md +372 -5
  9. data/bin/generate_checksums +13 -0
  10. data/bin/nerd_dice_benchmark +322 -0
  11. data/certs/msducheminjr.pem +26 -0
  12. data/checksum/nerd_dice-0.1.0.gem.sha256 +1 -0
  13. data/checksum/nerd_dice-0.1.0.gem.sha512 +1 -0
  14. data/checksum/nerd_dice-0.1.1.gem.sha256 +1 -0
  15. data/checksum/nerd_dice-0.1.1.gem.sha512 +1 -0
  16. data/checksum/nerd_dice-0.2.0.gem.sha256 +1 -0
  17. data/checksum/nerd_dice-0.2.0.gem.sha512 +1 -0
  18. data/checksum/nerd_dice-0.3.0.gem.sha256 +1 -0
  19. data/checksum/nerd_dice-0.3.0.gem.sha512 +1 -0
  20. data/lib/nerd_dice/class_methods/configure.rb +50 -0
  21. data/lib/nerd_dice/class_methods/execute_die_roll.rb +47 -0
  22. data/lib/nerd_dice/class_methods/harvest_totals.rb +40 -0
  23. data/lib/nerd_dice/class_methods/refresh_seed.rb +83 -0
  24. data/lib/nerd_dice/class_methods/roll_ability_scores.rb +73 -0
  25. data/lib/nerd_dice/class_methods/roll_dice.rb +45 -0
  26. data/lib/nerd_dice/class_methods/total_ability_scores.rb +52 -0
  27. data/lib/nerd_dice/class_methods/total_dice.rb +44 -0
  28. data/lib/nerd_dice/class_methods.rb +30 -0
  29. data/lib/nerd_dice/configuration.rb +91 -0
  30. data/lib/nerd_dice/convenience_methods.rb +279 -0
  31. data/lib/nerd_dice/dice_set.rb +166 -0
  32. data/lib/nerd_dice/die.rb +51 -0
  33. data/lib/nerd_dice/sets_randomization_technique.rb +19 -0
  34. data/lib/nerd_dice/version.rb +1 -1
  35. data/lib/nerd_dice.rb +15 -33
  36. data/nerd_dice.gemspec +12 -7
  37. data.tar.gz.sig +0 -0
  38. metadata +97 -21
  39. metadata.gz.sig +0 -0
  40. data/.travis.yml +0 -6
@@ -0,0 +1,322 @@
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
+ total_magic_securerandom: 6.04,
20
+ total_magic_random_rand: 85.9,
21
+ total_magic_random_object: 89.42,
22
+ total_magic_randomized: 20.27,
23
+ roll_dice_securerandom: 4.0,
24
+ roll_dice_random_rand: 42.0,
25
+ roll_dice_random_object: 44.0,
26
+ roll_dice_randomized: 14.5,
27
+ roll_magic_securerandom: 6.04,
28
+ roll_magic_random_rand: 85.9,
29
+ roll_magic_random_object: 89.42,
30
+ roll_magic_randomized: 20.27,
31
+ roll_dice_securerandom_3d6: 13.0,
32
+ roll_dice_random_rand_3d6: 79.0,
33
+ roll_dice_random_object_3d6: 86.0,
34
+ roll_dice_randomized_3d6: 26.5,
35
+ roll_magic_securerandom_3d6: 18.38,
36
+ roll_magic_random_rand_3d6: 108.54,
37
+ roll_magic_random_object_3d6: 118.36,
38
+ roll_magic_randomized_3d6: 44.39,
39
+ roll_ability_scores_randomized: 30.5,
40
+ total_ability_scores_randomized: 30.5
41
+ }.freeze
42
+
43
+ def check_against_baseline!(baseline_value, test_value)
44
+ ratio = RATIOS[test_value.label.to_sym]
45
+ error_message = "Failed benchmark for #{test_value.label}. "
46
+ error_message += "Allowed ratio was #{ratio} actual ratio was #{test_value.real / baseline_value}"
47
+ raise NerdDice::Error, error_message if test_value.real > baseline_value * ratio
48
+ end
49
+
50
+ puts "Set baseline"
51
+ baselines = Benchmark.bm do |x|
52
+ # Random.rand()
53
+ x.report("Random.rand") do # standard rand()
54
+ n.times { Random.rand(1000) }
55
+ end
56
+
57
+ # SecureRandom.rand()
58
+ x.report("Sec.rand") do
59
+ n.times { SecureRandom.rand(1000) }
60
+ end
61
+ end
62
+
63
+ random_rand_baseline = baselines[0].real
64
+ securerandom_baseline = baselines[1].real
65
+
66
+ puts "Roll d1000s"
67
+
68
+ puts "total_dice"
69
+ total_dice_d1000_results = Benchmark.bm do |x|
70
+ # NerdDice.total_dice securerandom
71
+ x.report("total_dice_securerandom") do
72
+ NerdDice.configuration.randomization_technique = :securerandom
73
+ n.times { NerdDice.total_dice(1000) }
74
+ end
75
+
76
+ x.report("total_dice_random_rand") do
77
+ NerdDice.configuration.randomization_technique = :random_rand
78
+ n.times { NerdDice.total_dice(1000) }
79
+ end
80
+
81
+ x.report("total_dice_random_object") do
82
+ NerdDice.configuration.randomization_technique = :random_object
83
+ n.times { NerdDice.total_dice(1000) }
84
+ end
85
+
86
+ x.report("total_dice_randomized") do
87
+ NerdDice.configuration.randomization_technique = :randomized
88
+ n.times { NerdDice.total_dice(1000) }
89
+ end
90
+ end
91
+
92
+ total_dice_securerandom = total_dice_d1000_results[0]
93
+ check_against_baseline! securerandom_baseline, total_dice_securerandom
94
+ total_dice_random_rand = total_dice_d1000_results[1]
95
+ check_against_baseline! random_rand_baseline, total_dice_random_rand
96
+ total_dice_random_object = total_dice_d1000_results[2]
97
+ check_against_baseline! random_rand_baseline, total_dice_random_object
98
+ total_dice_randomized = total_dice_d1000_results[3]
99
+ check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), total_dice_randomized
100
+
101
+ puts "total_ d1000s ConvenienceMethods"
102
+
103
+ # NOTE: Due to method_missing overhead, using roll_ ratios for ConvenienceMethods total_dice
104
+ total_d1000_results = Benchmark.bm do |x|
105
+ # NerdDice.total_dice securerandom
106
+ x.report("total_magic_securerandom") do
107
+ NerdDice.configuration.randomization_technique = :securerandom
108
+ n.times { NerdDice.total_d1000 }
109
+ end
110
+
111
+ x.report("total_magic_random_rand") do
112
+ NerdDice.configuration.randomization_technique = :random_rand
113
+ n.times { NerdDice.total_d1000 }
114
+ end
115
+
116
+ x.report("total_magic_random_object") do
117
+ NerdDice.configuration.randomization_technique = :random_object
118
+ n.times { NerdDice.total_d1000 }
119
+ end
120
+
121
+ x.report("total_magic_randomized") do
122
+ NerdDice.configuration.randomization_technique = :randomized
123
+ n.times { NerdDice.total_d1000 }
124
+ end
125
+ end
126
+
127
+ total_magic_securerandom = total_d1000_results[0]
128
+ check_against_baseline! securerandom_baseline, total_magic_securerandom
129
+ total_magic_random_rand = total_d1000_results[1]
130
+ check_against_baseline! random_rand_baseline, total_magic_random_rand
131
+ total_magic_random_object = total_d1000_results[2]
132
+ check_against_baseline! random_rand_baseline, total_magic_random_object
133
+ total_magic_randomized = total_d1000_results[3]
134
+ check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), total_magic_randomized
135
+
136
+ puts "roll_dice"
137
+ roll_dice_d1000_results = Benchmark.bm do |x|
138
+ # NerdDice.roll_dice securerandom
139
+ x.report("roll_dice_securerandom") do
140
+ NerdDice.configuration.randomization_technique = :securerandom
141
+ n.times { NerdDice.roll_dice(1000) }
142
+ end
143
+
144
+ x.report("roll_dice_random_rand") do
145
+ NerdDice.configuration.randomization_technique = :random_rand
146
+ n.times { NerdDice.roll_dice(1000) }
147
+ end
148
+
149
+ x.report("roll_dice_random_object") do
150
+ NerdDice.configuration.randomization_technique = :random_object
151
+ n.times { NerdDice.roll_dice(1000) }
152
+ end
153
+
154
+ x.report("roll_dice_randomized") do
155
+ NerdDice.configuration.randomization_technique = :randomized
156
+ n.times { NerdDice.roll_dice(1000) }
157
+ end
158
+ end
159
+
160
+ roll_dice_securerandom = roll_dice_d1000_results[0]
161
+ check_against_baseline! securerandom_baseline, roll_dice_securerandom
162
+ roll_dice_random_rand = roll_dice_d1000_results[1]
163
+ check_against_baseline! random_rand_baseline, roll_dice_random_rand
164
+ roll_dice_random_object = roll_dice_d1000_results[2]
165
+ check_against_baseline! random_rand_baseline, roll_dice_random_object
166
+ roll_dice_randomized = roll_dice_d1000_results[3]
167
+ check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), roll_dice_randomized
168
+
169
+ puts "roll_ d1000s ConvenienceMethods"
170
+ roll_d1000_results = Benchmark.bm do |x|
171
+ # NerdDice.roll_dice securerandom
172
+ x.report("roll_magic_securerandom") do
173
+ NerdDice.configuration.randomization_technique = :securerandom
174
+ n.times { NerdDice.roll_d1000 }
175
+ end
176
+
177
+ x.report("roll_magic_random_rand") do
178
+ NerdDice.configuration.randomization_technique = :random_rand
179
+ n.times { NerdDice.roll_d1000 }
180
+ end
181
+
182
+ x.report("roll_magic_random_object") do
183
+ NerdDice.configuration.randomization_technique = :random_object
184
+ n.times { NerdDice.roll_d1000 }
185
+ end
186
+
187
+ x.report("roll_magic_randomized") do
188
+ NerdDice.configuration.randomization_technique = :randomized
189
+ n.times { NerdDice.roll_d1000 }
190
+ end
191
+ end
192
+
193
+ roll_magic_securerandom = roll_d1000_results[0]
194
+ check_against_baseline! securerandom_baseline, roll_magic_securerandom
195
+ roll_magic_random_rand = roll_d1000_results[1]
196
+ check_against_baseline! random_rand_baseline, roll_magic_random_rand
197
+ roll_magic_random_object = roll_d1000_results[2]
198
+ check_against_baseline! random_rand_baseline, roll_magic_random_object
199
+ roll_magic_randomized = roll_d1000_results[3]
200
+ check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), roll_magic_randomized
201
+
202
+ puts "Roll 3d6"
203
+ puts "total_dice 3d6"
204
+ total_dice_3d6_results = Benchmark.bm do |x|
205
+ # NerdDice.total_dice securerandom
206
+ x.report("total_dice_securerandom_3d6") do
207
+ NerdDice.configuration.randomization_technique = :securerandom
208
+ n.times { NerdDice.total_dice(6, 3) }
209
+ end
210
+
211
+ x.report("total_dice_random_rand_3d6") do
212
+ NerdDice.configuration.randomization_technique = :random_rand
213
+ n.times { NerdDice.total_dice(6, 3) }
214
+ end
215
+
216
+ x.report("total_dice_random_object_3d6") do
217
+ NerdDice.configuration.randomization_technique = :random_object
218
+ n.times { NerdDice.total_dice(6, 3) }
219
+ end
220
+
221
+ x.report("total_dice_randomized_3d6") do
222
+ NerdDice.configuration.randomization_technique = :randomized
223
+ n.times { NerdDice.total_dice(6, 3) }
224
+ end
225
+ end
226
+
227
+ total_dice_3d6_securerandom = total_dice_3d6_results[0]
228
+ check_against_baseline! securerandom_baseline, total_dice_3d6_securerandom
229
+ total_dice_3d6_random_rand = total_dice_3d6_results[1]
230
+ check_against_baseline! random_rand_baseline, total_dice_3d6_random_rand
231
+ total_dice_3d6_random_object = total_dice_3d6_results[2]
232
+ check_against_baseline! random_rand_baseline, total_dice_3d6_random_object
233
+ total_dice_3d6_randomized = total_dice_3d6_results[3]
234
+ check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), total_dice_3d6_randomized
235
+
236
+ puts "roll_dice 3d6"
237
+ roll_dice_3d6_results = Benchmark.bm do |x|
238
+ # NerdDice.roll_dice securerandom
239
+ x.report("roll_dice_securerandom_3d6") do
240
+ NerdDice.configuration.randomization_technique = :securerandom
241
+ n.times { NerdDice.roll_dice(6, 3) }
242
+ end
243
+
244
+ x.report("roll_dice_random_rand_3d6") do
245
+ NerdDice.configuration.randomization_technique = :random_rand
246
+ n.times { NerdDice.roll_dice(6, 3) }
247
+ end
248
+
249
+ x.report("roll_dice_random_object_3d6") do
250
+ NerdDice.configuration.randomization_technique = :random_object
251
+ n.times { NerdDice.roll_dice(6, 3) }
252
+ end
253
+
254
+ x.report("roll_dice_randomized_3d6") do
255
+ NerdDice.configuration.randomization_technique = :randomized
256
+ n.times { NerdDice.roll_dice(6, 3) }
257
+ end
258
+ end
259
+
260
+ roll_dice_3d6_securerandom = roll_dice_3d6_results[0]
261
+ check_against_baseline! securerandom_baseline, roll_dice_3d6_securerandom
262
+ roll_dice_3d6_random_rand = roll_dice_3d6_results[1]
263
+ check_against_baseline! random_rand_baseline, roll_dice_3d6_random_rand
264
+ roll_dice_3d6_random_object = roll_dice_3d6_results[2]
265
+ check_against_baseline! random_rand_baseline, roll_dice_3d6_random_object
266
+ roll_dice_3d6_randomized = roll_dice_3d6_results[3]
267
+ check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), roll_dice_3d6_randomized
268
+
269
+ puts "roll_3d6 ConvenienceMethods"
270
+ roll_magic_3d6_results = Benchmark.bm do |x|
271
+ # NerdDice.roll_magic securerandom
272
+ x.report("roll_magic_securerandom_3d6") do
273
+ NerdDice.configuration.randomization_technique = :securerandom
274
+ n.times { NerdDice.roll_3d6 }
275
+ end
276
+
277
+ x.report("roll_magic_random_rand_3d6") do
278
+ NerdDice.configuration.randomization_technique = :random_rand
279
+ n.times { NerdDice.roll_3d6 }
280
+ end
281
+
282
+ x.report("roll_magic_random_object_3d6") do
283
+ NerdDice.configuration.randomization_technique = :random_object
284
+ n.times { NerdDice.roll_3d6 }
285
+ end
286
+
287
+ x.report("roll_magic_randomized_3d6") do
288
+ NerdDice.configuration.randomization_technique = :randomized
289
+ n.times { NerdDice.roll_3d6 }
290
+ end
291
+ end
292
+
293
+ roll_magic_3d6_securerandom = roll_magic_3d6_results[0]
294
+ check_against_baseline! securerandom_baseline, roll_magic_3d6_securerandom
295
+ roll_magic_3d6_random_rand = roll_magic_3d6_results[1]
296
+ check_against_baseline! random_rand_baseline, roll_magic_3d6_random_rand
297
+ roll_magic_3d6_random_object = roll_magic_3d6_results[2]
298
+ check_against_baseline! random_rand_baseline, roll_magic_3d6_random_object
299
+ roll_magic_3d6_randomized = roll_magic_3d6_results[3]
300
+ check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), roll_magic_3d6_randomized
301
+
302
+ puts "Setting n down to 5,000 due to more intensive methods"
303
+ n = 5_000
304
+
305
+ puts "Roll and total ability scores"
306
+ roll_ability_scores_results = Benchmark.bm do |x|
307
+ x.report("roll_ability_scores_randomized") do
308
+ NerdDice.configuration.randomization_technique = :randomized
309
+ n.times { NerdDice.roll_ability_scores }
310
+ end
311
+
312
+ x.report("total_ability_scores_randomized") do
313
+ NerdDice.configuration.randomization_technique = :randomized
314
+ n.times { NerdDice.total_ability_scores }
315
+ end
316
+ end
317
+
318
+ roll_ability_scores_randomized = roll_ability_scores_results[0]
319
+ check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)), roll_ability_scores_randomized
320
+ total_ability_scores_randomized = roll_ability_scores_results[1]
321
+ check_against_baseline! ((random_rand_baseline * 0.75) + (securerandom_baseline * 0.25)),
322
+ total_ability_scores_randomized
@@ -0,0 +1,26 @@
1
+ -----BEGIN CERTIFICATE-----
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==
26
+ -----END CERTIFICATE-----
@@ -0,0 +1 @@
1
+ 39c9724b0b40e17b309b71343c5b6838f401fa9660ac53c4be8d4b0050904da3
@@ -0,0 +1 @@
1
+ 58f15bb3c270b530f3620afd53d17981c48871aba61b205c8cb012ae8f396bbac905d46d32f657399f787b4c8aaf3572aab030a4bfa81c1b7d9ff1b060aa5b82
@@ -0,0 +1 @@
1
+ 3b8e94b12954afbeb9c08746c57a19e06dc2405cb0e74f500d0111ef99e97f72
@@ -0,0 +1 @@
1
+ 469f2104263dbf07ab0e83e04a3b08087b3f64a7702143ed2387a04601c7db2c0e43404dd325de1d2fbe394858973e6d9bb214d9b0f602cead65b7dc4fbcb46b
@@ -0,0 +1 @@
1
+ 0a2d4765e24c21fecf99229b0cc4fad806ca256d2187c45c442b25771af1b9cc
@@ -0,0 +1 @@
1
+ e345190f870eabd2a4fd6993f1a1d70d008ef8e6464767ba5697a46f7c4d6912c78a18039cec06c18dd6f0ee9f425453c078f780d36ccf65043ec3f7fba790a2
@@ -0,0 +1 @@
1
+ 30f9d3809362099e81e414bf987b711c8dad59703c68579809bb36ce9b199d58
@@ -0,0 +1 @@
1
+ 1a8913b8f2878c1471f32dadaddf9965fd61c7ef2e9a255961babdb9586f2c18b7eca1cd0f1021061fb69c96a330151a97df9a102b2871e1e1c5e5675f34a511
@@ -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,40 @@
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 = get_harvest_totals_error_message(e)
28
+ specific_message ? raise(ArgumentError, "You must provide a valid collection. #{specific_message}") : raise
29
+ end
30
+
31
+ private
32
+
33
+ def get_harvest_totals_error_message(rescued_error)
34
+ case rescued_error.message
35
+ when /`total'/ then "Each element must respond to :total."
36
+ when /`map'/ then "Argument must respond to :map."
37
+ end
38
+ end
39
+ end
40
+ 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