Class: GamesDice::ComplexDie

Inherits:
Object
  • Object
show all
Defined in:
lib/games_dice/complex_die.rb

Overview

This class models a die that is built up from a simpler unit by adding rules to re-roll and interpret the value shown.

An object of this class represents a single complex die. It rolls 1..#sides, with equal weighting for each value. The value from a roll may be used to trigger yet more rolls that combine together. After any re-rolls, the value can be interpretted (“mapped”) as another integer, which is used as the final result.

Examples:

An open-ended percentile die from a popular RPG

d = GamesDice::ComplexDie.new( 100, :rerolls => [[96, :<=, :reroll_add],[5, :>=, :reroll_subtract]] )
d.roll # => #<GamesDice::DieResult:0x007ff03a2415f8 @rolls=[4, 27], ...>
d.result.value # => -23
d.explain_result # => "[4-27] -23"

An “exploding” six-sided die with a target number

d = GamesDice::ComplexDie.new( 6, :rerolls => [[6, :<=, :reroll_add]], :maps => [[8, :<=, 1, 'Success']] )
d.roll # => #<GamesDice::DieResult:0x007ff03a1e8e08 @rolls=[6, 5], ...>
d.result.value # => 1
d.explain_result # => "[6+5] 11 Success"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sides, options = {}) ⇒ GamesDice::ComplexDie

Creates new instance of GamesDice::ComplexDie

Parameters:

  • sides (Integer)

    Number of sides on a single die, passed to GamesDice::Die’s constructor

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :rerolls (Array<GamesDice::RerollRule,Array>)

    The rules that cause the die to roll again

  • :maps (Array<GamesDice::MapRule,Array>)

    The rules to convert a value into a final result for the die

  • :prng (#rand)

    An alternative source of randomness to Ruby’s built-in #rand, passed to GamesDice::Die’s constructor



39
40
41
42
43
44
45
46
47
# File 'lib/games_dice/complex_die.rb', line 39

def initialize( sides, options = {} )
  @basic_die = GamesDice::Die.new(sides, options[:prng])

  @rerolls = construct_rerolls( options[:rerolls] )
  @maps = construct_maps( options[:maps] )

  @total = nil
  @result = nil
end

Instance Attribute Details

#basic_dieGamesDice::Die (readonly)

The simple component used by this complex one

Returns:

  • (GamesDice::Die)

    Object used to make individual dice rolls for the complex die



51
52
53
# File 'lib/games_dice/complex_die.rb', line 51

def basic_die
  @basic_die
end

#explain_resultString? (readonly)

Returns Explanation of result, or nil if no call to #roll yet.

Returns:

  • (String, nil)

    Explanation of result, or nil if no call to #roll yet.



77
78
79
# File 'lib/games_dice/complex_die.rb', line 77

def explain_result
  @result.explain_value
end

#mapsArray<GamesDice::MapRule>? (readonly)

Returns Sequence of map rules, or nil if mapping is not required.

Returns:

  • (Array<GamesDice::MapRule>, nil)

    Sequence of map rules, or nil if mapping is not required.



57
58
59
# File 'lib/games_dice/complex_die.rb', line 57

def maps
  @maps
end

#maxInteger (readonly)

Returns Maximum possible result from a call to #roll.

Returns:

  • (Integer)

    Maximum possible result from a call to #roll



93
94
95
96
97
# File 'lib/games_dice/complex_die.rb', line 93

def max
  return @max_result if @max_result
  calc_minmax
  @max_result
end

#minInteger (readonly)

The minimum possible result from a call to #roll. This is not always the same as the theoretical minimum, due to limits on the maximum number of rerolls.

Returns:

  • (Integer)


85
86
87
88
89
# File 'lib/games_dice/complex_die.rb', line 85

def min
  return @min_result if @min_result
  calc_minmax
  @min_result
end

#probabilities_completeBoolean? (readonly)

Whether or not #probabilities includes all possible outcomes. True if all possible results are represented and assigned a probability. Dice with open-ended re-rolls may have calculations cut short, and will result in a false value of this attribute. Even when this attribute is false, probabilities should still be accurate to nearest 1e-9.

Returns:

  • (Boolean, nil)

    Depending on completeness when generating #probabilities



67
68
69
# File 'lib/games_dice/complex_die.rb', line 67

def probabilities_complete
  @probabilities_complete
end

#rerollsArray<GamesDice::RerollRule>? (readonly)

Returns Sequence of re-roll rules, or nil if re-rolls are not required.

Returns:

  • (Array<GamesDice::RerollRule>, nil)

    Sequence of re-roll rules, or nil if re-rolls are not required.



54
55
56
# File 'lib/games_dice/complex_die.rb', line 54

def rerolls
  @rerolls
end

#resultGamesDice::DieResult? (readonly)

Returns Result of last call to #roll, nil if no call made yet.

Returns:



60
61
62
# File 'lib/games_dice/complex_die.rb', line 60

def result
  @result
end

#sidesInteger (readonly)

Returns Number of sides.

Returns:

  • (Integer)

    Number of sides.



71
72
73
# File 'lib/games_dice/complex_die.rb', line 71

def sides
  @basic_die.sides
end

Instance Method Details

#probabilitiesGamesDice::Probabilities

Calculates the probability distribution for the die. For open-ended re-roll rules, there are some arbitrary limits imposed to prevent large amounts of recursion. Probabilities should be to nearest 1e-9 at worst.

Returns:



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/games_dice/complex_die.rb', line 103

def probabilities
  return @probabilities if @probabilities
  @probabilities_complete = true
  if @rerolls && @maps
    reroll_probs = recursive_probabilities
    prob_hash = {}
    reroll_probs.each do |v,p|
      add_mapped_to_prob_hash( prob_hash, v, p )
    end
  elsif @rerolls
    prob_hash = recursive_probabilities
  elsif @maps
    prob_hash = {}
    @basic_die.probabilities.each do |v,p|
      add_mapped_to_prob_hash( prob_hash, v, p )
    end
  else
    @probabilities = @basic_die.probabilities
    return @probabilities
  end
  @probabilities = GamesDice::Probabilities.from_h( prob_hash )
end

#roll(reason = :basic) ⇒ GamesDice::DieResult

Simulates rolling the die

Parameters:

  • reason (Symbol) (defaults to: :basic)

    Assign a reason for rolling the first die.

Returns:



129
130
131
132
133
134
# File 'lib/games_dice/complex_die.rb', line 129

def roll( reason = :basic )
  @result = GamesDice::DieResult.new( @basic_die.roll, reason )
  roll_apply_rerolls
  roll_apply_maps
  @result
end