Class: Dice_Stats::Dice_Set

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

Overview

This class represents the roll statistics for a combination of dice. The probability distribution is based off the constituent dice distributions.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dice_string, probability_distribution = nil) ⇒ Dice_Set

Instantiates a new Dice_Set with the specified dice_string pattern. Examples: “2d6 + 1d3” “2d6 + 5” “1d8” “5d4 + 3d10” If probability_distribution is set, no distributions will be calculated and the provided distribution will be used.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/Dice_Set.rb', line 64

def initialize(dice_string, probability_distribution=nil)
	
	# Reject any predefined probability distributions that don't sum to 1.0.
	# Perhaps in the future I should add slightly better checks, but this is adequate for now.
	if probability_distribution != nil && (probability_distribution.inject(0) { |memo,(k,v)| memo + v }.round(3).to_f != 1.0)
		probability_distribution = nil
	end

	@dice = []
	@constant = 0
	@input_string = dice_string
	@aborted_probability_distribution = false

	split_string = dice_string.split('+')

	split_string.map!{|i| i.strip }

	split_string.count.times { |i|
		if /\d+[dD]\d+/.match(split_string[i])
			sub_string_split = split_string[i].downcase.split('d')

			# Skip calculating the sub-die distribution if the total one is already cached
			number_of_dice = sub_string_split[0].to_i
			dice_faces = sub_string_split[1].to_i

			calculate_probability = (probability_distribution == nil) && (number_of_dice * dice_faces <= 1000)
			
			if (number_of_dice * dice_faces > 1000)
				@aborted_probability_distribution = true
			end

			@dice << Dice.new(number_of_dice, dice_faces, calculate_probability)
		elsif (split_string[i].to_i > 0)
			@constant += split_string[i].to_i
		else
			puts "Unexpected paramter: #{split_string[0]}"
		end
	}

	@dice.sort! { |d1,d2| d2.sides <=> d1.sides }

	if probability_distribution != nil
		@probability_distribution = probability_distribution
	else
		if @aborted_probability_distribution || (100_000 < @dice.inject(1) { |m,d| m * (d.sides * d.count) })
			@probability_distribution = {}
			@aborted_probability_distribution = true
		else
			@probability_distribution = combine_probability_distributions 
		end
	end
		
	if (@probability_distribution.inject(0) { |memo,(k,v)| memo + v }.round(3).to_f != 1.0)
		#puts "Error in probability distrubtion."
	end
end

Instance Attribute Details

#diceObject

The constituent separate dice



18
19
20
# File 'lib/Dice_Set.rb', line 18

def dice
  @dice
end

#probability_distributionObject (readonly)

The raw probability distribution of the dice set. Can be queried more interactively through Dice_Set#p.



14
15
16
# File 'lib/Dice_Set.rb', line 14

def probability_distribution
  @probability_distribution
end

Class Method Details

.Get_Clean_String(dice_string, with_constant = true) ⇒ Object

Returns the “clean string” for a dice pattern without actually instantiating the class, calculating the probability, etc. Good to use to check a cache hit if results are being cached



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/Dice_Set.rb', line 23

def self.Get_Clean_String(dice_string, with_constant=true)
	dice = []
	constant = 0


	split_string = dice_string.split('+')

	split_string.map!{|i| i.strip }

	split_string.count.times { |i|
		if /\d+[dD]\d+/.match(split_string[i])
			sub_string_split = split_string[i].downcase.split('d')
			dice << Dice.new(sub_string_split[0].to_i, sub_string_split[1].to_i, false)
		elsif (split_string[i].to_i > 0)
			constant += split_string[i].to_i
		else
			puts "Unexpected paramter: #{split_string[0]}"
		end
	}

	dice.sort! { |d1,d2| d2.sides <=> d1.sides }

	formatted_string = ""
	dice.each { |d| 
		formatted_string += d.count.to_s + "d" + d.sides.to_s + " + "
	}
	if with_constant && constant > 0
		return (formatted_string + constant.to_s)
	else
		return (formatted_string[0..formatted_string.length-4])
	end
end

Instance Method Details

#adjusted_distributionObject

Add the constant the the probability distribution, useful for printing / output purposes



203
204
205
# File 'lib/Dice_Set.rb', line 203

def adjusted_distribution
	@probability_distribution.inject(Hash.new) { |m,(k,v)| m[k+@constant] = v; m }
end

#clean_string(with_constant = true) ⇒ Object

Returns the dice string used to generate the pattern sorted by dice face, descending. For example “2d3 + 2 + 1d6” would become “1d6 + 2d3 + 2” If with_constant is set to false, the constant “+ 2” will be ommitted.



163
164
165
166
167
168
169
170
171
172
173
# File 'lib/Dice_Set.rb', line 163

def clean_string(with_constant=true)
	formatted_string = ""
	@dice.each { |d| 
		formatted_string += d.count.to_s + "d" + d.sides.to_s + " + "
	}
	if with_constant && @constant > 0
		formatted_string + @constant.to_s
	else
		formatted_string[0..formatted_string.length-4]
	end
end

#combine_probability_distributionsObject

For internal use only. Takes the cartesian product of the individual dice and combines them.



154
155
156
157
# File 'lib/Dice_Set.rb', line 154

def combine_probability_distributions
	separate_distributions = @dice.map { |d| d.probability_distribution }
	Internal_Utilities::Math_Utilities.Cartesian_Product_For_Probabilities(separate_distributions)
end

#expectedObject

Returns the average roll result



135
136
137
# File 'lib/Dice_Set.rb', line 135

def expected
	@dice.inject(0) { |memo, d| memo + d.expected }.to_f + @constant
end

#maxObject

Returns the highest possible roll



123
124
125
# File 'lib/Dice_Set.rb', line 123

def max
	@dice.inject(0) { |memo, d| memo + d.max }.to_i + @constant
end

#minObject

Returns the lowest possible roll



129
130
131
# File 'lib/Dice_Set.rb', line 129

def min
	@dice.inject(0) { |memo, d| memo + d.min }.to_i + @constant
end

#pObject

Instantiates and returns a Filtered_distribution. See the documentation for Filtered_distribution.rb.



190
191
192
193
# File 'lib/Dice_Set.rb', line 190

def p
	filtered_distribution = Internal_Utilities::Filtered_distribution.new(adjusted_distribution)
	return filtered_distribution
end

Displays the probability distribution. Can take up quite a lot of screen space for the mroe complicated rolls.



178
179
180
# File 'lib/Dice_Set.rb', line 178

def print_probability
	@probability_distribution.each { |k,v| puts "p(#{k}) => #{v.round(8).to_f}"}
end

#rollObject

Simulates a roll of the dice



184
185
186
# File 'lib/Dice_Set.rb', line 184

def roll
	@dice.inject(@constant || 0) { |memo,d| memo + d.roll }
end

#standard_deviationObject

Returns the standard deviation of the roll



147
148
149
# File 'lib/Dice_Set.rb', line 147

def standard_deviation
	BigDecimal.new(variance, 10).sqrt(5).round(10).to_f
end

#too_complex?Boolean

If the probability distribution was determined to be too complex to compute this will return true.

Returns:

  • (Boolean)


197
198
199
# File 'lib/Dice_Set.rb', line 197

def too_complex?
	@aborted_probability_distribution
end

#varianceObject

Returns the variance of the roll



141
142
143
# File 'lib/Dice_Set.rb', line 141

def variance
	@probability_distribution.inject(0) { |memo, (key,val)| memo + ((key - (expected - @constant))**2 * val) }.round(10).to_f
end