games_dice 0.3.3 → 0.3.5
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.
- data/.travis.yml +1 -0
- data/Rakefile +16 -1
- data/ext/games_dice/probabilities.c +160 -102
- data/ext/games_dice/probabilities.h +14 -14
- data/games_dice.gemspec +4 -4
- data/lib/games_dice.rb +1 -1
- data/lib/games_dice/probabilities.rb +22 -1
- data/lib/games_dice/version.rb +1 -1
- data/spec/probability_spec.rb +7 -0
- metadata +104 -118
data/.travis.yml
CHANGED
data/Rakefile
CHANGED
@@ -3,6 +3,11 @@ require "rspec/core/rake_task"
|
|
3
3
|
require 'rake/extensiontask'
|
4
4
|
require "yard"
|
5
5
|
|
6
|
+
def can_compile_extensions
|
7
|
+
return false if RUBY_DESCRIPTION =~ /jruby/
|
8
|
+
return true
|
9
|
+
end
|
10
|
+
|
6
11
|
desc "GamesDice unit tests"
|
7
12
|
RSpec::Core::RakeTask.new(:test) do |t|
|
8
13
|
t.pattern = "spec/*_spec.rb"
|
@@ -22,4 +27,14 @@ Rake::ExtensionTask.new do |ext|
|
|
22
27
|
ext.gem_spec = gemspec
|
23
28
|
end
|
24
29
|
|
25
|
-
task :
|
30
|
+
task :delete_compiled_ext do |t|
|
31
|
+
`rm lib/games_dice/games_dice.*`
|
32
|
+
end
|
33
|
+
|
34
|
+
task :pure_test => [:delete_compiled_ext, :test]
|
35
|
+
|
36
|
+
if can_compile_extensions
|
37
|
+
task :default => [:compile, :test]
|
38
|
+
else
|
39
|
+
task :default => [:test]
|
40
|
+
end
|
@@ -21,7 +21,7 @@ VALUE Probabilities = Qnil;
|
|
21
21
|
// General utils
|
22
22
|
//
|
23
23
|
|
24
|
-
|
24
|
+
inline int max( int *a, int n ) {
|
25
25
|
int m = -1000000000;
|
26
26
|
int i;
|
27
27
|
for ( i=0; i < n; i++ ) {
|
@@ -30,7 +30,7 @@ static inline int max( int *a, int n ) {
|
|
30
30
|
return m;
|
31
31
|
}
|
32
32
|
|
33
|
-
|
33
|
+
inline int min( int *a, int n ) {
|
34
34
|
int m = 1000000000;
|
35
35
|
int i;
|
36
36
|
for ( i=0; i < n; i++ ) {
|
@@ -46,7 +46,7 @@ static inline int min( int *a, int n ) {
|
|
46
46
|
//
|
47
47
|
|
48
48
|
// There is no point calculating these, a cache of them is just fine.
|
49
|
-
|
49
|
+
double nfact[171] = {
|
50
50
|
1.0, 1.0, 2.0, 6.0,
|
51
51
|
24.0, 120.0, 720.0, 5040.0,
|
52
52
|
40320.0, 362880.0, 3628800.0, 39916800.0,
|
@@ -91,7 +91,7 @@ static double nfact[171] = {
|
|
91
91
|
3.287218585534296e+293, 5.423910666131589e+295, 9.003691705778438e+297, 1.503616514864999e+300,
|
92
92
|
2.5260757449731984e+302, 4.269068009004705e+304, 7.257415615307999e+306 };
|
93
93
|
|
94
|
-
|
94
|
+
double num_arrangements( int *args, int nargs ) {
|
95
95
|
int sum = 0;
|
96
96
|
double div_by = 1.0;
|
97
97
|
int i;
|
@@ -110,7 +110,7 @@ static double num_arrangements( int *args, int nargs ) {
|
|
110
110
|
// Probability List basics - create, delete, copy
|
111
111
|
//
|
112
112
|
|
113
|
-
|
113
|
+
ProbabilityList *create_probability_list() {
|
114
114
|
ProbabilityList *pl;
|
115
115
|
pl = malloc (sizeof(ProbabilityList));
|
116
116
|
if ( pl == NULL ) {
|
@@ -123,20 +123,22 @@ static ProbabilityList *create_probability_list() {
|
|
123
123
|
return pl;
|
124
124
|
}
|
125
125
|
|
126
|
-
|
126
|
+
void destroy_probability_list( ProbabilityList *pl ) {
|
127
127
|
xfree( pl->cumulative );
|
128
128
|
xfree( pl->probs );
|
129
129
|
xfree( pl );
|
130
130
|
return;
|
131
131
|
}
|
132
132
|
|
133
|
-
|
133
|
+
double *alloc_probs( ProbabilityList *pl, int slots ) {
|
134
|
+
double *pr;
|
135
|
+
|
134
136
|
if ( slots < 1 || slots > 1000000 ) {
|
135
137
|
rb_raise(rb_eArgError, "Bad number of probability slots");
|
136
138
|
}
|
137
139
|
pl->slots = slots;
|
138
140
|
|
139
|
-
|
141
|
+
pr = ALLOC_N( double, slots );
|
140
142
|
pl->probs = pr;
|
141
143
|
|
142
144
|
pl->cumulative = ALLOC_N( double, slots );
|
@@ -144,7 +146,7 @@ static double *alloc_probs( ProbabilityList *pl, int slots ) {
|
|
144
146
|
return pr;
|
145
147
|
}
|
146
148
|
|
147
|
-
|
149
|
+
double calc_cumulative( ProbabilityList *pl ) {
|
148
150
|
double *c = pl->cumulative;
|
149
151
|
double *pr = pl->probs;
|
150
152
|
int i;
|
@@ -156,12 +158,14 @@ static double calc_cumulative( ProbabilityList *pl ) {
|
|
156
158
|
return t;
|
157
159
|
}
|
158
160
|
|
159
|
-
|
161
|
+
double *alloc_probs_iv( ProbabilityList *pl, int slots, double iv ) {
|
162
|
+
double *pr;
|
163
|
+
int i;
|
164
|
+
|
160
165
|
if ( iv < 0.0 || iv > 1.0 ) {
|
161
166
|
rb_raise(rb_eArgError, "Bad single probability value");
|
162
167
|
}
|
163
|
-
|
164
|
-
int i;
|
168
|
+
pr= alloc_probs( pl, slots );
|
165
169
|
for(i=0; i<slots; i++) {
|
166
170
|
pr[i] = iv;
|
167
171
|
}
|
@@ -169,16 +173,17 @@ static double *alloc_probs_iv( ProbabilityList *pl, int slots, double iv ) {
|
|
169
173
|
return pr;
|
170
174
|
}
|
171
175
|
|
172
|
-
|
176
|
+
ProbabilityList *copy_probability_list( ProbabilityList *orig ) {
|
173
177
|
ProbabilityList *pl = create_probability_list();
|
174
|
-
double *pr
|
178
|
+
double *pr;
|
179
|
+
pr = alloc_probs( pl, orig->slots );
|
175
180
|
pl->offset = orig->offset;
|
176
181
|
memcpy( pr, orig->probs, orig->slots * sizeof(double) );
|
177
182
|
memcpy( pl->cumulative, orig->cumulative, orig->slots * sizeof(double) );
|
178
183
|
return pl;
|
179
184
|
}
|
180
185
|
|
181
|
-
|
186
|
+
inline ProbabilityList *new_basic_pl( int nslots, double iv, int o ) {
|
182
187
|
ProbabilityList *pl = create_probability_list();
|
183
188
|
alloc_probs_iv( pl, nslots, iv );
|
184
189
|
pl->offset = o;
|
@@ -190,22 +195,23 @@ static inline ProbabilityList *new_basic_pl( int nslots, double iv, int o ) {
|
|
190
195
|
// Probability List core "native" methods
|
191
196
|
//
|
192
197
|
|
193
|
-
|
198
|
+
inline int pl_min( ProbabilityList *pl ) {
|
194
199
|
return pl->offset;
|
195
200
|
}
|
196
201
|
|
197
|
-
|
202
|
+
inline int pl_max( ProbabilityList *pl ) {
|
198
203
|
return pl->offset + pl->slots - 1;
|
199
204
|
}
|
200
205
|
|
201
|
-
|
206
|
+
ProbabilityList *pl_add_distributions( ProbabilityList *pl_a, ProbabilityList *pl_b ) {
|
207
|
+
double *pr;
|
202
208
|
int s = pl_a->slots + pl_b->slots - 1;
|
203
209
|
int o = pl_a->offset + pl_b->offset;
|
204
210
|
int i,j;
|
205
211
|
|
206
212
|
ProbabilityList *pl = create_probability_list();
|
207
213
|
pl->offset = o;
|
208
|
-
|
214
|
+
pr = alloc_probs_iv( pl, s, 0.0 );
|
209
215
|
for ( i=0; i < pl_a->slots; i++ ) { for ( j=0; j < pl_b->slots; j++ ) {
|
210
216
|
pr[ i + j ] += (pl_a->probs)[i] * (pl_b->probs)[j];
|
211
217
|
} }
|
@@ -213,21 +219,22 @@ static ProbabilityList *pl_add_distributions( ProbabilityList *pl_a, Probability
|
|
213
219
|
return pl;
|
214
220
|
}
|
215
221
|
|
216
|
-
|
222
|
+
ProbabilityList *pl_add_distributions_mult( int mul_a, ProbabilityList *pl_a, int mul_b, ProbabilityList *pl_b ) {
|
217
223
|
int pts[4] = {
|
218
224
|
mul_a * pl_min( pl_a ) + mul_b * pl_min( pl_b ),
|
219
225
|
mul_a * pl_max( pl_a ) + mul_b * pl_min( pl_b ),
|
220
226
|
mul_a * pl_min( pl_a ) + mul_b * pl_max( pl_b ),
|
221
227
|
mul_a * pl_max( pl_a ) + mul_b * pl_max( pl_b ) };
|
222
228
|
|
229
|
+
double *pr;
|
223
230
|
int combined_min = min( pts, 4 );
|
224
231
|
int combined_max = max( pts, 4 );
|
225
232
|
int s = 1 + combined_max - combined_min;
|
233
|
+
int i,j;
|
226
234
|
|
227
235
|
ProbabilityList *pl = create_probability_list();
|
228
236
|
pl->offset = combined_min;
|
229
|
-
|
230
|
-
int i,j;
|
237
|
+
pr = alloc_probs_iv( pl, s, 0.0 );
|
231
238
|
for ( i=0; i < pl_a->slots; i++ ) { for ( j=0; j < pl_b->slots; j++ ) {
|
232
239
|
int k = mul_a * (i + pl_a->offset) + mul_b * (j + pl_b->offset) - combined_min;
|
233
240
|
pr[ k ] += (pl_a->probs)[i] * (pl_b->probs)[j];
|
@@ -236,7 +243,7 @@ static ProbabilityList *pl_add_distributions_mult( int mul_a, ProbabilityList *p
|
|
236
243
|
return pl;
|
237
244
|
}
|
238
245
|
|
239
|
-
|
246
|
+
inline double pl_p_eql( ProbabilityList *pl, int target ) {
|
240
247
|
int idx = target - pl->offset;
|
241
248
|
if ( idx < 0 || idx >= pl->slots ) {
|
242
249
|
return 0.0;
|
@@ -244,15 +251,15 @@ static inline double pl_p_eql( ProbabilityList *pl, int target ) {
|
|
244
251
|
return (pl->probs)[idx];
|
245
252
|
}
|
246
253
|
|
247
|
-
|
254
|
+
inline double pl_p_gt( ProbabilityList *pl, int target ) {
|
248
255
|
return 1.0 - pl_p_le( pl, target );
|
249
256
|
}
|
250
257
|
|
251
|
-
|
258
|
+
inline double pl_p_lt( ProbabilityList *pl, int target ) {
|
252
259
|
return pl_p_le( pl, target - 1 );
|
253
260
|
}
|
254
261
|
|
255
|
-
|
262
|
+
inline double pl_p_le( ProbabilityList *pl, int target ) {
|
256
263
|
int idx = target - pl->offset;
|
257
264
|
if ( idx < 0 ) {
|
258
265
|
return 0.0;
|
@@ -263,11 +270,11 @@ static inline double pl_p_le( ProbabilityList *pl, int target ) {
|
|
263
270
|
return (pl->cumulative)[idx];
|
264
271
|
}
|
265
272
|
|
266
|
-
|
273
|
+
inline double pl_p_ge( ProbabilityList *pl, int target ) {
|
267
274
|
return 1.0 - pl_p_le( pl, target - 1 );
|
268
275
|
}
|
269
276
|
|
270
|
-
|
277
|
+
inline double pl_expected( ProbabilityList *pl ) {
|
271
278
|
double t = 0.0;
|
272
279
|
int o = pl->offset;
|
273
280
|
int s = pl->slots;
|
@@ -279,24 +286,30 @@ static inline double pl_expected( ProbabilityList *pl ) {
|
|
279
286
|
return t;
|
280
287
|
}
|
281
288
|
|
282
|
-
|
289
|
+
ProbabilityList *pl_given_ge( ProbabilityList *pl, int target ) {
|
283
290
|
int m = pl_min( pl );
|
291
|
+
double p, mult;
|
292
|
+
double *pr;
|
293
|
+
double *new_pr;
|
294
|
+
int o,i,s;
|
295
|
+
ProbabilityList *new_pl;
|
296
|
+
|
284
297
|
if ( m > target ) {
|
285
298
|
target = m;
|
286
299
|
}
|
287
|
-
|
300
|
+
p = pl_p_ge( pl, target );
|
288
301
|
if ( p <= 0.0 ) {
|
289
302
|
rb_raise( rb_eRuntimeError, "Cannot calculate given probabilities, divide by zero" );
|
290
303
|
}
|
291
|
-
|
292
|
-
|
293
|
-
|
304
|
+
mult = 1.0/p;
|
305
|
+
s = pl->slots + pl->offset - target;
|
306
|
+
pr = pl->probs;
|
294
307
|
|
295
|
-
|
308
|
+
new_pl = create_probability_list();
|
296
309
|
new_pl->offset = target;
|
297
|
-
|
298
|
-
|
299
|
-
|
310
|
+
new_pr = alloc_probs( new_pl, s );
|
311
|
+
o = target - pl->offset;
|
312
|
+
|
300
313
|
for ( i = 0; i < s; i++ ) {
|
301
314
|
new_pr[i] = pr[o + i] * mult;
|
302
315
|
}
|
@@ -304,23 +317,29 @@ static ProbabilityList *pl_given_ge( ProbabilityList *pl, int target ) {
|
|
304
317
|
return new_pl;
|
305
318
|
}
|
306
319
|
|
307
|
-
|
320
|
+
ProbabilityList *pl_given_le( ProbabilityList *pl, int target ) {
|
308
321
|
int m = pl_max( pl );
|
322
|
+
double p, mult;
|
323
|
+
double *pr;
|
324
|
+
double *new_pr;
|
325
|
+
int i,s;
|
326
|
+
ProbabilityList *new_pl;
|
327
|
+
|
309
328
|
if ( m < target ) {
|
310
329
|
target = m;
|
311
330
|
}
|
312
|
-
|
331
|
+
p = pl_p_le( pl, target );
|
313
332
|
if ( p <= 0.0 ) {
|
314
333
|
rb_raise( rb_eRuntimeError, "Cannot calculate given probabilities, divide by zero" );
|
315
334
|
}
|
316
|
-
|
317
|
-
|
318
|
-
|
335
|
+
mult = 1.0/p;
|
336
|
+
s = target - pl->offset + 1;
|
337
|
+
pr = pl->probs;
|
319
338
|
|
320
|
-
|
339
|
+
new_pl = create_probability_list();
|
321
340
|
new_pl->offset = pl->offset;
|
322
|
-
|
323
|
-
|
341
|
+
new_pr = alloc_probs( new_pl, s );
|
342
|
+
|
324
343
|
for ( i = 0; i < s; i++ ) {
|
325
344
|
new_pr[i] = pr[i] * mult;
|
326
345
|
}
|
@@ -328,7 +347,12 @@ static ProbabilityList *pl_given_le( ProbabilityList *pl, int target ) {
|
|
328
347
|
return new_pl;
|
329
348
|
}
|
330
349
|
|
331
|
-
|
350
|
+
ProbabilityList *pl_repeat_sum( ProbabilityList *pl, int n ) {
|
351
|
+
ProbabilityList *pd_power = NULL;
|
352
|
+
ProbabilityList *pd_result = NULL;
|
353
|
+
ProbabilityList *pd_next = NULL;
|
354
|
+
int power = 1;
|
355
|
+
|
332
356
|
if ( n < 1 ) {
|
333
357
|
rb_raise( rb_eRuntimeError, "Cannot calculate repeat_sum when n < 1" );
|
334
358
|
}
|
@@ -336,10 +360,8 @@ static ProbabilityList *pl_repeat_sum( ProbabilityList *pl, int n ) {
|
|
336
360
|
rb_raise( rb_eRuntimeError, "Too many probability slots" );
|
337
361
|
}
|
338
362
|
|
339
|
-
|
340
|
-
|
341
|
-
ProbabilityList *pd_next = NULL;
|
342
|
-
int power = 1;
|
363
|
+
pd_power = copy_probability_list( pl );
|
364
|
+
|
343
365
|
while ( 1 ) {
|
344
366
|
if ( power & n ) {
|
345
367
|
if ( pd_result ) {
|
@@ -362,7 +384,7 @@ static ProbabilityList *pl_repeat_sum( ProbabilityList *pl, int n ) {
|
|
362
384
|
}
|
363
385
|
|
364
386
|
// Assigns { p_rejected, p_maybe, p_kept } to buffer
|
365
|
-
|
387
|
+
void calc_p_table( ProbabilityList *pl, int q, int kbest, double *buffer ) {
|
366
388
|
if ( kbest ) {
|
367
389
|
buffer[2] = pl_p_gt( pl, q );
|
368
390
|
buffer[1] = pl_p_eql( pl, q );
|
@@ -376,12 +398,12 @@ static void calc_p_table( ProbabilityList *pl, int q, int kbest, double *buffer
|
|
376
398
|
}
|
377
399
|
|
378
400
|
// Assigns a list of pl variants to a buffer
|
379
|
-
|
380
|
-
|
401
|
+
void calc_keep_distributions( ProbabilityList *pl, int k, int q, int kbest, ProbabilityList **pl_array ) {
|
402
|
+
ProbabilityList *pl_kd;
|
403
|
+
|
381
404
|
int n;
|
382
405
|
for ( n=0; n<k; n++) { pl_array[n] = NULL; }
|
383
406
|
pl_array[0] = new_basic_pl( 1, 1.0, q * k );
|
384
|
-
ProbabilityList *pl_kd;
|
385
407
|
|
386
408
|
if ( kbest ) {
|
387
409
|
if ( pl_p_gt( pl, q ) > 0.0 && k > 1 ) {
|
@@ -404,7 +426,7 @@ static void calc_keep_distributions( ProbabilityList *pl, int k, int q, int kbes
|
|
404
426
|
return;
|
405
427
|
}
|
406
428
|
|
407
|
-
|
429
|
+
inline void clear_pl_array( int k, ProbabilityList **pl_array ) {
|
408
430
|
int n;
|
409
431
|
for ( n=0; n<k; n++) {
|
410
432
|
if ( pl_array[n] != NULL ) {
|
@@ -414,7 +436,20 @@ static inline void clear_pl_array( int k, ProbabilityList **pl_array ) {
|
|
414
436
|
return;
|
415
437
|
}
|
416
438
|
|
417
|
-
|
439
|
+
ProbabilityList *pl_repeat_n_sum_k( ProbabilityList *pl, int n, int k, int kbest ) {
|
440
|
+
// Table of probabilities ( reject, maybe, keep ) for each "pivot point"
|
441
|
+
double p_table[3];
|
442
|
+
int keep_combos[3];
|
443
|
+
// Table of distributions for each count of > pivot point (vs == pivot point)
|
444
|
+
ProbabilityList *keep_distributions[171];
|
445
|
+
ProbabilityList *kd;
|
446
|
+
ProbabilityList *pl_result = NULL;
|
447
|
+
|
448
|
+
double *pr;
|
449
|
+
int d = n - k;
|
450
|
+
int i, j, q, dn, kn, mn, kdq;
|
451
|
+
double p_sequence;
|
452
|
+
|
418
453
|
if ( n < 1 ) {
|
419
454
|
rb_raise( rb_eRuntimeError, "Cannot calculate repeat_n_sum_k when n < 1" );
|
420
455
|
}
|
@@ -432,21 +467,10 @@ static ProbabilityList *pl_repeat_n_sum_k( ProbabilityList *pl, int n, int k, in
|
|
432
467
|
}
|
433
468
|
|
434
469
|
// Init target
|
435
|
-
|
436
|
-
|
470
|
+
pl_result = create_probability_list();
|
471
|
+
pr = alloc_probs_iv( pl_result, 1 + k * (pl->slots - 1), 0.0 );
|
437
472
|
pl_result->offset = pl->offset * k;
|
438
473
|
|
439
|
-
// Table of probabilities ( reject, maybe, keep ) for each "pivot point"
|
440
|
-
double p_table[3];
|
441
|
-
int keep_combos[3];
|
442
|
-
// Table of distributions for each count of > pivot point (vs == pivot point)
|
443
|
-
ProbabilityList *keep_distributions[171];
|
444
|
-
ProbabilityList *kd;
|
445
|
-
|
446
|
-
int d = n - k;
|
447
|
-
int i, j, q, dn, kn, mn, kdq;
|
448
|
-
double p_sequence;
|
449
|
-
|
450
474
|
for ( i = 0; i < pl->slots; i++ ) {
|
451
475
|
if ( ! pl->probs[i] > 0.0 ) continue;
|
452
476
|
|
@@ -491,21 +515,21 @@ static ProbabilityList *pl_repeat_n_sum_k( ProbabilityList *pl, int n, int k, in
|
|
491
515
|
// Ruby integration
|
492
516
|
//
|
493
517
|
|
494
|
-
|
518
|
+
inline VALUE pl_as_ruby_class( ProbabilityList *pl, VALUE klass ) {
|
495
519
|
return Data_Wrap_Struct( klass, 0, destroy_probability_list, pl );
|
496
520
|
}
|
497
521
|
|
498
|
-
|
522
|
+
VALUE pl_alloc(VALUE klass) {
|
499
523
|
return pl_as_ruby_class( create_probability_list(), klass );
|
500
524
|
}
|
501
525
|
|
502
|
-
inline
|
526
|
+
inline ProbabilityList *get_probability_list( VALUE obj ) {
|
503
527
|
ProbabilityList *pl;
|
504
528
|
Data_Get_Struct( obj, ProbabilityList, pl );
|
505
529
|
return pl;
|
506
530
|
}
|
507
531
|
|
508
|
-
|
532
|
+
void assert_value_wraps_pl( VALUE obj ) {
|
509
533
|
if ( TYPE(obj) != T_DATA ||
|
510
534
|
RDATA(obj)->dfree != (RUBY_DATA_FUNC)destroy_probability_list) {
|
511
535
|
rb_raise( rb_eTypeError, "Expected a Probabilities object, but got something else" );
|
@@ -515,8 +539,14 @@ static void assert_value_wraps_pl( VALUE obj ) {
|
|
515
539
|
// Validate key/value from hash, and adjust object properties as required
|
516
540
|
int validate_key_value( VALUE key, VALUE val, VALUE obj ) {
|
517
541
|
int k = NUM2INT( key );
|
518
|
-
double v = NUM2DBL( val );
|
519
542
|
ProbabilityList *pl = get_probability_list( obj );
|
543
|
+
// Not assigned (to avoid "unused" warning), but this throws execption if val cannot be coerced to double
|
544
|
+
NUM2DBL( val );
|
545
|
+
|
546
|
+
if ( k > 0x7fffffff ) {
|
547
|
+
rb_raise( rb_eArgError, "Result too large" );
|
548
|
+
}
|
549
|
+
|
520
550
|
if ( k < pl->offset ) {
|
521
551
|
if ( pl->slots < 1 ) {
|
522
552
|
pl->slots = 1;
|
@@ -544,16 +574,20 @@ int copy_key_value( VALUE key, VALUE val, VALUE obj ) {
|
|
544
574
|
// Ruby class and instance methods for Probabilities
|
545
575
|
//
|
546
576
|
|
547
|
-
|
548
|
-
int o
|
577
|
+
VALUE probabilities_initialize( VALUE self, VALUE arr, VALUE offset ) {
|
578
|
+
int i, o, s;
|
579
|
+
double error, p_item;
|
580
|
+
ProbabilityList *pl;
|
581
|
+
double *pr;
|
582
|
+
|
583
|
+
o = NUM2INT(offset);
|
549
584
|
Check_Type( arr, T_ARRAY );
|
550
|
-
|
551
|
-
|
585
|
+
s = FIX2INT( rb_funcall( arr, rb_intern("count"), 0 ) );
|
586
|
+
pl = get_probability_list( self );
|
552
587
|
pl->offset = o;
|
553
|
-
|
554
|
-
double *pr = alloc_probs( pl, s );
|
588
|
+
pr = alloc_probs( pl, s );
|
555
589
|
for(i=0; i<s; i++) {
|
556
|
-
|
590
|
+
p_item = NUM2DBL( rb_ary_entry( arr, i ) );
|
557
591
|
if ( p_item < 0.0 ) {
|
558
592
|
rb_raise( rb_eArgError, "Negative probability not allowed" );
|
559
593
|
} else if ( p_item > 1.0 ) {
|
@@ -561,7 +595,7 @@ static VALUE probabilities_initialize( VALUE self, VALUE arr, VALUE offset ) {
|
|
561
595
|
}
|
562
596
|
pr[i] = p_item;
|
563
597
|
}
|
564
|
-
|
598
|
+
error = calc_cumulative( pl ) - 1.0;
|
565
599
|
if ( error < -1.0e-8 ) {
|
566
600
|
rb_raise( rb_eArgError, "Total probabilities are less than 1.0" );
|
567
601
|
} else if ( error > 1.0e-8 ) {
|
@@ -571,12 +605,16 @@ static VALUE probabilities_initialize( VALUE self, VALUE arr, VALUE offset ) {
|
|
571
605
|
}
|
572
606
|
|
573
607
|
|
574
|
-
|
608
|
+
VALUE probabilities_initialize_copy( VALUE copy, VALUE orig ) {
|
609
|
+
ProbabilityList *pl_copy;
|
610
|
+
ProbabilityList *pl_orig;
|
611
|
+
double *pr;
|
612
|
+
|
575
613
|
if (copy == orig) return copy;
|
576
|
-
|
577
|
-
|
614
|
+
pl_copy = get_probability_list( copy );
|
615
|
+
pl_orig = get_probability_list( orig );
|
578
616
|
|
579
|
-
|
617
|
+
pr = alloc_probs( pl_copy, pl_orig->slots );
|
580
618
|
pl_copy->offset = pl_orig->offset;
|
581
619
|
memcpy( pr, pl_orig->probs, pl_orig->slots * sizeof(double) );
|
582
620
|
memcpy( pl_copy->cumulative, pl_orig->cumulative, pl_orig->slots * sizeof(double) );;
|
@@ -649,10 +687,14 @@ VALUE probabilities_repeat_sum( VALUE self, VALUE nsum ) {
|
|
649
687
|
return pl_as_ruby_class( pl_repeat_sum( pl, n ), Probabilities );
|
650
688
|
}
|
651
689
|
|
652
|
-
|
690
|
+
VALUE probabilities_repeat_n_sum_k( int argc, VALUE* argv, VALUE self ) {
|
653
691
|
VALUE nsum, nkeepers, kmode;
|
692
|
+
int keep_best, n, k;
|
693
|
+
ProbabilityList *pl;
|
694
|
+
|
654
695
|
rb_scan_args( argc, argv, "21", &nsum, &nkeepers, &kmode );
|
655
|
-
|
696
|
+
|
697
|
+
keep_best = 1;
|
656
698
|
if (NIL_P(kmode)) {
|
657
699
|
keep_best = 1;
|
658
700
|
} else if ( rb_intern("keep_worst") == SYM2ID(kmode) ) {
|
@@ -661,9 +703,9 @@ static VALUE probabilities_repeat_n_sum_k( int argc, VALUE* argv, VALUE self ) {
|
|
661
703
|
rb_raise( rb_eArgError, "Keep mode not recognised" );
|
662
704
|
}
|
663
705
|
|
664
|
-
|
665
|
-
|
666
|
-
|
706
|
+
n = NUM2INT(nsum);
|
707
|
+
k = NUM2INT(nkeepers);
|
708
|
+
pl = get_probability_list( self );
|
667
709
|
return pl_as_ruby_class( pl_repeat_n_sum_k( pl, n, k, keep_best ), Probabilities );
|
668
710
|
}
|
669
711
|
|
@@ -685,14 +727,17 @@ VALUE probabilities_each( VALUE self ) {
|
|
685
727
|
|
686
728
|
VALUE probabilities_for_fair_die( VALUE self, VALUE sides ) {
|
687
729
|
int s = NUM2INT( sides );
|
730
|
+
VALUE obj;
|
731
|
+
ProbabilityList *pl;
|
732
|
+
|
688
733
|
if ( s < 1 ) {
|
689
734
|
rb_raise( rb_eArgError, "Number of sides should be 1 or more" );
|
690
735
|
}
|
691
736
|
if ( s > 100000 ) {
|
692
737
|
rb_raise( rb_eArgError, "Number of sides should be less than 100001" );
|
693
738
|
}
|
694
|
-
|
695
|
-
|
739
|
+
obj = pl_alloc( Probabilities );
|
740
|
+
pl = get_probability_list( obj );
|
696
741
|
pl->offset = 1;
|
697
742
|
alloc_probs_iv( pl, s, 1.0/s );
|
698
743
|
return obj;
|
@@ -701,17 +746,19 @@ VALUE probabilities_for_fair_die( VALUE self, VALUE sides ) {
|
|
701
746
|
VALUE probabilities_from_h( VALUE self, VALUE hash ) {
|
702
747
|
VALUE obj = pl_alloc( Probabilities );
|
703
748
|
ProbabilityList *pl = get_probability_list( obj );
|
749
|
+
double error;
|
750
|
+
|
704
751
|
// Set these up so that they get adjusted during hash iteration
|
705
|
-
pl->offset =
|
752
|
+
pl->offset = 0x7fffffff;
|
706
753
|
pl->slots = 0;
|
707
754
|
// First iteration establish min/max and validate all key/values
|
708
755
|
rb_hash_foreach( hash, validate_key_value, obj );
|
709
756
|
|
710
|
-
|
757
|
+
alloc_probs_iv( pl, pl->slots, 0.0 );
|
711
758
|
// Second iteration copy key/value pairs into structure
|
712
759
|
rb_hash_foreach( hash, copy_key_value, obj );
|
713
760
|
|
714
|
-
|
761
|
+
error = calc_cumulative( pl ) - 1.0;
|
715
762
|
if ( error < -1.0e-8 ) {
|
716
763
|
rb_raise( rb_eArgError, "Total probabilities are less than 1.0" );
|
717
764
|
} else if ( error > 1.0e-8 ) {
|
@@ -721,23 +768,33 @@ VALUE probabilities_from_h( VALUE self, VALUE hash ) {
|
|
721
768
|
}
|
722
769
|
|
723
770
|
VALUE probabilities_add_distributions( VALUE self, VALUE gdpa, VALUE gdpb ) {
|
724
|
-
assert_value_wraps_pl( gdpa );
|
725
|
-
assert_value_wraps_pl( gdpb );
|
726
771
|
ProbabilityList *pl_a = get_probability_list( gdpa );
|
727
772
|
ProbabilityList *pl_b = get_probability_list( gdpb );
|
773
|
+
assert_value_wraps_pl( gdpa );
|
774
|
+
assert_value_wraps_pl( gdpb );
|
775
|
+
pl_a = get_probability_list( gdpa );
|
776
|
+
pl_b = get_probability_list( gdpb );
|
728
777
|
return pl_as_ruby_class( pl_add_distributions( pl_a, pl_b ), Probabilities );
|
729
778
|
}
|
730
779
|
|
731
780
|
VALUE probabilities_add_distributions_mult( VALUE self, VALUE m_a, VALUE gdpa, VALUE m_b, VALUE gdpb ) {
|
781
|
+
int mul_a, mul_b;
|
782
|
+
ProbabilityList *pl_a;
|
783
|
+
ProbabilityList *pl_b;
|
784
|
+
|
732
785
|
assert_value_wraps_pl( gdpa );
|
733
786
|
assert_value_wraps_pl( gdpb );
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
787
|
+
mul_a = NUM2INT( m_a );
|
788
|
+
pl_a = get_probability_list( gdpa );
|
789
|
+
mul_b = NUM2INT( m_b );
|
790
|
+
pl_b = get_probability_list( gdpb );
|
738
791
|
return pl_as_ruby_class( pl_add_distributions_mult( mul_a, pl_a, mul_b, pl_b ), Probabilities );
|
739
792
|
}
|
740
793
|
|
794
|
+
VALUE probabilities_implemented_in( VALUE self ) {
|
795
|
+
return ID2SYM( rb_intern("c") );
|
796
|
+
}
|
797
|
+
|
741
798
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
742
799
|
//
|
743
800
|
// Setup Probabilities class for Ruby interpretter
|
@@ -765,6 +822,7 @@ void init_probabilities_class( VALUE ParentModule ) {
|
|
765
822
|
rb_define_singleton_method( Probabilities, "for_fair_die", probabilities_for_fair_die, 1 );
|
766
823
|
rb_define_singleton_method( Probabilities, "add_distributions", probabilities_add_distributions, 2 );
|
767
824
|
rb_define_singleton_method( Probabilities, "add_distributions_mult", probabilities_add_distributions_mult, 4 );
|
825
|
+
rb_define_singleton_method( Probabilities, "implemented_in", probabilities_implemented_in, 0 );
|
768
826
|
rb_define_singleton_method( Probabilities, "from_h", probabilities_from_h, 1 );
|
769
827
|
return;
|
770
828
|
}
|
@@ -16,32 +16,32 @@ typedef struct _pd {
|
|
16
16
|
double *cumulative;
|
17
17
|
} ProbabilityList;
|
18
18
|
|
19
|
-
|
19
|
+
inline int pl_min( ProbabilityList *pl );
|
20
20
|
|
21
|
-
|
21
|
+
inline int pl_max( ProbabilityList *pl );
|
22
22
|
|
23
|
-
|
23
|
+
ProbabilityList *pl_add_distributions( ProbabilityList *pl_a, ProbabilityList *pl_b );
|
24
24
|
|
25
|
-
|
25
|
+
ProbabilityList *pl_add_distributions_mult( int mul_a, ProbabilityList *pl_a, int mul_b, ProbabilityList *pl_b );
|
26
26
|
|
27
|
-
|
27
|
+
inline double pl_p_eql( ProbabilityList *pl, int target );
|
28
28
|
|
29
|
-
|
29
|
+
inline double pl_p_gt( ProbabilityList *pl, int target );
|
30
30
|
|
31
|
-
|
31
|
+
inline double pl_p_lt( ProbabilityList *pl, int target );
|
32
32
|
|
33
|
-
|
33
|
+
inline double pl_p_le( ProbabilityList *pl, int target );
|
34
34
|
|
35
|
-
|
35
|
+
inline double pl_p_ge( ProbabilityList *pl, int target );
|
36
36
|
|
37
|
-
|
37
|
+
inline double pl_expected( ProbabilityList *pl );
|
38
38
|
|
39
|
-
|
39
|
+
ProbabilityList *pl_given_ge( ProbabilityList *pl, int target );
|
40
40
|
|
41
|
-
|
41
|
+
ProbabilityList *pl_given_le( ProbabilityList *pl, int target );
|
42
42
|
|
43
|
-
|
43
|
+
ProbabilityList *pl_repeat_sum( ProbabilityList *pl, int n );
|
44
44
|
|
45
|
-
|
45
|
+
ProbabilityList *pl_repeat_n_sum_k( ProbabilityList *pl, int n, int k, int kbest );
|
46
46
|
|
47
47
|
#endif
|
data/games_dice.gemspec
CHANGED
@@ -12,25 +12,25 @@ Gem::Specification.new do |gem|
|
|
12
12
|
gem.summary = %q{Simulates and explains dice rolls from simple "1d6" to complex "roll 7 ten-sided dice, take best 3,
|
13
13
|
results of 10 roll again and add on".}
|
14
14
|
gem.homepage = "https://github.com/neilslater/games_dice"
|
15
|
+
gem.license = "MIT"
|
15
16
|
|
16
17
|
gem.add_development_dependency "rspec", ">= 2.13.0"
|
17
18
|
gem.add_development_dependency "rake", ">= 1.9.1"
|
18
19
|
gem.add_development_dependency "yard", ">= 0.8.6"
|
20
|
+
gem.add_development_dependency "rake-compiler"
|
19
21
|
|
22
|
+
# Red Carpet has a C extension, and v3.0.0 is does not compile for 1.8.7
|
20
23
|
if RUBY_VERSION < "1.9.0"
|
21
|
-
# Red Carpet v3.0.0 does not compile for 1.8.7
|
22
24
|
gem.add_development_dependency "redcarpet", ">=2.3.0", "<3.0.0"
|
23
25
|
else
|
24
26
|
gem.add_development_dependency "redcarpet", ">=2.3.0"
|
25
27
|
end
|
26
28
|
|
27
|
-
gem.add_development_dependency "rake-compiler"
|
28
|
-
|
29
29
|
gem.add_dependency "parslet", ">= 1.5.0"
|
30
30
|
|
31
31
|
gem.files = `git ls-files`.split($/)
|
32
32
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
33
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
34
33
|
gem.extensions = gem.files.grep(%r{/extconf\.rb$})
|
34
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
35
35
|
gem.require_paths = ["lib"]
|
36
36
|
end
|
data/lib/games_dice.rb
CHANGED
@@ -26,7 +26,7 @@ class GamesDice::Probabilities
|
|
26
26
|
# @return [GamesDice::Probabilities]
|
27
27
|
def initialize( probs = [1.0], offset = 0 )
|
28
28
|
# This should *probably* be validated in future, but that would impact performance
|
29
|
-
@probs = probs
|
29
|
+
@probs = check_probs_array probs.clone
|
30
30
|
@offset = offset
|
31
31
|
end
|
32
32
|
|
@@ -218,6 +218,13 @@ class GamesDice::Probabilities
|
|
218
218
|
GamesDice::Probabilities.new( new_probs, combined_min )
|
219
219
|
end
|
220
220
|
|
221
|
+
# Returns a symbol for the language name that this class is implemented in. The C version of the
|
222
|
+
# code is noticeably faster when dealing with larger numbers of possible results.
|
223
|
+
# @return [Symbol] Either :c or :ruby
|
224
|
+
def self.implemented_in
|
225
|
+
:ruby
|
226
|
+
end
|
227
|
+
|
221
228
|
# Adds a distribution to itself repeatedly, to simulate a number of dice
|
222
229
|
# results being summed.
|
223
230
|
# @param [Integer] n Number of repetitions, must be at least 1
|
@@ -286,6 +293,20 @@ class GamesDice::Probabilities
|
|
286
293
|
|
287
294
|
private
|
288
295
|
|
296
|
+
def check_probs_array probs_array
|
297
|
+
probs_array.map!{ |n| Float(n) }
|
298
|
+
total = probs_array.inject(0.0) do |t,x|
|
299
|
+
if x < 0.0 || x > 1.0
|
300
|
+
raise ArgumentError, "Found probability value #{x} which is not in range 0.0..1.0"
|
301
|
+
end
|
302
|
+
t+x
|
303
|
+
end
|
304
|
+
if (total-1.0).abs > 1e-6
|
305
|
+
raise ArgumentError, "Total probabilities too far from 1.0 for a valid distribution"
|
306
|
+
end
|
307
|
+
probs_array
|
308
|
+
end
|
309
|
+
|
289
310
|
def calc_keep_distributions k, q, kmode
|
290
311
|
if kmode == :keep_best
|
291
312
|
keep_distributions = [ GamesDice::Probabilities.new( [1.0], q * k ) ]
|
data/lib/games_dice/version.rb
CHANGED
data/spec/probability_spec.rb
CHANGED
@@ -104,6 +104,13 @@ describe GamesDice::Probabilities do
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
+
describe "#implemented_in" do
|
108
|
+
it "should be either :c or :ruby" do
|
109
|
+
lang = GamesDice::Probabilities.implemented_in
|
110
|
+
lang.should be_a Symbol
|
111
|
+
[:c, :ruby].member?( lang ).should be_true
|
112
|
+
end
|
113
|
+
end
|
107
114
|
end # describe "class methods"
|
108
115
|
|
109
116
|
describe "instance methods" do
|
metadata
CHANGED
@@ -1,134 +1,121 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: games_dice
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.5
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 3
|
9
|
-
- 3
|
10
|
-
version: 0.3.3
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Neil Slater
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2013-07-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: rspec
|
22
|
-
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
24
17
|
none: false
|
25
|
-
requirements:
|
26
|
-
- -
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
hash: 59
|
29
|
-
segments:
|
30
|
-
- 2
|
31
|
-
- 13
|
32
|
-
- 0
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
33
21
|
version: 2.13.0
|
34
22
|
type: :development
|
35
|
-
version_requirements: *id001
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: rake
|
38
23
|
prerelease: false
|
39
|
-
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.13.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
40
33
|
none: false
|
41
|
-
requirements:
|
42
|
-
- -
|
43
|
-
- !ruby/object:Gem::Version
|
44
|
-
hash: 49
|
45
|
-
segments:
|
46
|
-
- 1
|
47
|
-
- 9
|
48
|
-
- 1
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
49
37
|
version: 1.9.1
|
50
38
|
type: :development
|
51
|
-
|
52
|
-
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.9.1
|
46
|
+
- !ruby/object:Gem::Dependency
|
53
47
|
name: yard
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.8.6
|
54
|
+
type: :development
|
54
55
|
prerelease: false
|
55
|
-
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
56
57
|
none: false
|
57
|
-
requirements:
|
58
|
-
- -
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
hash: 51
|
61
|
-
segments:
|
62
|
-
- 0
|
63
|
-
- 8
|
64
|
-
- 6
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
65
61
|
version: 0.8.6
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake-compiler
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
66
70
|
type: :development
|
67
|
-
version_requirements: *id003
|
68
|
-
- !ruby/object:Gem::Dependency
|
69
|
-
name: redcarpet
|
70
71
|
prerelease: false
|
71
|
-
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: redcarpet
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
72
81
|
none: false
|
73
|
-
requirements:
|
74
|
-
- -
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
hash: 3
|
77
|
-
segments:
|
78
|
-
- 2
|
79
|
-
- 3
|
80
|
-
- 0
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
81
85
|
version: 2.3.0
|
82
|
-
- - <
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
hash: 7
|
85
|
-
segments:
|
86
|
-
- 3
|
87
|
-
- 0
|
88
|
-
- 0
|
89
|
-
version: 3.0.0
|
90
86
|
type: :development
|
91
|
-
version_requirements: *id004
|
92
|
-
- !ruby/object:Gem::Dependency
|
93
|
-
name: rake-compiler
|
94
87
|
prerelease: false
|
95
|
-
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
96
89
|
none: false
|
97
|
-
requirements:
|
98
|
-
- -
|
99
|
-
- !ruby/object:Gem::Version
|
100
|
-
|
101
|
-
|
102
|
-
- 0
|
103
|
-
version: "0"
|
104
|
-
type: :development
|
105
|
-
version_requirements: *id005
|
106
|
-
- !ruby/object:Gem::Dependency
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 2.3.0
|
94
|
+
- !ruby/object:Gem::Dependency
|
107
95
|
name: parslet
|
108
|
-
|
109
|
-
requirement: &id006 !ruby/object:Gem::Requirement
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
110
97
|
none: false
|
111
|
-
requirements:
|
112
|
-
- -
|
113
|
-
- !ruby/object:Gem::Version
|
114
|
-
hash: 3
|
115
|
-
segments:
|
116
|
-
- 1
|
117
|
-
- 5
|
118
|
-
- 0
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
119
101
|
version: 1.5.0
|
120
102
|
type: :runtime
|
121
|
-
|
122
|
-
|
123
|
-
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.5.0
|
110
|
+
description: A library for simulating dice. Use it to construct dice-rolling systems
|
111
|
+
used in role-playing and board games.
|
112
|
+
email:
|
124
113
|
- slobo777@gmail.com
|
125
114
|
executables: []
|
126
|
-
|
127
|
-
extensions:
|
115
|
+
extensions:
|
128
116
|
- ext/games_dice/extconf.rb
|
129
117
|
extra_rdoc_files: []
|
130
|
-
|
131
|
-
files:
|
118
|
+
files:
|
132
119
|
- .gitignore
|
133
120
|
- .travis.yml
|
134
121
|
- Gemfile
|
@@ -164,39 +151,38 @@ files:
|
|
164
151
|
- spec/readme_spec.rb
|
165
152
|
- spec/reroll_rule_spec.rb
|
166
153
|
homepage: https://github.com/neilslater/games_dice
|
167
|
-
licenses:
|
168
|
-
|
154
|
+
licenses:
|
155
|
+
- MIT
|
169
156
|
post_install_message:
|
170
157
|
rdoc_options: []
|
171
|
-
|
172
|
-
require_paths:
|
158
|
+
require_paths:
|
173
159
|
- lib
|
174
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
160
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
175
161
|
none: false
|
176
|
-
requirements:
|
177
|
-
- -
|
178
|
-
- !ruby/object:Gem::Version
|
179
|
-
|
180
|
-
segments:
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
segments:
|
181
167
|
- 0
|
182
|
-
|
183
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
|
+
hash: -335297493340390599
|
169
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
184
170
|
none: false
|
185
|
-
requirements:
|
186
|
-
- -
|
187
|
-
- !ruby/object:Gem::Version
|
188
|
-
|
189
|
-
segments:
|
171
|
+
requirements:
|
172
|
+
- - ! '>='
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
segments:
|
190
176
|
- 0
|
191
|
-
|
177
|
+
hash: -335297493340390599
|
192
178
|
requirements: []
|
193
|
-
|
194
179
|
rubyforge_project:
|
195
180
|
rubygems_version: 1.8.24
|
196
181
|
signing_key:
|
197
182
|
specification_version: 3
|
198
|
-
summary: Simulates and explains dice rolls from simple "1d6" to complex "roll 7 ten-sided
|
199
|
-
|
183
|
+
summary: Simulates and explains dice rolls from simple "1d6" to complex "roll 7 ten-sided
|
184
|
+
dice, take best 3, results of 10 roll again and add on".
|
185
|
+
test_files:
|
200
186
|
- spec/bunch_spec.rb
|
201
187
|
- spec/complex_die_spec.rb
|
202
188
|
- spec/dice_spec.rb
|