polyhedra 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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