spec/probability_spec.rb in games_dice-0.2.3 vs spec/probability_spec.rb in games_dice-0.2.4

- old
+ new

@@ -1,15 +1,13 @@ require 'games_dice' require 'helpers' describe GamesDice::Probabilities do - describe "class methods" do - describe "#new" do - it "should create a new distribution from a hash" do - p = GamesDice::Probabilities.new( { 1 => 1.0 } ) + it "should create a new distribution from an array and offset" do + p = GamesDice::Probabilities.new( [1.0], 1 ) p.is_a?( GamesDice::Probabilities ).should be_true p.to_h.should be_valid_distribution end end @@ -29,42 +27,103 @@ end end describe "#add_distributions" do it "should combine two distributions to create a third one" do - d4a = GamesDice::Probabilities.new( { 1 => 1.0/4, 2 => 1.0/4, 3 => 1.0/4, 4 => 1.0/4 } ) - d4b = GamesDice::Probabilities.new( { 1 => 1.0/10, 2 => 2.0/10, 3 => 3.0/10, 4 => 4.0/10 } ) + d4a = GamesDice::Probabilities.new( [ 1.0/4, 1.0/4, 1.0/4, 1.0/4 ], 1 ) + d4b = GamesDice::Probabilities.new( [ 1.0/10, 2.0/10, 3.0/10, 4.0/10], 1 ) p = GamesDice::Probabilities.add_distributions( d4a, d4b ) p.to_h.should be_valid_distribution end it "should calculate a classic 2d6 distribution accurately" do d6 = GamesDice::Probabilities.for_fair_die( 6 ) p = GamesDice::Probabilities.add_distributions( d6, d6 ) + h = p.to_h + h.should be_valid_distribution + h[2].should be_within(1e-9).of 1.0/36 + h[3].should be_within(1e-9).of 2.0/36 + h[4].should be_within(1e-9).of 3.0/36 + h[5].should be_within(1e-9).of 4.0/36 + h[6].should be_within(1e-9).of 5.0/36 + h[7].should be_within(1e-9).of 6.0/36 + h[8].should be_within(1e-9).of 5.0/36 + h[9].should be_within(1e-9).of 4.0/36 + h[10].should be_within(1e-9).of 3.0/36 + h[11].should be_within(1e-9).of 2.0/36 + h[12].should be_within(1e-9).of 1.0/36 + end + end + + describe "#repeat_distribution" do + it "should output a valid distribution if params are valid" do + d4a = GamesDice::Probabilities.new( [ 1.0/4, 1.0/4, 1.0/4, 1.0/4 ], 1 ) + d4b = GamesDice::Probabilities.new( [ 1.0/10, 2.0/10, 3.0/10, 4.0/10], 1 ) + p = GamesDice::Probabilities.repeat_distribution( d4a, 7 ) p.to_h.should be_valid_distribution - p.to_h[2].should be_within(1e-9).of 1.0/36 - p.to_h[3].should be_within(1e-9).of 2.0/36 - p.to_h[4].should be_within(1e-9).of 3.0/36 - p.to_h[5].should be_within(1e-9).of 4.0/36 - p.to_h[6].should be_within(1e-9).of 5.0/36 - p.to_h[7].should be_within(1e-9).of 6.0/36 - p.to_h[8].should be_within(1e-9).of 5.0/36 - p.to_h[9].should be_within(1e-9).of 4.0/36 - p.to_h[10].should be_within(1e-9).of 3.0/36 - p.to_h[11].should be_within(1e-9).of 2.0/36 - p.to_h[12].should be_within(1e-9).of 1.0/36 + p = GamesDice::Probabilities.repeat_distribution( d4b, 12 ) + p.to_h.should be_valid_distribution end + + it "should calculate a classic 3d6 distribution accurately" do + d6 = GamesDice::Probabilities.for_fair_die( 6 ) + p = GamesDice::Probabilities.repeat_distribution( d6, 3 ) + h = p.to_h + h.should be_valid_distribution + h[3].should be_within(1e-9).of 1.0/216 + h[4].should be_within(1e-9).of 3.0/216 + h[5].should be_within(1e-9).of 6.0/216 + h[6].should be_within(1e-9).of 10.0/216 + h[7].should be_within(1e-9).of 15.0/216 + h[8].should be_within(1e-9).of 21.0/216 + h[9].should be_within(1e-9).of 25.0/216 + h[10].should be_within(1e-9).of 27.0/216 + h[11].should be_within(1e-9).of 27.0/216 + h[12].should be_within(1e-9).of 25.0/216 + h[13].should be_within(1e-9).of 21.0/216 + h[14].should be_within(1e-9).of 15.0/216 + h[15].should be_within(1e-9).of 10.0/216 + h[16].should be_within(1e-9).of 6.0/216 + h[17].should be_within(1e-9).of 3.0/216 + h[18].should be_within(1e-9).of 1.0/216 + end + end # describe "#repeat_distribution" + + describe "#add_distributions_mult" do + it "should combine two multiplied distributions to create a third one" do + d4a = GamesDice::Probabilities.new( [ 1.0/4, 1.0/4, 1.0/4, 1.0/4 ], 1 ) + d4b = GamesDice::Probabilities.new( [ 1.0/10, 2.0/10, 3.0/10, 4.0/10], 1 ) + p = GamesDice::Probabilities.add_distributions_mult( 2, d4a, -1, d4b ) + p.to_h.should be_valid_distribution + end + + it "should calculate a distribution for '1d6 - 1d4' accurately" do + d6 = GamesDice::Probabilities.for_fair_die( 6 ) + d4 = GamesDice::Probabilities.for_fair_die( 4 ) + p = GamesDice::Probabilities.add_distributions_mult( 1, d6, -1, d4 ) + h = p.to_h + h.should be_valid_distribution + h[-3].should be_within(1e-9).of 1.0/24 + h[-2].should be_within(1e-9).of 2.0/24 + h[-1].should be_within(1e-9).of 3.0/24 + h[0].should be_within(1e-9).of 4.0/24 + h[1].should be_within(1e-9).of 4.0/24 + h[2].should be_within(1e-9).of 4.0/24 + h[3].should be_within(1e-9).of 3.0/24 + h[4].should be_within(1e-9).of 2.0/24 + h[5].should be_within(1e-9).of 1.0/24 + end end end # describe "class methods" describe "instance methods" do let(:p2) { GamesDice::Probabilities.for_fair_die( 2 ) } let(:p4) { GamesDice::Probabilities.for_fair_die( 4 ) } let(:p6) { GamesDice::Probabilities.for_fair_die( 6 ) } let(:p10) { GamesDice::Probabilities.for_fair_die( 10 ) } - let(:pa) { GamesDice::Probabilities.new( { -1 => 0.4, 0 => 0.2, 1 => 0.4 } ) } + let(:pa) { GamesDice::Probabilities.new( [ 0.4, 0.2, 0.4 ], -1 ) } describe "#p_eql" do it "should return probability of getting a number inside the range" do p2.p_eql(2).should be_within(1.0e-9).of 0.5 p4.p_eql(1).should be_within(1.0e-9).of 0.25 @@ -220,8 +279,28 @@ p10.expected.should be_within(1.0e-9).of 5.5 GamesDice::Probabilities.add_distributions( p6, p10 ).expected.should be_within(1.0e-9).of 9.0 end end - end # describe "instance methods" + describe "#given_ge" do + it "should return a new distribution with probabilities calculated assuming value is >= target" do + pd = p2.given_ge(2) + pd.to_h.should == { 2 => 1.0 } + pd = p10.given_ge(4) + pd.to_h.should be_valid_distribution + pd.p_eql( 3 ).should == 0.0 + pd.p_eql( 10 ).should be_within(1.0e-9).of 0.1/0.7 + end + end + describe "#given_le" do + it "should return a new distribution with probabilities calculated assuming value is <= target" do + pd = p2.given_le(2) + pd.to_h.should == { 1 => 0.5, 2 => 0.5 } + pd = p10.given_le(4) + pd.to_h.should be_valid_distribution + pd.p_eql( 3 ).should be_within(1.0e-9).of 0.1/0.4 + pd.p_eql( 10 ).should == 0.0 + end + end + end # describe "instance methods" end