Skip to content

Commit

Permalink
C documentation for GamesDice::Probabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
neilslater committed Oct 3, 2021
1 parent 792d300 commit f568010
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ spec/reports
test/tmp
test/version_tmp
tmp
.DS_Store
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# GamesDice Changelog

## 0.4.1 ( Unreleased )

* Tidy up documentation and address some Rubocop offences.

## 0.4.0 ( 19 September 2021 )

* Dropping support for older Ruby versions (< 2.6)
Expand Down
114 changes: 109 additions & 5 deletions ext/games_dice/probabilities.c
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,12 @@ VALUE probabilities_initialize_copy( VALUE copy, VALUE orig ) {
return copy;
}

/*
* A hash representation of the distribution. Each key is an integer result,
* and the matching value is probability of getting that result. A new hash is generated on each
* call to this method.
* @return [Hash]
*/
VALUE probabilities_to_h( VALUE self ) {
ProbabilityList *pl = get_probability_list( self );
VALUE h = rb_hash_new();
Expand All @@ -648,56 +654,123 @@ VALUE probabilities_to_h( VALUE self ) {
return h;
}

/*
* @!attribute [r] min
* Minimum result in the distribution
* @return [Integer]
*/
VALUE probabilities_min( VALUE self ) {
return INT2NUM( pl_min( get_probability_list( self ) ) );
}

/*
* @!attribute [r] max
* Maximum result in the distribution
* @return [Integer]
*/
VALUE probabilities_max( VALUE self ) {
return INT2NUM( pl_max( get_probability_list( self ) ) );
}

/*
* Probability of result equalling specific target
* @param [Integer] target
* @return [Float] in range (0.0..1.0)
*/
VALUE probabilites_p_eql( VALUE self, VALUE target ) {
return DBL2NUM( pl_p_eql( get_probability_list( self ), NUM2INT(target) ) );
}

/*
* Probability of result being greater than specific target
* @param [Integer] target
* @return [Float] in range (0.0..1.0)
*/
VALUE probabilites_p_gt( VALUE self, VALUE target ) {
return DBL2NUM( pl_p_gt( get_probability_list( self ), NUM2INT(target) ) );
}

/*
* Probability of result being equal to or greater than specific target
* @param [Integer] target
* @return [Float] in range (0.0..1.0)
*/
VALUE probabilites_p_ge( VALUE self, VALUE target ) {
return DBL2NUM( pl_p_ge( get_probability_list( self ), NUM2INT(target) ) );
}

/*
* Probability of result being equal to or less than specific target
* @param [Integer] target
* @return [Float] in range (0.0..1.0)
*/
VALUE probabilites_p_le( VALUE self, VALUE target ) {
return DBL2NUM( pl_p_le( get_probability_list( self ), NUM2INT(target) ) );
}

/*
* Probability of result being less than specific target
* @param [Integer] target
* @return [Float] in range (0.0..1.0)
*/
VALUE probabilites_p_lt( VALUE self, VALUE target ) {
return DBL2NUM( pl_p_lt( get_probability_list( self ), NUM2INT(target) ) );
}

/*
* @!attribute [r] expected
* Expected value of distribution.
* @return [Float]
*/
VALUE probabilites_expected( VALUE self ) {
return DBL2NUM( pl_expected( get_probability_list( self ) ) );
}

/*
* Probability distribution derived from this one, where we know (or are only interested in
* situations where) the result is greater than or equal to target.
* @param [Integer] target
* @return [GamesDice::Probabilities] new distribution.
*/
VALUE probabilities_given_ge( VALUE self, VALUE target ) {
int t = NUM2INT(target);
ProbabilityList *pl = get_probability_list( self );
return pl_as_ruby_class( pl_given_ge( pl, t ), Probabilities );
}

/*
* Probability distribution derived from this one, where we know (or are only interested in
* situations where) the result is less than or equal to target.
* @param [Integer] target
* @return [GamesDice::Probabilities] new distribution.
*/
VALUE probabilities_given_le( VALUE self, VALUE target ) {
int t = NUM2INT(target);
ProbabilityList *pl = get_probability_list( self );
return pl_as_ruby_class( pl_given_le( pl, t ), Probabilities );
}

/*
* @overload repeat_sum(n)
* Adds a distribution to itself repeatedly, to simulate a number of dice
* results being summed.
* @param [Integer] n Number of repetitions, must be at least 1
* @return [GamesDice::Probabilities] new distribution
*/
VALUE probabilities_repeat_sum( VALUE self, VALUE nsum ) {
int n = NUM2INT(nsum);
ProbabilityList *pl = get_probability_list( self );
return pl_as_ruby_class( pl_repeat_sum( pl, n ), Probabilities );
}

/*
* @overload repeat_n_sum_k(n, k, kmode = :keep_best)
* Calculates distribution generated by summing best k results of n iterations
* of the distribution.
* @param [Integer] n Number of repetitions, must be at least 1
* @param [Integer] k Number of best results to keep and sum
* @return [GamesDice::Probabilities] new distribution
*/
VALUE probabilities_repeat_n_sum_k( int argc, VALUE* argv, VALUE self ) {
VALUE nsum, nkeepers, kmode;
int keep_best, n, k;
Expand All @@ -720,6 +793,12 @@ VALUE probabilities_repeat_n_sum_k( int argc, VALUE* argv, VALUE self ) {
return pl_as_ruby_class( pl_repeat_n_sum_k( pl, n, k, keep_best ), Probabilities );
}

/*
* Iterates through value, probability pairs
* @yieldparam [Integer] result A result that may be possible in the dice scheme
* @yieldparam [Float] probability Probability of result, in range 0.0..1.0
* @return [GamesDice::Probabilities] this object
*/
VALUE probabilities_each( VALUE self ) {
ProbabilityList *pl = get_probability_list( self );
int i;
Expand All @@ -736,6 +815,11 @@ VALUE probabilities_each( VALUE self ) {
return self;
}

/*
* Distribution for a die with equal chance of rolling 1..N
* @param [Integer] sides Number of sides on die
* @return [GamesDice::Probabilities]
*/
VALUE probabilities_for_fair_die( VALUE self, VALUE sides ) {
int s = NUM2INT( sides );
VALUE obj;
Expand All @@ -754,6 +838,13 @@ VALUE probabilities_for_fair_die( VALUE self, VALUE sides ) {
return obj;
}

/*
* @overload self.from_h(prob_hash)
* Creates new instance of GamesDice::Probabilities.
* @param [Hash] prob_hash A hash representation of the distribution, each key is an integer result,
* and the matching value is probability of getting that result
* @return [GamesDice::Probabilities]
*/
VALUE probabilities_from_h( VALUE self, VALUE hash ) {
VALUE obj;
ProbabilityList *pl;
Expand Down Expand Up @@ -784,6 +875,14 @@ VALUE probabilities_from_h( VALUE self, VALUE hash ) {
return obj;
}

/*
* @overload self.add_distributions(pd_a, pd_b)
* Combines two distributions to create a third, that represents the distribution created when adding
* results together.
* @param [GamesDice::Probabilities] pd_a First distribution
* @param [GamesDice::Probabilities] pd_b Second distribution
* @return [GamesDice::Probabilities]
*/
VALUE probabilities_add_distributions( VALUE self, VALUE gdpa, VALUE gdpb ) {
ProbabilityList *pl_a = get_probability_list( gdpa );
ProbabilityList *pl_b = get_probability_list( gdpb );
Expand All @@ -794,6 +893,16 @@ VALUE probabilities_add_distributions( VALUE self, VALUE gdpa, VALUE gdpb ) {
return pl_as_ruby_class( pl_add_distributions( pl_a, pl_b ), Probabilities );
}

/*
* @overload self.add_distributions_mult(m_a, pd_a, m_b, pd_b)
* Combines two distributions with multipliers to create a third, that represents the distribution
* created when adding weighted results together.
* @param [Integer] m_a Weighting for first distribution
* @param [GamesDice::Probabilities] pd_a First distribution
* @param [Integer] m_b Weighting for second distribution
* @param [GamesDice::Probabilities] pd_b Second distribution
* @return [GamesDice::Probabilities]
*/
VALUE probabilities_add_distributions_mult( VALUE self, VALUE m_a, VALUE gdpa, VALUE m_b, VALUE gdpb ) {
int mul_a, mul_b;
ProbabilityList *pl_a;
Expand All @@ -808,10 +917,6 @@ VALUE probabilities_add_distributions_mult( VALUE self, VALUE m_a, VALUE gdpa, V
return pl_as_ruby_class( pl_add_distributions_mult( mul_a, pl_a, mul_b, pl_b ), Probabilities );
}

VALUE probabilities_implemented_in( VALUE self ) {
return ID2SYM( rb_intern("c") );
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Setup Probabilities class for Ruby interpretter
Expand Down Expand Up @@ -840,7 +945,6 @@ void init_probabilities_class() {
rb_define_singleton_method( Probabilities, "for_fair_die", probabilities_for_fair_die, 1 );
rb_define_singleton_method( Probabilities, "add_distributions", probabilities_add_distributions, 2 );
rb_define_singleton_method( Probabilities, "add_distributions_mult", probabilities_add_distributions_mult, 4 );
rb_define_singleton_method( Probabilities, "implemented_in", probabilities_implemented_in, 0 );
rb_define_singleton_method( Probabilities, "from_h", probabilities_from_h, 1 );
return;
}
12 changes: 8 additions & 4 deletions lib/games_dice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,22 @@
require 'games_dice/games_dice'
require 'games_dice/marshal'

# GamesDice is a library for simulating dice combinations used in dice and board games.
module GamesDice
# @!visibility private
@@parser = GamesDice::Parser.new

# Creates an instance of GamesDice::Dice from a string description.
# @param [String] dice_description Uses a variation of common game notation, examples: '1d6', '3d8+1d4+7', '5d10k2'
# @param [#rand] prng Optional random number generator, default is to use Ruby's built-in #rand()
# @return [GamesDice::Dice] A new dice object.
#
def self.create(dice_description, prng = nil)
parsed = @@parser.parse(dice_description)
parsed = parser.parse(dice_description)
parsed[:bunches].each { |bunch| bunch.merge!(prng: prng) } if prng
GamesDice::Dice.new(parsed[:bunches], parsed[:offset])
end

private

def self.parser
@parser ||= GamesDice::Parser.new
end
end
3 changes: 2 additions & 1 deletion lib/games_dice/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

module GamesDice
VERSION = '0.4.0'
# Current version of the gem.
VERSION = '0.4.1'
end
8 changes: 0 additions & 8 deletions spec/probability_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,6 @@
expect(-> { GamesDice::Probabilities.from_h({ 0 => 0.5, 2_000_000 => 0.5 }) }).to raise_error ArgumentError
end
end

describe '#implemented_in' do
it 'should be either :c or :ruby' do
lang = GamesDice::Probabilities.implemented_in
expect(lang).to be_a Symbol
expect(%i[c ruby].member?(lang)).to eql true
end
end
end

describe 'instance methods' do
Expand Down

0 comments on commit f568010

Please sign in to comment.