polyhedra 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ruby-1.9.3@polyhedra --create
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :development do
4
+ gem "guard"
5
+ gem "guard-rspec"
6
+ gem "listen"
7
+ gem "rb-fsevent"
8
+ gem "rspec"
9
+ end
10
+
@@ -0,0 +1,47 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch(%r{^lib/polyhedra/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
8
+ watch('spec/spec_helper.rb') { "spec" }
9
+
10
+ # Rails example
11
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
12
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
13
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
14
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
15
+ watch('config/routes.rb') { "spec/routing" }
16
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
17
+
18
+ # Capybara request specs
19
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
20
+
21
+ # Turnip features and steps
22
+ watch(%r{^spec/acceptance/(.+)\.feature$})
23
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
24
+ end
25
+
26
+
27
+ guard 'rspec', :version => 2 do
28
+ watch(%r{^spec/.+_spec\.rb$})
29
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
30
+ watch('spec/spec_helper.rb') { "spec" }
31
+
32
+ # Rails example
33
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
34
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
35
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
36
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
37
+ watch('config/routes.rb') { "spec/routing" }
38
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
39
+
40
+ # Capybara request specs
41
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
42
+
43
+ # Turnip features and steps
44
+ watch(%r{^spec/acceptance/(.+)\.feature$})
45
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
46
+ end
47
+
@@ -0,0 +1,209 @@
1
+ # Overview
2
+
3
+ Polyhedra is a tool to help you write programs that manage dice using
4
+ the kinds of expressions most RPG rulebooks use. Some examples of dice
5
+ expressions that can be handled:
6
+
7
+ * d20
8
+ * 3d6
9
+ * 6d6
10
+ * 1d4-1
11
+ * 2d6x10
12
+ * 2d6*10
13
+ * 4d6t3 # roll 4d6, take highest 3
14
+ * 3d6r2 # roll 3d6, re-rolling 1's or 2's
15
+ * 2d6-1x10 # note that +/- modifiers happen before multipliers; that's just how dice math works. 2d6-1x10 == 1-11x10 == 10-110
16
+ * 1d6 fire # you can assign units to the dice as well
17
+
18
+ Polyhedra understands dice math:
19
+
20
+ * 3d6 + 2d6 => 5d6
21
+ * 2d6 + 1d4 => 2d6 + 1d4 # dissimilar bases can't be added
22
+ * 1d6 fire + 1d4 fire + 1d6 earth => 1d6 + 1d4 fire + 1d6 earth # similar units are grouped before bases
23
+
24
+ Note that adding two dissimilar dice results in a "DiceSet", which is
25
+ a collection of Dice objects. You can still "roll" a DiceSet just like
26
+ you would a Dice object, but #sides won't work and #units will return
27
+ an array.
28
+
29
+ Polyhedra also understands units, and knows to avoid adding dice of
30
+ different units:
31
+
32
+ * 3d6 fire + 2d6 physical
33
+ * 1d4 frost + 2
34
+
35
+ # Dice Notation
36
+
37
+ The simplest RPG Dice notation is given as numbers and letters of the
38
+ form _NdS_, where N is the number of dice to roll and S is the number
39
+ of sides per die. When you roll all the dice in a Yahtzee cup, you are
40
+ rolling 5d6, or five dice, each with six sides. If you are rolling a
41
+ single die, you can omit the 1 and represent the notation as e.g d6.
42
+
43
+ Role-playing games make allowances for other alterations to the roll:
44
+ you can add or subtract (2d6+3, 1d4-1), multiply or divide (1d4x10,
45
+ 1d6/2). (Note that most game systems round down, so 1d6/2 actually
46
+ yields a number between 0 and 3.)
47
+
48
+ Mathematically, none of the following are equivalent: 1d3, 1d4-1,
49
+ 1d6/2. The first one cannot roll 0's, and although the second two have
50
+ the same min/max range, 1d4-1 has an even distribution--exactly a 25%
51
+ chance of rolling each number--while 1d6/2 has an uneven distribution
52
+ (a 17% chance of rolling a 0, 33% chance of rolling a 1, etc).
53
+
54
+ ## Notational Affixes
55
+
56
+ * rR - Reroll any dice equal or below R. R must be < S. 3d6r3 will
57
+ roll 12-18 as each die must be 4 or higher to be kept.
58
+ Mathematically 3d6r3 is identical to 3d3+9 but the semantics are
59
+ considered to be different so the extra notation is allowed.
60
+
61
+ * RR - Reroll any dice equal or above R. R must be > 1 and <= S.
62
+
63
+ * kM - Keep highest M dice. 1 < M < N. 4d6k3 means roll 4d6, but only
64
+ count the highest 3 dice in the final tally.
65
+
66
+ * KM - Keep lowest M dice. 1 < M < N.
67
+
68
+
69
+
70
+ # Order of Operations
71
+
72
+ Rerolls are considered first, then keeps. Next--and this is the
73
+ reverse of typical algebraic precedence--addition or subtraction
74
+ happens and finally multiplication or division. Thus
75
+
76
+ 4d6r1k3+1x10
77
+
78
+ Would roll dice until 4 dice showed 2 or higher, then the top 3 dice
79
+ would be kept. The range at this point would be 6-18. 1 would be added
80
+ to this bumping the range to 7-19. Finally the roll is mulitplied by
81
+ 10 to yield a range of 70-190. Note that because multiplication is
82
+ performed last the final value will be in steps of the multiplier;
83
+ e.g. the above dice expression could roll a 70, 80, 90, etc., but
84
+ could not roll a 75 or an 81.
85
+
86
+ # Monkeypatch! Woo! (Fixnum shorthand)
87
+
88
+ Polyhedra will add .d* methods to Fixnum and to Kernel (d20 is the same
89
+ as 1.d20 is the same as Dice.new "1d20"). Since this is a monkeypatch,
90
+ it's optional. Require polyhedra/shorthand instead of polyhedra to get
91
+ these methods.
92
+
93
+
94
+ require 'polyhedra/shorthand'
95
+ dice = 3.d6
96
+ # => <#Dice: 3d6>
97
+
98
+ fire1 = 1.d6("fire")
99
+ fire2 = 2.d8("fire")
100
+ fire3 = 3.d6(:fire) # symbols and strings are okay
101
+ frost = 2.d6("frost")
102
+
103
+ fire1 + fire2 + fire3 + frost
104
+ # => <DiceSet: <Dice: 4d6, fire>, <Dice: 2d8, fire>, <Dice: 2d6 frost>]
105
+
106
+ Note that while the shorthand allows for modifiers like -1 or x10, it
107
+ looks kind of lame.
108
+
109
+ 1.d6("r1-1")
110
+ # => <Dice: 1d6r1-1>
111
+ 2.d10("+3x10")
112
+ # => <Dice: 2d10+3x10>
113
+ d20
114
+ # => <Dice: 1d20>
115
+
116
+ I am open to changing the interface to cascade like so:
117
+
118
+ 4.d6.r1.k3("+1x10") but honestly this still looks unnecessarily
119
+ complicated. Better to just use Dice.new() at this point.
120
+
121
+ Then again, since we have to catch method_missing to allow for
122
+ arbitrary digits, maybe we could steal a page from the Rails playbook
123
+ and allow longer methods names that encode the entire sequence, such
124
+ as:
125
+
126
+ 4.d6r1t3
127
+ # => <Dice: 4d6r1t3
128
+
129
+ The only gotcha is that we can't capture +/- in its proper place
130
+ (immediately after the dX sequence). Legal ruby would be `4.d6r1t3+3`
131
+ but proper dice notation would `4.d6+3r1t3` which won't work.
132
+
133
+ Hrm, if a Dice.new() or Fixnum#dXX statement returns a Dice object,
134
+ maybe we should define +,-,*,/ etc to return new Dice objects?
135
+
136
+ d6
137
+ # => <Dice: 1d6>
138
+ d6 + 1
139
+ # => <Dice: 1d6+1>
140
+
141
+
142
+ ## Complex Notation
143
+
144
+ A set of Dice can be collected into a DiceSet and rolled as a unit:
145
+
146
+ bag = DiceSet.new
147
+ bag << Dice.new('3d6')
148
+ bag << '2d4' # bag#<< accepts Dice or string
149
+ bag
150
+ # => <DiceSet: <Dice: 3d6>, <Dice: 2d4>>
151
+ bag.roll
152
+ # => 19
153
+ bag.max
154
+ # => 26
155
+ bag.min
156
+ # => 5
157
+
158
+ ## Units
159
+
160
+ Each Dice object can have its own units, and units are treated as a
161
+ higher-order grouping than number of sides. Note that #min, #max and
162
+ #roll will return an array of pairs containing the amount and unit for
163
+ each type of dice.
164
+
165
+ bag = DiceSet.new
166
+ bag << 1.d6("fire")
167
+ bag << 1.d6("fire")
168
+ bag << 1.d4("frost")
169
+ bag.min
170
+ # => [[2, :fire], [1, :frost]]
171
+ bag.min_without_units
172
+ # => 3
173
+ bag.max
174
+ # => [[12, :fire], [4, :frost]]
175
+ bag.max_without_units
176
+ # => 16
177
+ bag.roll
178
+ # => [[7, :fire], [2, :frost]]
179
+ bag.roll_without_units
180
+ # => 11
181
+
182
+ You can also pass a specific unit to #min, #max and #roll to isolate
183
+ part of the roll:
184
+
185
+ bag.max(:fire)
186
+ # => 12
187
+ bag.min(:frost)
188
+ # => 1
189
+ bag.roll(:fire)
190
+ # => 3
191
+
192
+
193
+ # Contributing
194
+
195
+ 1. Pull requests are welcome!
196
+ 2. Fork the repo
197
+ 3. Write _good_ specs for your change: specs that fully cover and
198
+ clearly document the intent of your change
199
+ 4. Send a pull request
200
+
201
+ *Note:* If you want to make a wild and crazy change (and have it
202
+ merged into the gem), I'm open to that--but please get in touch with
203
+ me and let's chat about the direction you want to go so you don't
204
+ waste your time (unless you're okay with your changes staying in
205
+ your fork forever)
206
+
207
+
208
+
209
+
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
1
+ require "polyhedra/version"
2
+ require "polyhedra/dice"
3
+
@@ -0,0 +1,112 @@
1
+ module Polyhedra
2
+ class Dice
3
+ include Comparable
4
+
5
+ attr_accessor :number, :sides, :offset, :multiplier, :divisor, :reroll_under, :take_top
6
+ attr_writer :rng
7
+
8
+ def initialize(dice_expression)
9
+ dice_expression = dice_expression.gsub(/s+/, '')
10
+
11
+ @offset = @reroll_under = 0
12
+ @multiplier = @divisor = 1
13
+
14
+ @take_top = @number = [1, dice_expression.to_i].max
15
+ dice_expression.sub!(/^\d+/, '')
16
+
17
+ while dice_expression.length > 0
18
+ action, amount, dice_expression = pop_expression(dice_expression)
19
+ amount = amount.to_i
20
+ case action
21
+ when 'd'
22
+ self.sides = amount
23
+ when '+'
24
+ self.offset = amount
25
+ when '-'
26
+ self.offset = -amount
27
+ when '*', 'x'
28
+ self.multiplier = amount
29
+ when '/'
30
+ self.divisor = amount
31
+ when 'r'
32
+ self.reroll_under = amount
33
+ when 't'
34
+ self.take_top = amount
35
+ end
36
+ end
37
+ end
38
+
39
+ def to_s
40
+ str = ""
41
+ str << "%dd%d" % [number, sides]
42
+ str << "%+d" % offset unless offset.zero?
43
+ str << "x%d" % multiplier unless multiplier == 1
44
+ str << "/%d" % divisor unless divisor == 1
45
+ str << "r%d" % reroll_under unless reroll_under.zero?
46
+ str << "t%d" % take_top unless take_top == number
47
+ str
48
+ end
49
+
50
+ def roll
51
+ rolled_dice = []
52
+
53
+ while rolled_dice.size < number
54
+ roll=rand(sides)+1
55
+ rolled_dice << roll if roll > reroll_under
56
+ end
57
+
58
+ rolled_dice = rolled_dice.sort.reverse.take take_top
59
+
60
+ rolled_dice.inject {|a,b| a+b}
61
+ end
62
+
63
+ def min
64
+ ((take_top + offset + (reroll_under*take_top)) * multiplier) / divisor
65
+ end
66
+
67
+ def max
68
+ ((take_top * sides + offset) * multiplier) / divisor
69
+ end
70
+
71
+ def pop_expression(string)
72
+ %r|^([dr+-x\*/])(\d+)(.*)$|.match(string).to_a.dup.tap(&:shift)
73
+ end
74
+
75
+ # def dice_matrix
76
+ # # TODO: make this work with take_top--probably a sort/take in the each_slice?
77
+ # # TODO: make this work with reroll--probably change the 1..sides to reroll+1..sides ?
78
+ # Array.new(number) { (1..sides).to_a }.inject(:product).flatten.each_slice(number).map {|ray| ray.sort.take take_top }
79
+ # end
80
+
81
+ def rand(num)
82
+ rng.rand(num)
83
+ end
84
+
85
+ def inverted_divisor
86
+ 1.0 / divisor
87
+ end
88
+
89
+ def <=>(other)
90
+ a,b = [:sides, :number, :multiplier, :inverted_divisor, :offset].map {|sym| [send(sym), other.send(sym)] }.detect {|a,b| (a <=> b) != 0 }
91
+ a <=> b
92
+ # if sides != other.sides
93
+ # sides <=> other.sides
94
+ # else
95
+ # if number != other.number
96
+ # number <=> other.number
97
+ # else
98
+ # if multiplier != other.multiplier
99
+ # multiplier <=> other.multiplier
100
+ # else
101
+ # -divisor <=> -other.divisor
102
+ # end
103
+ # end
104
+ # end
105
+ end
106
+
107
+ private
108
+ def rng
109
+ @rng ||= Random.new
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,3 @@
1
+ module Polyhedra
2
+ VERSION = "0.3.0"
3
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "polyhedra/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "polyhedra"
7
+ s.version = Polyhedra::VERSION
8
+ s.authors = ["David Brady"]
9
+ s.email = ["github@shinybit.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Dice manipulation and rolling gem capable of handling complex dice expressions}
12
+ s.description = %q{Dice manipulation and rolling gem capable of handling complex RPG dice expressions, from a simple "d6" up to "4d6r1k3-2x10 frost" and "3d6", etc.}
13
+
14
+ s.rubyforge_project = "polyhedra"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+
23
+ # s.add_runtime_dependency "treetop"
24
+ end
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+ require 'polyhedra/dice'
3
+
4
+ # I roll twenties! rand(n) always returns max possible value
5
+ class LuckyRng < Random
6
+ def rand(num)
7
+ num-1
8
+ end
9
+ end
10
+
11
+ # Returns 0, 1, 2, ..., n-1 in order.
12
+ class GaussianRng < Random
13
+ def rand(num)
14
+ @sequence ||= (0..num).cycle
15
+ @sequence.next
16
+ end
17
+ end
18
+
19
+ # Returns... whatever... you tell... it to...
20
+ class JediMindTrickRng < Random
21
+ def initialize(sequence)
22
+ @sequence = sequence.cycle
23
+ super(0)
24
+ end
25
+
26
+ def rand(num)
27
+ @sequence.next
28
+ end
29
+ end
30
+
31
+ module Polyhedra
32
+ describe Dice do
33
+ context "simple dice expression" do
34
+ let(:dice) { Dice.new("3d6") }
35
+
36
+ it { dice.offset.should == 0 }
37
+ it { dice.sides.should == 6 }
38
+ it { dice.number.should == 3 }
39
+ it { dice.roll.should >= 3 }
40
+ it { dice.roll.should <= 18 }
41
+ it { dice.min.should == 3 }
42
+ it { dice.max.should == 18 }
43
+ end
44
+
45
+ context "with offset" do
46
+ it { Dice.new("3d6+2").min.should == 5 }
47
+ it { Dice.new("3d6+2").max.should == 20 }
48
+ it { Dice.new("3d6-2").min.should == 1 }
49
+ it { Dice.new("3d6-2").max.should == 16 }
50
+ end
51
+
52
+ context "with scalar" do
53
+ it { Dice.new("3d6x10").min.should == 30 }
54
+ it { Dice.new("3d6x10").max.should == 180 }
55
+ it { Dice.new("3d6*10").min.should == 30 }
56
+ it { Dice.new("3d6*10").max.should == 180 }
57
+ it { Dice.new("1d6/2").min.should == 0 }
58
+ it { Dice.new("1d6/2").max.should == 3 }
59
+ end
60
+
61
+ context "with reroll_under" do
62
+ let(:dice) { Dice.new("3d6r1") }
63
+ before(:each) do
64
+ dice.rng = JediMindTrickRng.new [0, 1, 0, 2, 0, 3]
65
+ end
66
+ it { dice.reroll_under.should == 1 }
67
+ it { dice.min.should == 6 }
68
+ it { dice.max.should == 18 }
69
+
70
+ it { dice.roll.should == 9 }
71
+ end
72
+
73
+ context "with take_top" do
74
+ let(:dice) { Dice.new("4d6t3") }
75
+ it { dice.take_top.should == 3 }
76
+ it { dice.max.should == 18 }
77
+ it { dice.min.should == 3 }
78
+ context "with loaded dice" do
79
+ before :each do
80
+ dice.rng = JediMindTrickRng.new [2,0,4,5]
81
+ end
82
+ it { dice.roll.should == 14 }
83
+ end
84
+ end
85
+
86
+ context "when I roll twenties" do
87
+ let(:dice) { Dice.new("4d6") }
88
+ before :each do
89
+ dice.rng = LuckyRng.new
90
+ end
91
+ it { dice.roll.should == 24 }
92
+ end
93
+
94
+ describe "#pop_expression" do
95
+ describe "returns subexpression, rest_of_string" do
96
+ it { Dice.new("1d6").pop_expression("r3string").should == ["r", "3", "string"] }
97
+ end
98
+ end
99
+
100
+ describe "#to_s" do
101
+ it { Dice.new("d20").to_s.should == "1d20" }
102
+ it { Dice.new("1d4*10").to_s.should =="1d4x10" }
103
+
104
+ # These expressions should all parse and to_s as themselves
105
+ [ "3d6",
106
+ "1d4+1",
107
+ "3d6r1",
108
+ "4d6t3",
109
+ "6d6+3r2t4",
110
+ "1d10x10",
111
+ "1d4+2x10",
112
+ "1d6/2",
113
+ "9d8+2x5r2t6"
114
+ ].each do |str|
115
+ it "correctly parses '#{str}'" do
116
+ Dice.new(str).to_s.should eq str
117
+ end
118
+ end
119
+ end
120
+
121
+ describe "comparison" do
122
+ it { Dice.new("3d6").should == Dice.new("3d6") }
123
+ it("favors bases first") { Dice.new("10d4").should < Dice.new("1d5") }
124
+ it("favors number second") { Dice.new("3d6").should > Dice.new("2d6") }
125
+ it("favors multipliers third") { Dice.new("3d6x10").should > Dice.new("3d6x8") }
126
+ it("favors divisors third") { Dice.new("3d6/10").should < Dice.new("3d6/8") }
127
+ it("favors offset fourth") { Dice.new("3d6+3").should > Dice.new("3d6") }
128
+ end
129
+
130
+ describe "dice math" do
131
+ describe "addition" do
132
+ it { Dice.new("3d6")}
133
+ end
134
+ end
135
+ end
136
+ end
137
+
@@ -0,0 +1,4 @@
1
+ # spec helper
2
+
3
+
4
+ # ;-) -- happy little no-op for now
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: polyhedra
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - David Brady
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-17 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Dice manipulation and rolling gem capable of handling complex RPG dice
15
+ expressions, from a simple "d6" up to "4d6r1k3-2x10 frost" and "3d6", etc.
16
+ email:
17
+ - github@shinybit.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - .rspec
24
+ - .rvmrc
25
+ - Gemfile
26
+ - Guardfile
27
+ - README.md
28
+ - Rakefile
29
+ - lib/polyhedra.rb
30
+ - lib/polyhedra/dice.rb
31
+ - lib/polyhedra/version.rb
32
+ - polyhedra.gemspec
33
+ - spec/lib/dice_spec.rb
34
+ - spec/spec_helper.rb
35
+ homepage: ''
36
+ licenses: []
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project: polyhedra
55
+ rubygems_version: 1.8.23
56
+ signing_key:
57
+ specification_version: 3
58
+ summary: Dice manipulation and rolling gem capable of handling complex dice expressions
59
+ test_files:
60
+ - spec/lib/dice_spec.rb
61
+ - spec/spec_helper.rb