nerd_dice 0.1.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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