games_dice 0.0.3 → 0.0.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/games_dice.gemspec +4 -2
- data/lib/games_dice.rb +3 -0
- data/lib/games_dice/bunch.rb +275 -320
- data/lib/games_dice/complex_die.rb +226 -269
- data/lib/games_dice/constants.rb +16 -0
- data/lib/games_dice/dice.rb +43 -0
- data/lib/games_dice/die.rb +58 -92
- data/lib/games_dice/die_result.rb +3 -15
- data/lib/games_dice/map_rule.rb +41 -43
- data/lib/games_dice/probabilities.rb +97 -0
- data/lib/games_dice/reroll_rule.rb +41 -58
- data/lib/games_dice/version.rb +1 -1
- data/spec/bunch_spec.rb +196 -188
- data/spec/complex_die_spec.rb +77 -68
- data/spec/dice_spec.rb +34 -0
- data/spec/die_spec.rb +25 -29
- data/spec/probability_spec.rb +265 -0
- metadata +31 -8
data/spec/complex_die_spec.rb
CHANGED
@@ -110,60 +110,64 @@ describe GamesDice::ComplexDie do
|
|
110
110
|
|
111
111
|
it "should calculate an expected result" do
|
112
112
|
die = GamesDice::ComplexDie.new(10, :rerolls => [GamesDice::RerollRule.new(10, :<=, :reroll_add),GamesDice::RerollRule.new(1, :>=, :reroll_subtract)] )
|
113
|
-
die.
|
113
|
+
die.probabilities.expected.should be_within(1e-10).of 5.5
|
114
114
|
|
115
115
|
die = GamesDice::ComplexDie.new(10, :rerolls => [GamesDice::RerollRule.new(1, :<=, :reroll_use_best, 1)] )
|
116
|
-
die.
|
116
|
+
die.probabilities.expected.should be_within(1e-10).of 7.15
|
117
117
|
|
118
118
|
die = GamesDice::ComplexDie.new(10, :rerolls => [GamesDice::RerollRule.new(1, :<=, :reroll_use_worst, 2)] )
|
119
|
-
die.
|
119
|
+
die.probabilities.expected.should be_within(1e-10).of 3.025
|
120
120
|
|
121
121
|
die = GamesDice::ComplexDie.new(6, :rerolls => [GamesDice::RerollRule.new(6, :<=, :reroll_add)] )
|
122
|
-
die.
|
122
|
+
die.probabilities.expected.should be_within(1e-10).of 4.2
|
123
123
|
|
124
124
|
die = GamesDice::ComplexDie.new(8, :rerolls => [GamesDice::RerollRule.new(1, :>=, :reroll_use_best)] )
|
125
|
-
die.
|
125
|
+
die.probabilities.expected.should be_within(1e-10).of 5.0
|
126
126
|
|
127
127
|
die = GamesDice::ComplexDie.new(4, :rerolls => [GamesDice::RerollRule.new(1, :>=, :reroll_replace, 1)] )
|
128
|
-
die.
|
128
|
+
die.probabilities.expected.should be_within(1e-10).of 2.875
|
129
129
|
end
|
130
130
|
|
131
131
|
it "should calculate probabilities of each possible result" do
|
132
132
|
die = GamesDice::ComplexDie.new(6, :rerolls => [GamesDice::RerollRule.new(7, :>, :reroll_add, 1)] )
|
133
|
-
die.probabilities
|
134
|
-
|
135
|
-
|
133
|
+
probs = die.probabilities.to_h
|
134
|
+
probs[11].should be_within(1e-10).of 2/36.0
|
135
|
+
probs[8].should be_within(1e-10).of 5/36.0
|
136
|
+
probs.values.inject(:+).should be_within(1e-9).of 1.0
|
136
137
|
|
137
138
|
die = GamesDice::ComplexDie.new(10, :rerolls => [GamesDice::RerollRule.new(10, :<=, :reroll_add)] )
|
138
|
-
die.probabilities
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
139
|
+
probs = die.probabilities.to_h
|
140
|
+
probs[8].should be_within(1e-10).of 0.1
|
141
|
+
probs[10].should be_false
|
142
|
+
probs[13].should be_within(1e-10).of 0.01
|
143
|
+
probs[27].should be_within(1e-10).of 0.001
|
144
|
+
probs.values.inject(:+).should be_within(1e-9).of 1.0
|
143
145
|
|
144
146
|
die = GamesDice::ComplexDie.new(6, :rerolls => [GamesDice::RerollRule.new(1, :>=, :reroll_replace, 1)] )
|
145
|
-
die.probabilities
|
146
|
-
|
147
|
-
|
147
|
+
probs = die.probabilities.to_h
|
148
|
+
probs[1].should be_within(1e-10).of 1/36.0
|
149
|
+
probs[2].should be_within(1e-10).of 7/36.0
|
150
|
+
probs.values.inject(:+).should be_within(1e-9).of 1.0
|
148
151
|
end
|
149
152
|
|
150
153
|
it "should calculate aggregate probabilities" do
|
151
154
|
die = GamesDice::ComplexDie.new(6, :rerolls => [GamesDice::RerollRule.new(7, :>, :reroll_add, 1)] )
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
155
|
+
probs = die.probabilities
|
156
|
+
probs.p_gt(7).should be_within(1e-10).of 15/36.0
|
157
|
+
probs.p_gt(-10).should == 1.0
|
158
|
+
probs.p_gt(12).should == 0.0
|
159
|
+
|
160
|
+
probs.p_ge(7).should be_within(1e-10).of 21/36.0
|
161
|
+
probs.p_ge(2).should == 1.0
|
162
|
+
probs.p_ge(15).should == 0.0
|
163
|
+
|
164
|
+
probs.p_lt(7).should be_within(1e-10).of 15/36.0
|
165
|
+
probs.p_lt(-10).should == 0.0
|
166
|
+
probs.p_lt(13).should == 1.0
|
167
|
+
|
168
|
+
probs.p_le(7).should be_within(1e-10).of 21/36.0
|
169
|
+
probs.p_le(1).should == 0.0
|
170
|
+
probs.p_le(12).should == 1.0
|
167
171
|
end
|
168
172
|
end
|
169
173
|
|
@@ -192,34 +196,36 @@ describe GamesDice::ComplexDie do
|
|
192
196
|
|
193
197
|
it "should calculate an expected result" do
|
194
198
|
die = GamesDice::ComplexDie.new(10, :maps => [GamesDice::MapRule.new(7, :<=, 1, 'S'),GamesDice::MapRule.new(1, :>=, -1, 'F')] )
|
195
|
-
die.
|
199
|
+
die.probabilities.expected.should be_within(1e-10).of 0.3
|
196
200
|
end
|
197
201
|
|
198
202
|
it "should calculate probabilities of each possible result" do
|
199
203
|
die = GamesDice::ComplexDie.new(10, :maps => [GamesDice::MapRule.new(7, :<=, 1, 'S'),GamesDice::MapRule.new(1, :>=, -1, 'F')] )
|
200
|
-
die.probabilities
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
+
probs_hash = die.probabilities.to_h
|
205
|
+
probs_hash[1].should be_within(1e-10).of 0.4
|
206
|
+
probs_hash[0].should be_within(1e-10).of 0.5
|
207
|
+
probs_hash[-1].should be_within(1e-10).of 0.1
|
208
|
+
probs_hash.values.inject(:+).should be_within(1e-9).of 1.0
|
204
209
|
end
|
205
210
|
|
206
211
|
it "should calculate aggregate probabilities" do
|
207
212
|
die = GamesDice::ComplexDie.new(10, :maps => [GamesDice::MapRule.new(7, :<=, 1, 'S'),GamesDice::MapRule.new(1, :>=, -1, 'F')] )
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
213
|
+
probs = die.probabilities
|
214
|
+
probs.p_gt(-2).should == 1.0
|
215
|
+
probs.p_gt(-1).should be_within(1e-10).of 0.9
|
216
|
+
probs.p_gt(1).should == 0.0
|
217
|
+
|
218
|
+
probs.p_ge(1).should be_within(1e-10).of 0.4
|
219
|
+
probs.p_ge(-1).should == 1.0
|
220
|
+
probs.p_ge(2).should == 0.0
|
221
|
+
|
222
|
+
probs.p_lt(1).should be_within(1e-10).of 0.6
|
223
|
+
probs.p_lt(-1).should == 0.0
|
224
|
+
probs.p_lt(2).should == 1.0
|
225
|
+
|
226
|
+
probs.p_le(-1).should be_within(1e-10).of 0.1
|
227
|
+
probs.p_le(-2).should == 0.0
|
228
|
+
probs.p_le(1).should == 1.0
|
223
229
|
end
|
224
230
|
end
|
225
231
|
|
@@ -237,31 +243,34 @@ describe GamesDice::ComplexDie do
|
|
237
243
|
end
|
238
244
|
|
239
245
|
it "should calculate an expected result" do
|
240
|
-
@die.
|
246
|
+
@die.probabilities.expected.should be_within(1e-10).of 4/36.0
|
241
247
|
end
|
242
248
|
|
243
249
|
it "should calculate probabilities of each possible result" do
|
244
|
-
@die.probabilities
|
245
|
-
|
246
|
-
|
250
|
+
probs_hash = @die.probabilities.to_h
|
251
|
+
probs_hash[1].should be_within(1e-10).of 4/36.0
|
252
|
+
probs_hash[0].should be_within(1e-10).of 32/36.0
|
253
|
+
probs_hash.values.inject(:+).should be_within(1e-9).of 1.0
|
247
254
|
end
|
248
255
|
|
249
256
|
it "should calculate aggregate probabilities" do
|
250
|
-
@die.
|
251
|
-
|
252
|
-
|
257
|
+
probs = @die.probabilities
|
258
|
+
|
259
|
+
probs.p_gt(0).should be_within(1e-10).of 4/36.0
|
260
|
+
probs.p_gt(-2).should == 1.0
|
261
|
+
probs.p_gt(1).should == 0.0
|
253
262
|
|
254
|
-
|
255
|
-
|
256
|
-
|
263
|
+
probs.p_ge(1).should be_within(1e-10).of 4/36.0
|
264
|
+
probs.p_ge(-1).should == 1.0
|
265
|
+
probs.p_ge(2).should == 0.0
|
257
266
|
|
258
|
-
|
259
|
-
|
260
|
-
|
267
|
+
probs.p_lt(1).should be_within(1e-10).of 32/36.0
|
268
|
+
probs.p_lt(0).should == 0.0
|
269
|
+
probs.p_lt(2).should == 1.0
|
261
270
|
|
262
|
-
|
263
|
-
|
264
|
-
|
271
|
+
probs.p_le(0).should be_within(1e-10).of 32/36.0
|
272
|
+
probs.p_le(-1).should == 0.0
|
273
|
+
probs.p_le(1).should == 1.0
|
265
274
|
end
|
266
275
|
|
267
276
|
it "should apply mapping to final re-rolled result" do
|
data/spec/dice_spec.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'games_dice'
|
2
|
+
|
3
|
+
describe GamesDice::Dice do
|
4
|
+
|
5
|
+
describe "dice scheme" do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
srand(67809)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '1d10+2' do
|
12
|
+
let(:dice) { GamesDice::Dice.new( [ { :sides => 10, :ndice => 1 } ], 2 ) }
|
13
|
+
|
14
|
+
it "should simulate rolling a ten-sided die, and adding two to each result" do
|
15
|
+
[5,4,10,10,7,5,9].each do |expected_total|
|
16
|
+
dice.roll.should == expected_total
|
17
|
+
dice.result.should == expected_total
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '2d6+6' do
|
23
|
+
let(:dice) { GamesDice::Dice.new( [ { :sides => 6, :ndice => 2 } ], 6) }
|
24
|
+
|
25
|
+
it "should simulate rolling two six-sided dice and adding six to the result" do
|
26
|
+
[15,12,17,15,13,13,16].each do |expected_total|
|
27
|
+
dice.roll.should == expected_total
|
28
|
+
dice.result.should == expected_total
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
data/spec/die_spec.rb
CHANGED
@@ -24,8 +24,6 @@ describe GamesDice::Die do
|
|
24
24
|
die.min.should == 1
|
25
25
|
die.max.should == 6
|
26
26
|
die.sides.should == 6
|
27
|
-
die.probabilities.should == { 1 => 1.0/6, 2 => 1.0/6, 3 => 1.0/6, 4 => 1.0/6, 5 => 1.0/6, 6 => 1.0/6 }
|
28
|
-
die.expected_result.should == 3.5
|
29
27
|
end
|
30
28
|
|
31
29
|
it "should accept any object with a rand(Integer) method as the second param" do
|
@@ -56,39 +54,37 @@ describe GamesDice::Die do
|
|
56
54
|
end
|
57
55
|
end
|
58
56
|
|
59
|
-
describe "#expected_result" do
|
60
|
-
it "should calculate correct weighted mean" do
|
61
|
-
die = GamesDice::Die.new(20)
|
62
|
-
die.expected_result.should be_within(1e-10).of 10.5
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
57
|
describe "#probabilities" do
|
67
|
-
it "should
|
58
|
+
it "should return the die's probability distribution as a GamesDice::Probabilities object" do
|
68
59
|
die = GamesDice::Die.new(6)
|
69
|
-
die.probabilities
|
70
|
-
die.probabilities
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
60
|
+
die.probabilities.is_a?( GamesDice::Probabilities ).should be_true
|
61
|
+
probs = die.probabilities
|
62
|
+
|
63
|
+
probs.p_eql(1).should be_within(1e-10).of 1/6.0
|
64
|
+
probs.p_eql(2).should be_within(1e-10).of 1/6.0
|
65
|
+
probs.p_eql(3).should be_within(1e-10).of 1/6.0
|
66
|
+
probs.p_eql(4).should be_within(1e-10).of 1/6.0
|
67
|
+
probs.p_eql(5).should be_within(1e-10).of 1/6.0
|
68
|
+
probs.p_eql(6).should be_within(1e-10).of 1/6.0
|
69
|
+
probs.to_h.values.inject(:+).should be_within(1e-9).of 1.0
|
70
|
+
|
71
|
+
probs.p_gt(6).should == 0.0
|
72
|
+
probs.p_gt(-20).should == 1.0
|
73
|
+
probs.p_gt(4).should be_within(1e-10).of 2/6.0
|
76
74
|
|
77
|
-
|
78
|
-
|
79
|
-
|
75
|
+
probs.p_ge(20).should == 0.0
|
76
|
+
probs.p_ge(1).should == 1.0
|
77
|
+
probs.p_ge(4).should be_within(1e-10).of 0.5
|
80
78
|
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
probs.p_le(6).should == 1.0
|
80
|
+
probs.p_le(-3).should == 0.0
|
81
|
+
probs.p_le(5).should be_within(1e-10).of 5/6.0
|
84
82
|
|
85
|
-
|
86
|
-
|
87
|
-
|
83
|
+
probs.p_lt(7).should == 1.0
|
84
|
+
probs.p_lt(1).should == 0.0
|
85
|
+
probs.p_lt(3).should be_within(1e-10).of 2/6.0
|
88
86
|
|
89
|
-
|
90
|
-
die.probability_lt(1).should == 0.0
|
91
|
-
die.probability_lt(3).should be_within(1e-10).of 2/6.0
|
87
|
+
probs.expected.should be_within(1e-10).of 3.5
|
92
88
|
end
|
93
89
|
end
|
94
90
|
|
@@ -0,0 +1,265 @@
|
|
1
|
+
require 'games_dice'
|
2
|
+
|
3
|
+
# A valid distribution is:
|
4
|
+
# A hash
|
5
|
+
# Keys are all Integers
|
6
|
+
# Values are all positive Floats, between 0.0 and 1.0
|
7
|
+
# Sum of values is 1.0
|
8
|
+
RSpec::Matchers.define :be_valid_distribution do
|
9
|
+
match do |given|
|
10
|
+
@error = nil
|
11
|
+
if ! given.is_a?(Hash)
|
12
|
+
@error = "distribution should be a Hash, but it is a #{given.class}"
|
13
|
+
elsif given.keys.any? { |k| ! k.is_a?(Fixnum) }
|
14
|
+
bad_key = given.keys.first { |k| ! k.is_a?(Fixnum) }
|
15
|
+
@error = "all keys should be Fixnums, but found '#{bad_key.inspect}' which is a #{bad_key.class}"
|
16
|
+
elsif given.values.any? { |v| ! v.is_a?(Float) }
|
17
|
+
bad_value = given.values.first { |v| ! v.is_a?(Float) }
|
18
|
+
@error = "all values should be Floats, but found '#{bad_value.inspect}' which is a #{bad_value.class}"
|
19
|
+
elsif given.values.any? { |v| v < 0.0 || v > 1.0 }
|
20
|
+
bad_value = given.values.first { |v| v < 0.0 || v > 1.0 }
|
21
|
+
@error = "all values should be in range (0.0..1.0), but found #{bad_value}"
|
22
|
+
elsif (1.0 - given.values.inject(:+)).abs > 1e-6
|
23
|
+
total_probs = given.values.inject(:+)
|
24
|
+
@error = "sum of values should be 1.0, but got #{total_probs}"
|
25
|
+
end
|
26
|
+
! @error
|
27
|
+
end
|
28
|
+
|
29
|
+
failure_message_for_should do |given|
|
30
|
+
@error ? @error : 'Distribution is valid and complete'
|
31
|
+
end
|
32
|
+
|
33
|
+
failure_message_for_should_not do |given|
|
34
|
+
@error ? @error : 'Distribution is valid and complete'
|
35
|
+
end
|
36
|
+
|
37
|
+
description do |given|
|
38
|
+
"a hash describing a complete discrete probability distribution of integers"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe GamesDice::Probabilities do
|
43
|
+
|
44
|
+
describe "class methods" do
|
45
|
+
|
46
|
+
describe "#new" do
|
47
|
+
it "should create a new distribution from a hash" do
|
48
|
+
p = GamesDice::Probabilities.new( { 1 => 1.0 } )
|
49
|
+
p.is_a?( GamesDice::Probabilities ).should be_true
|
50
|
+
p.to_h.should be_valid_distribution
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#for_fair_die" do
|
55
|
+
it "should create a new distribution based on number of sides" do
|
56
|
+
p2 = GamesDice::Probabilities.for_fair_die( 2 )
|
57
|
+
p2.is_a?( GamesDice::Probabilities ).should be_true
|
58
|
+
p2.to_h.should == { 1 => 0.5, 2 => 0.5 }
|
59
|
+
(1..20).each do |sides|
|
60
|
+
p = GamesDice::Probabilities.for_fair_die( sides )
|
61
|
+
p.is_a?( GamesDice::Probabilities ).should be_true
|
62
|
+
h = p.to_h
|
63
|
+
h.should be_valid_distribution
|
64
|
+
h.keys.count.should == sides
|
65
|
+
h.values.each { |v| v.should be_within(1e-10).of 1.0/sides }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#add_distributions" do
|
71
|
+
it "should combine two distributions to create a third one" do
|
72
|
+
d4a = GamesDice::Probabilities.new( { 1 => 1.0/4, 2 => 1.0/4, 3 => 1.0/4, 4 => 1.0/4 } )
|
73
|
+
d4b = GamesDice::Probabilities.new( { 1 => 1.0/10, 2 => 2.0/10, 3 => 3.0/10, 4 => 4.0/10 } )
|
74
|
+
p = GamesDice::Probabilities.add_distributions( d4a, d4b )
|
75
|
+
p.to_h.should be_valid_distribution
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should calculate a classic 2d6 distribution accurately" do
|
79
|
+
d6 = GamesDice::Probabilities.for_fair_die( 6 )
|
80
|
+
p = GamesDice::Probabilities.add_distributions( d6, d6 )
|
81
|
+
p.to_h.should be_valid_distribution
|
82
|
+
p.to_h[2].should be_within(1e-9).of 1.0/36
|
83
|
+
p.to_h[3].should be_within(1e-9).of 2.0/36
|
84
|
+
p.to_h[4].should be_within(1e-9).of 3.0/36
|
85
|
+
p.to_h[5].should be_within(1e-9).of 4.0/36
|
86
|
+
p.to_h[6].should be_within(1e-9).of 5.0/36
|
87
|
+
p.to_h[7].should be_within(1e-9).of 6.0/36
|
88
|
+
p.to_h[8].should be_within(1e-9).of 5.0/36
|
89
|
+
p.to_h[9].should be_within(1e-9).of 4.0/36
|
90
|
+
p.to_h[10].should be_within(1e-9).of 3.0/36
|
91
|
+
p.to_h[11].should be_within(1e-9).of 2.0/36
|
92
|
+
p.to_h[12].should be_within(1e-9).of 1.0/36
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end # describe "class methods"
|
97
|
+
|
98
|
+
describe "instance methods" do
|
99
|
+
let(:p2) { GamesDice::Probabilities.for_fair_die( 2 ) }
|
100
|
+
let(:p4) { GamesDice::Probabilities.for_fair_die( 4 ) }
|
101
|
+
let(:p6) { GamesDice::Probabilities.for_fair_die( 6 ) }
|
102
|
+
let(:p10) { GamesDice::Probabilities.for_fair_die( 10 ) }
|
103
|
+
let(:pa) { GamesDice::Probabilities.new( { -1 => 0.4, 0 => 0.2, 1 => 0.4 } ) }
|
104
|
+
|
105
|
+
describe "#p_eql" do
|
106
|
+
it "should return probability of getting a number inside the range" do
|
107
|
+
p2.p_eql(2).should be_within(1.0e-9).of 0.5
|
108
|
+
p4.p_eql(1).should be_within(1.0e-9).of 0.25
|
109
|
+
p6.p_eql(6).should be_within(1.0e-9).of 1.0/6
|
110
|
+
p10.p_eql(3).should be_within(1.0e-9).of 0.1
|
111
|
+
pa.p_eql(-1).should be_within(1.0e-9).of 0.4
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should return 0.0 for values not covered by distribution" do
|
115
|
+
p2.p_eql(3).should == 0.0
|
116
|
+
p4.p_eql(-1).should == 0.0
|
117
|
+
p6.p_eql(8).should == 0.0
|
118
|
+
p10.p_eql(11).should == 0.0
|
119
|
+
pa.p_eql(2).should == 0.0
|
120
|
+
end
|
121
|
+
end # describe "#p_eql"
|
122
|
+
|
123
|
+
describe "#p_gt" do
|
124
|
+
it "should return probability of getting a number greater than target" do
|
125
|
+
p2.p_gt(1).should be_within(1.0e-9).of 0.5
|
126
|
+
p4.p_gt(3).should be_within(1.0e-9).of 0.25
|
127
|
+
p6.p_gt(2).should be_within(1.0e-9).of 4.0/6
|
128
|
+
p10.p_gt(6).should be_within(1.0e-9).of 0.4
|
129
|
+
|
130
|
+
# Trying more than one, due to unusual error seen in complex_die_spec when calculating probabilities
|
131
|
+
pa.p_gt(-2).should be_within(1.0e-9).of 1.0
|
132
|
+
pa.p_gt(-1).should be_within(1.0e-9).of 0.6
|
133
|
+
pa.p_gt(0).should be_within(1.0e-9).of 0.4
|
134
|
+
pa.p_gt(1).should be_within(1.0e-9).of 0.0
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should return 0.0 when the target number is equal or higher than maximum possible" do
|
138
|
+
p2.p_gt(2).should == 0.0
|
139
|
+
p4.p_gt(5).should == 0.0
|
140
|
+
p6.p_gt(6).should == 0.0
|
141
|
+
p10.p_gt(20).should == 0.0
|
142
|
+
pa.p_gt(3).should == 0.0
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should return 1.0 when the target number is lower than minimum" do
|
146
|
+
p2.p_gt(0).should == 1.0
|
147
|
+
p4.p_gt(-5).should == 1.0
|
148
|
+
p6.p_gt(0).should == 1.0
|
149
|
+
p10.p_gt(-200).should == 1.0
|
150
|
+
pa.p_gt(-2).should == 1.0
|
151
|
+
end
|
152
|
+
end # describe "#p_gt"
|
153
|
+
|
154
|
+
describe "#p_ge" do
|
155
|
+
it "should return probability of getting a number greater than or equal to target" do
|
156
|
+
p2.p_ge(2).should be_within(1.0e-9).of 0.5
|
157
|
+
p4.p_ge(3).should be_within(1.0e-9).of 0.5
|
158
|
+
p6.p_ge(2).should be_within(1.0e-9).of 5.0/6
|
159
|
+
p10.p_ge(6).should be_within(1.0e-9).of 0.5
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should return 0.0 when the target number is higher than maximum possible" do
|
163
|
+
p2.p_ge(6).should == 0.0
|
164
|
+
p4.p_ge(5).should == 0.0
|
165
|
+
p6.p_ge(7).should == 0.0
|
166
|
+
p10.p_ge(20).should == 0.0
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should return 1.0 when the target number is lower than or equal to minimum possible" do
|
170
|
+
p2.p_ge(1).should == 1.0
|
171
|
+
p4.p_ge(-5).should == 1.0
|
172
|
+
p6.p_ge(1).should == 1.0
|
173
|
+
p10.p_ge(-200).should == 1.0
|
174
|
+
end
|
175
|
+
end # describe "#p_ge"
|
176
|
+
|
177
|
+
describe "#p_le" do
|
178
|
+
it "should return probability of getting a number less than or equal to target" do
|
179
|
+
p2.p_le(1).should be_within(1.0e-9).of 0.5
|
180
|
+
p4.p_le(2).should be_within(1.0e-9).of 0.5
|
181
|
+
p6.p_le(2).should be_within(1.0e-9).of 2.0/6
|
182
|
+
p10.p_le(6).should be_within(1.0e-9).of 0.6
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should return 1.0 when the target number is higher than or equal to maximum possible" do
|
186
|
+
p2.p_le(6).should == 1.0
|
187
|
+
p4.p_le(4).should == 1.0
|
188
|
+
p6.p_le(7).should == 1.0
|
189
|
+
p10.p_le(10).should == 1.0
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should return 0.0 when the target number is lower than minimum possible" do
|
193
|
+
p2.p_le(0).should == 0.0
|
194
|
+
p4.p_le(-5).should == 0.0
|
195
|
+
p6.p_le(0).should == 0.0
|
196
|
+
p10.p_le(-200).should == 0.0
|
197
|
+
end
|
198
|
+
end # describe "#p_le"
|
199
|
+
|
200
|
+
describe "#p_lt" do
|
201
|
+
it "should return probability of getting a number less than target" do
|
202
|
+
p2.p_lt(2).should be_within(1.0e-9).of 0.5
|
203
|
+
p4.p_lt(3).should be_within(1.0e-9).of 0.5
|
204
|
+
p6.p_lt(2).should be_within(1.0e-9).of 1/6.0
|
205
|
+
p10.p_lt(6).should be_within(1.0e-9).of 0.5
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should return 1.0 when the target number is higher than maximum possible" do
|
209
|
+
p2.p_lt(6).should == 1.0
|
210
|
+
p4.p_lt(5).should == 1.0
|
211
|
+
p6.p_lt(7).should == 1.0
|
212
|
+
p10.p_lt(20).should == 1.0
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should return 0.0 when the target number is lower than or equal to minimum possible" do
|
216
|
+
p2.p_lt(1).should == 0.0
|
217
|
+
p4.p_lt(-5).should == 0.0
|
218
|
+
p6.p_lt(1).should == 0.0
|
219
|
+
p10.p_lt(-200).should == 0.0
|
220
|
+
end
|
221
|
+
end # describe "#p_lt"
|
222
|
+
|
223
|
+
describe "#to_h" do
|
224
|
+
# This is used loads in other tests
|
225
|
+
it "should represent a valid distribution with each integer result associated with its probability" do
|
226
|
+
p2.to_h.should be_valid_distribution
|
227
|
+
p4.to_h.should be_valid_distribution
|
228
|
+
p6.to_h.should be_valid_distribution
|
229
|
+
p10.to_h.should be_valid_distribution
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "#min" do
|
234
|
+
it "should return lowest possible result allowed by distribution" do
|
235
|
+
p2.min.should == 1
|
236
|
+
p4.min.should == 1
|
237
|
+
p6.min.should == 1
|
238
|
+
p10.min.should == 1
|
239
|
+
GamesDice::Probabilities.add_distributions( p6, p10 ).min.should == 2
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe "#max" do
|
244
|
+
it "should return highest possible result allowed by distribution" do
|
245
|
+
p2.max.should == 2
|
246
|
+
p4.max.should == 4
|
247
|
+
p6.max.should == 6
|
248
|
+
p10.max.should == 10
|
249
|
+
GamesDice::Probabilities.add_distributions( p6, p10 ).max.should == 16
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
describe "#expected" do
|
254
|
+
it "should return the weighted mean value" do
|
255
|
+
p2.expected.should be_within(1.0e-9).of 1.5
|
256
|
+
p4.expected.should be_within(1.0e-9).of 2.5
|
257
|
+
p6.expected.should be_within(1.0e-9).of 3.5
|
258
|
+
p10.expected.should be_within(1.0e-9).of 5.5
|
259
|
+
GamesDice::Probabilities.add_distributions( p6, p10 ).expected.should be_within(1.0e-9).of 9.0
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
end # describe "instance methods"
|
264
|
+
|
265
|
+
end
|