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