tabletop 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ .DS_Store
3
+ pkg/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Nick Novitski
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,44 @@
1
+ # tabletop
2
+
3
+ Tabletop aims to provide a simple way of describing, automating and tracking the tools and tasks involved in "analog" games, determining results from the motions and properties of various dice and chips.
4
+
5
+ Currently, you can roll dice with it.
6
+
7
+ ## Installation
8
+
9
+ gem install tabletop
10
+
11
+ ## Usage
12
+
13
+ Just `require 'tabletop'` and off you go! The easiest way to create a pool of dice is exactly the way you'd expect.
14
+
15
+ 3.d6 #=> [3 (d6), 3 (d6), 4 (d6)]
16
+ 2.d10 + 1.d8 #=> [2 (d10), 6 (d10), 8 (d8)]
17
+ 6.d17 #=> [8 (d17), 3 (d17), 7 (d17), 16 (d17), 11 (d17), 10 (d17)]
18
+
19
+ Pools are arrays of Dice objects that have a few nice extra functions.
20
+
21
+ d&d_strength = 3.d6.roll.sum #=> 13
22
+ ore_character = 10.d10.sets #=> ["3x2", "2x8", "1x7", "1x6", "1x4", "1x3", "1x1"]
23
+ cortex_result = (1.d8 + 2.d6 + 1.d4).highest(2).sum #=> 9
24
+
25
+ Dice are pretty straightforward.
26
+
27
+ d = Die.new
28
+ d.sides #=> 6
29
+ d.result #=> 4
30
+ d.roll #=> "2 (d6)"
31
+
32
+ ## Note on Patches/Pull Requests
33
+
34
+ * Fork the project.
35
+ * Create a topic branch
36
+ * Make tests that describe your feature addition or bug fix.
37
+ * Write code that passes those tests
38
+ * Commit, without altering the rakefile or version.
39
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
40
+ * Send me a pull request.
41
+
42
+ ## Copyright
43
+
44
+ Copyright (c) 2011 Nick Novitski. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+
3
+ begin
4
+ require 'bundler'
5
+ rescue LoadError
6
+ $stderr.puts "You must install bundler - run `gem install bundler`"
7
+ end
8
+
9
+ begin
10
+ Bundler.setup
11
+ rescue Bundler::BundlerError => e
12
+ $stderr.puts e.message
13
+ $stderr.puts "Run `bundle install` to install missing gems"
14
+ exit e.status_code
15
+ end
16
+ require 'rake'
17
+
18
+ require 'bueller'
19
+ Bueller::Tasks.new
20
+
21
+ require 'rspec/core/rake_task'
22
+ RSpec::Core::RakeTask.new(:examples) do |examples|
23
+ examples.rspec_opts = '-Ispec'
24
+ end
25
+
26
+ task :default => :examples
27
+
28
+ require 'rdoc/task'
29
+ RDoc::Task.new do |rdoc|
30
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
31
+
32
+ rdoc.main = 'README.rdoc'
33
+ rdoc.rdoc_dir = 'rdoc'
34
+ rdoc.title = "tabletop #{version}"
35
+ rdoc.rdoc_files.include('README*')
36
+ rdoc.rdoc_files.include('lib/**/*.rb')
37
+ end
data/lib/fixnum.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'tabletop'
2
+
3
+ class Fixnum
4
+ def dX(sides)
5
+ dice = []
6
+ times { dice << Tabletop::Die.new(sides) }
7
+ Tabletop::Pool.new(dice)
8
+ end
9
+ def dF
10
+ dice = []
11
+ times {dice << Tabletop::FudgeDie.new}
12
+ Tabletop::Pool.new(dice)
13
+ end
14
+ def method_missing(symbol, *args, &block)
15
+ if symbol =~ /^d(.*)$/
16
+ dX($1.to_i)
17
+ else
18
+ super
19
+ end
20
+ end
21
+ def respond_to?(symbol, include_private = false)
22
+ if symbol.to_s =~ /^d(.*)$/
23
+ true if $1.to_i > 0
24
+ else
25
+ super
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,59 @@
1
+ module Tabletop
2
+ class Die
3
+ include Comparable
4
+ attr_reader :sides, :result
5
+ def initialize(sides=6, result=nil)
6
+ if sides <= 0
7
+ raise ArgumentError, "Die cannot have #{sides} sides"
8
+ end
9
+ unless sides.kind_of? Integer
10
+ raise ArgumentError, "Parameter must be Integer, not #{sides.class}"
11
+ end
12
+ @sides = sides
13
+ if result.nil?
14
+ result = roll
15
+ else
16
+ raise ArgumentError unless valid_result?(result)
17
+ end
18
+ @result = result
19
+ end
20
+ def roll
21
+ @result = rand(sides)+1
22
+ end
23
+ def inspect
24
+ "#{@result} (d#{@sides})"
25
+ end
26
+ def result=(new_result)
27
+ raise ArgumentError unless valid_result?(new_result)
28
+ @result = new_result
29
+ end
30
+ def <=>(operand)
31
+ @result <=> operand.to_int
32
+ end
33
+ def to_int
34
+ @result
35
+ end
36
+
37
+ protected
38
+ def valid_result?(result)
39
+ result > 0 and result <= @sides
40
+ end
41
+ end
42
+
43
+ class FudgeDie < Die
44
+ def initialize(result = nil)
45
+ super(3, result)
46
+ end
47
+ def roll
48
+ @result = rand(sides)-1
49
+ end
50
+ def inspect
51
+ "[#{['-', ' ', '+'][@result+1]}] (dF)"
52
+ end
53
+
54
+ protected
55
+ def valid_result?(result)
56
+ [1,0,-1].include?(result)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,115 @@
1
+ require_relative 'die'
2
+ require 'delegate'
3
+
4
+ module Tabletop
5
+ class Pool < DelegateClass(Array)
6
+ include Comparable
7
+ def initialize(init_dice)
8
+ return super(init_dice) if init_dice.class == Array
9
+ d_groups = init_dice.split
10
+ dice = []
11
+ d_groups.each do |d_notation|
12
+ number, sides = d_notation.split('d')
13
+ number = number.to_i
14
+ number += 1 if number == 0
15
+ if sides.to_i > 0
16
+ number.times { dice << Die.new(sides.to_i)}
17
+ elsif sides == "F"
18
+ number.times {dice << FudgeDie.new}
19
+ end
20
+ end
21
+ super(dice)
22
+ end
23
+ def +(operand)
24
+ # if the operator is a pool, or an array only of Die objects...
25
+ if operand.class == Pool or (operand.class == Array and !(operand.detect{|obj| obj.class != Die}))
26
+ new_union(operand)
27
+ elsif operand.kind_of? Numeric
28
+ sum + operand
29
+ else
30
+ raise ArgumentError, "Cannot add operand of class #{operand.class}"
31
+ end
32
+ end
33
+
34
+ def <=>(operand)
35
+ sum <=> operand.to_int
36
+ end
37
+
38
+ def results
39
+ map {|die| die.result}
40
+ end
41
+ def dice
42
+ fudge = nil
43
+ result = {}
44
+ each do |die|
45
+ if die.class == FudgeDie
46
+ fudge = count {|d| d.class == FudgeDie}
47
+ else
48
+ result[die.sides] = count {|d| d.sides == die.sides}
49
+ end
50
+ end
51
+ d_array = result.sort.collect do |d_group|
52
+ number = d_group[1]
53
+ number = "" if number == 1
54
+ sides = d_group[0]
55
+ "#{number}d#{sides}"
56
+ end
57
+ if fudge
58
+ d_array << "#{fudge}dF"
59
+ end
60
+ d_array
61
+ end
62
+ def roll
63
+ each do |die|
64
+ die.roll
65
+ end
66
+ self
67
+ end
68
+ def sum
69
+ inject(0) {|sum, d| sum + d.result}
70
+ end
71
+ def to_int
72
+ sum
73
+ end
74
+ def sets
75
+ result = {}
76
+ each do |die|
77
+ result[die.result] = count {|d| d.result == die.result}
78
+ end
79
+ result.sort_by{|height, width| [width, height] }.collect {|i| i[1].to_s+"x"+i[0].to_s}.reverse
80
+ end
81
+ def highest(n=1)
82
+ sorted = sort_by {|d| d.result}.reverse
83
+ Pool.new(sorted.first(n))
84
+ end
85
+ def lowest(n=1)
86
+ sorted = sort_by {|d| d.result}
87
+ Pool.new(sorted.first(n))
88
+ end
89
+ def drop_highest(n=1)
90
+ Pool.new(self-highest(n))
91
+ end
92
+ def drop_lowest(n=1)
93
+ Pool.new(self-lowest(n))
94
+ end
95
+ def drop(to_drop)
96
+ to_drop = [to_drop].flatten #turn it into an array if it isn't one.
97
+ kept = reject{|die| to_drop.any?{|drop_value| die.result == drop_value }}
98
+ return Pool.new(kept)
99
+ end
100
+
101
+ private
102
+ def new_union(array)
103
+ union = [self, array].flatten
104
+ new_pool =[]
105
+ union.each do |die|
106
+ if die.class == FudgeDie
107
+ new_pool << FudgeDie.new(die.result)
108
+ else
109
+ new_pool << Die.new(die.sides, die.result)
110
+ end
111
+ end
112
+ Pool.new(new_pool)
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,3 @@
1
+ module Tabletop
2
+ VERSION = "0.0.1"
3
+ end
data/lib/tabletop.rb ADDED
@@ -0,0 +1,3 @@
1
+ require_relative 'fixnum'
2
+ require_relative 'tabletop/die'
3
+ require_relative 'tabletop/pool'
data/spec/die_spec.rb ADDED
@@ -0,0 +1,189 @@
1
+ require 'spec_helper'
2
+
3
+ module Tabletop
4
+ describe Die do
5
+ before :each do
6
+ @d6_2 = Die.new(6, 2)
7
+ @d6_3 = Die.new(6, 3)
8
+ end
9
+ describe "#sides" do
10
+ it "can be accessed" do
11
+ d = Die.new(6)
12
+ d.sides.should == 6
13
+ d = Die.new(20)
14
+ d.sides.should == 20
15
+ d = Die.new(7)
16
+ d.sides.should equal(7)
17
+ end
18
+ it "is 6 by default" do
19
+ d = Die.new
20
+ d.sides.should equal(6)
21
+ end
22
+ it "cannot be 0 or less" do
23
+ lambda { Die.new(0) }.should raise_error(ArgumentError)
24
+ lambda { Die.new(-5) }.should raise_error(ArgumentError)
25
+ end
26
+ it "cannot be a non-integer" do
27
+ lambda { Die.new(0.1) }.should raise_error(ArgumentError)
28
+ lambda { Die.new(5.7694) }.should raise_error(ArgumentError)
29
+ lambda { Die.new("foof") }.should raise_error(ArgumentError)
30
+ end
31
+ end
32
+ describe "#result" do
33
+ before :each do
34
+ Random.srand(10)
35
+ end
36
+ it "should be random on instantiation by default" do
37
+ d = Die.new
38
+ d.result.should equal(2)
39
+ d = Die.new(10)
40
+ d.result.should equal(5)
41
+ d = Die.new(50)
42
+ d.result.should equal(16)
43
+ end
44
+ it "can be set to a given value on instantiation" do
45
+ Die.new(6, 5).result.should == 5
46
+ Die.new(10, 2).result.should == 2
47
+ end
48
+ it "cannot be a non-integer" do
49
+ lambda { Die.new(0.1) }.should raise_error(ArgumentError)
50
+ lambda { Die.new(5.7694) }.should raise_error(ArgumentError)
51
+ lambda { Die.new("foof") }.should raise_error(ArgumentError)
52
+ end
53
+ end
54
+ describe "#result=" do
55
+ it "can only be set to an integer i, where 0 < i <= sides" do
56
+ d = Die.new
57
+ lambda { d.result = 0 }.should raise_error(ArgumentError)
58
+ lambda { d.result = -5 }.should raise_error(ArgumentError)
59
+ lambda { d.result = 7 }.should raise_error(ArgumentError)
60
+ d = Die.new(10)
61
+ d.result = 7
62
+ lambda { d.result = 22 }.should raise_error(ArgumentError)
63
+ end
64
+ end
65
+ describe "#roll" do
66
+ before(:each) do
67
+ Random.srand(10)
68
+ end
69
+ context "six sides" do
70
+ it "should return a random result between 1 and @sides" do
71
+ d = Die.new
72
+ #d.roll.should == 2 # This result gets swallowed by the init roll
73
+ d.roll.should == 6
74
+ d.roll.should == 5
75
+ d.roll.should == 1
76
+ end
77
+ it "should alter the result appropriately" do
78
+ d = Die.new
79
+ #d.roll # Covered by the initial roll
80
+ d.result.should == 2
81
+ d.roll
82
+ d.result.should == 6
83
+ d.roll
84
+ d.result.should == 5
85
+ d.roll
86
+ d.result.should == 1
87
+ end
88
+ end
89
+ context "eleven sides" do
90
+ it "should return a random result between 1 and @sides" do
91
+ d = Die.new(11)
92
+ # d.roll.should == 10 # This result gets swallowed by the init roll
93
+ d.roll.should == 5
94
+ d.roll.should == 1
95
+ d.roll.should == 2
96
+ end
97
+ it "should alter the result appropriately" do
98
+ d = Die.new(11)
99
+ #d.roll # covered by the initial roll
100
+ d.result.should == 10
101
+ d.roll
102
+ d.result.should == 5
103
+ d.roll
104
+ d.result.should == 1
105
+ d.roll
106
+ d.result.should == 2
107
+ end
108
+ end
109
+ end
110
+ describe "#inspect" do
111
+ before(:each) do
112
+ Random.srand(10)
113
+ end
114
+ it "should be interesting" do
115
+ Die.new.inspect.should == "2 (d6)"
116
+ Die.new.inspect.should == "6 (d6)"
117
+ end
118
+ end
119
+ describe "#to_int" do
120
+ it "returns the result" do
121
+ d = Die.new
122
+ d.to_int.should == d.result
123
+ end
124
+ end
125
+ describe "<=>" do
126
+ it "compares numeric objects with the die's value" do
127
+ (@d6_3 < 4).should be_true
128
+ (@d6_3 < 2).should be_false
129
+ (@d6_3 > 2).should be_true
130
+ (@d6_3 > 4).should be_false
131
+ (@d6_3 >= 3).should be_true
132
+ (@d6_3 >= 10).should be_false
133
+ (@d6_3 <= 3).should be_true
134
+ (@d6_3 <= 2).should be_false
135
+ (@d6_3 == 3).should be_true
136
+ (@d6_3 == 6).should be_false
137
+ end
138
+ it "compares dice with each other by value" do
139
+ (@d6_3 > @d6_2).should be_true
140
+ (@d6_3 < @d6_2).should be_false
141
+ (@d6_2 < @d6_3).should be_true
142
+ (@d6_2 > @d6_3).should be_false
143
+ (@d6_3 == @d6_2).should be_false
144
+ end
145
+ end
146
+ end
147
+ describe FudgeDie do
148
+ before(:each) do
149
+ Random.srand(10)
150
+ @fudge = FudgeDie.new
151
+ end
152
+ describe "#sides" do
153
+ it "is always 3" do
154
+ @fudge.sides.should == 3
155
+ end
156
+ end
157
+ describe "#result" do
158
+ it "can be set on instantiation" do
159
+ FudgeDie.new(1).result.should == 1
160
+ FudgeDie.new(0).result.should == 0
161
+ FudgeDie.new(-1).result.should == -1
162
+ end
163
+ it "is randomly rolled if not set" do
164
+ @fudge.result.should == 0
165
+ end
166
+ it "can only be one of either -1, 0, or 1" do
167
+ lambda {FudgeDie.new(2)}.should raise_error(ArgumentError)
168
+ lambda {FudgeDie.new(0.6)}.should raise_error(ArgumentError)
169
+ lambda {FudgeDie.new("5")}.should raise_error(ArgumentError)
170
+ end
171
+ end
172
+ describe "#result=" do
173
+ it "cannot be set to anything but -1, 0, or 1" do
174
+ lambda {@fudge.result = 2}.should raise_error(ArgumentError)
175
+ lambda {@fudge.result = 0.6}.should raise_error(ArgumentError)
176
+ lambda {@fudge.result = "5"}.should raise_error(ArgumentError)
177
+ @fudge.result = 1
178
+ @fudge.result.should == 1
179
+ end
180
+ end
181
+ describe "#inspect" do
182
+ it "should look like plusses, minuses and spaces" do
183
+ FudgeDie.new(1).inspect.should == "[+] (dF)"
184
+ FudgeDie.new(0).inspect.should == "[ ] (dF)"
185
+ FudgeDie.new(-1).inspect.should == "[-] (dF)"
186
+ end
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Tabletop
4
+ describe Fixnum do
5
+ describe "#dX" do
6
+ it "generates a pool of the appropriate size and type" do
7
+ 1.d6.class.should == Pool
8
+ 4.d7.dice.should == ["4d7"]
9
+ 10.d100.class.should == Pool
10
+ end
11
+ it "shows up in respond_to?(:dN)" do
12
+ 1.respond_to?(:d50).should be_true
13
+ end
14
+ end
15
+ describe "#dF" do
16
+ it "generates a pool of fudge dice" do
17
+ sotc = 4.dF
18
+ sotc.class.should == Pool
19
+ sotc.all? { |d| d.class == FudgeDie }.should be_true
20
+ sotc.dice.should == ["4dF"]
21
+ end
22
+ end
23
+ end
24
+ end
data/spec/pool_spec.rb ADDED
@@ -0,0 +1,193 @@
1
+ require 'spec_helper'
2
+
3
+ module Tabletop
4
+ describe Pool do
5
+ before :each do
6
+ Random.srand(10)
7
+ @d6 = Pool.new("d6")
8
+ @d17s = Pool.new("5d17")
9
+ @mixed = Pool.new("2d10 d20")
10
+ @fudge = Pool.new("3dF")
11
+ end
12
+ describe "#dice" do
13
+ it "should return an array of dice notation" do
14
+ @mixed.dice.should == ["2d10","d20"]
15
+ @d6.dice.should == ["d6"]
16
+ @d17s.dice.should == ["5d17"]
17
+ @fudge.dice.should == ["3dF"]
18
+ Pool.new("d20 2dF 2d10").dice.should == ["2d10","d20", "2dF"]
19
+ end
20
+ end
21
+ describe "[]" do
22
+ it "should access Die objects" do
23
+ @d6[0].class.should == Die
24
+ @fudge[0].class.should == FudgeDie
25
+ end
26
+ end
27
+ describe "+" do
28
+ it "should join Pools into new Pools" do
29
+ (@mixed + @d17s).class == Pool
30
+ (@d6 + @fudge).class == Pool
31
+ end
32
+ it "should persist die types" do
33
+ (@d6 + @fudge)[1].class.should == FudgeDie
34
+ end
35
+ it "should join pools without rolling them" do
36
+ merge = @d6 + @d17s
37
+ merge.results.should == [2, 5, 16, 1, 17, 9]
38
+ merge.roll
39
+ merge.results.should == [4, 17, 5, 16, 12, 12]
40
+ end
41
+ it "creates genuinely new pools" do
42
+ merge = @d6 + @d17s
43
+ merge.roll
44
+ @d6.results.should == [2]
45
+ @d17s.results.should == [5, 16, 1, 17, 9]
46
+ end
47
+
48
+ it "should alter #dice accordingly" do
49
+ @d6 = Pool.new("d6")
50
+ @d17s = Pool.new("5d17")
51
+ @mixed = Pool.new("2d10 d20")
52
+ (@d6 + @d17s).dice.should == ["d6", "5d17"]
53
+ (@d17s + @d6).dice.should == ["d6", "5d17"]
54
+ (@d17s + @mixed).dice.should == ["2d10","5d17","d20"]
55
+ (@mixed + @fudge).dice.should == ["2d10", "d20", "3dF"]
56
+ end
57
+ it "should understand adding a number as looking for a sum result" do
58
+ (@d17s + 5).should == 53
59
+ (@mixed + @d6 + 10).should == 34
60
+ (@fudge + 3).should == 2
61
+ end
62
+ it "should add literal dice arrays as if they were pools" do
63
+ g = @d6 + [Die.new(6,3), Die.new(10, 4)]
64
+ g.results.should == [2, 3, 4]
65
+ g.dice.should == ["2d6", "d10"]
66
+ g.roll
67
+ @d6.results.should == [2]
68
+ end
69
+ it "should reject adding anything else" do
70
+ lambda {@d6 + "foof"}.should raise_error(ArgumentError)
71
+ lambda {@d6 + [Die.new, Object.new]}.should raise_error(ArgumentError)
72
+ end
73
+ end
74
+ describe "#results" do
75
+ it "should be an array of random numbers" do
76
+ @d6.results.should == [2]
77
+ @d17s.results.should == [5, 16, 1, 17, 9]
78
+ @mixed.results.should == [10, 1, 11]
79
+ end
80
+ end
81
+ describe "#roll" do
82
+ it "should return the Pool itself" do
83
+ @d6.roll.length.should == @d6.length
84
+ @d6.roll.class.should == @d6.class
85
+ end
86
+ it "should store the new values" do
87
+ @d6.roll
88
+ @d6.results.should == [4]
89
+ @d17s.roll
90
+ @d17s.results.should == [17, 5, 16, 12, 12]
91
+ @mixed.roll
92
+ @mixed.results.should == [2, 9, 5]
93
+ end
94
+ end
95
+ describe "#sum" do
96
+ it "should sum the dice values" do
97
+ @d6.sum.should == 2
98
+ @d17s.sum.should == 48
99
+ @mixed.sum.should == 22
100
+ @fudge.sum.should == -1
101
+ end
102
+ it "should be aliased to #to_int" do
103
+ @d6.to_int.should == @d6.sum
104
+ @d17s.to_int.should == @d17s.sum
105
+ @mixed.to_int.should == @mixed.sum
106
+ @fudge.to_int.should == @fudge.sum
107
+ end
108
+ end
109
+ describe "<=>" do
110
+ it "should compare the sums of different pools" do
111
+ @d17s.should >= @d6
112
+ @d6.should < Pool.new([Die.new(4, 4)])
113
+ end
114
+ it "should compare pools to numbers" do
115
+ @d6.should < 10
116
+ @d6.should == 2
117
+ @d17s.should <= 49
118
+ end
119
+ end
120
+ describe "#sets" do
121
+ it "should list the sets, in order by height and width" do
122
+ ore = Pool.new("10d10")
123
+ ore.sets.should == ["2x9", "2x5", "2x4", "2x2", "1x7", "1x1"]
124
+ ore.roll
125
+ ore.sets.should == ["3x10", "2x7", "1x6", "1x5", "1x4", "1x3", "1x2"]
126
+ ore.roll
127
+ ore.sets.should == ["3x9", "2x8", "2x7", "1x10", "1x3", "1x1"]
128
+ end
129
+ end
130
+ describe "#highest" do
131
+ it "should return a pool of the highest-value die" do
132
+ @d6.highest.class.should == Pool
133
+ @d6.highest.results.should == [2]
134
+ @d17s.highest.results.should == [17]
135
+ @mixed.highest.results.should == [11]
136
+ end
137
+ it "should return as many items as are specified" do
138
+ @d6.highest(5).results.should == [2]
139
+ @d17s.highest(3).results.should == [17, 16, 9]
140
+ @mixed.highest(2).results.should == [11, 10]
141
+ end
142
+ end
143
+ describe "#lowest" do
144
+ it "should return a pool of the lowest-value die." do
145
+ @d6.lowest.results.should == [2]
146
+ @d17s.lowest.class.should == Pool
147
+ @d17s.lowest.results.should == [1]
148
+ @mixed.lowest.results.should == [1]
149
+ end
150
+ it "should return as many items as are specified" do
151
+ @d6.lowest(5).results.should == [2]
152
+ @d17s.lowest(3).results.should == [1, 5, 9]
153
+ @mixed.lowest(2).results.should == [1, 10]
154
+ end
155
+ end
156
+ describe "#drop_highest" do
157
+ it "should return a new pool missing the highest result" do
158
+ p = @d17s.drop_highest
159
+ p.results.should == [5, 16, 1, 9]
160
+ @d17s.results.should == [5, 16, 1, 17, 9]
161
+ end
162
+ it "should drop as many items as are specified and are possible" do
163
+ p = @d17s.drop_highest(2)
164
+ p.results.should == [5, 1, 9]
165
+ p = @d6.drop_highest(10)
166
+ p.results.should == []
167
+ end
168
+ end
169
+ describe "#drop_lowest" do
170
+ it "should return a pool missing the lowest result" do
171
+ p = @d17s.drop_lowest
172
+ p.results.should == [5, 16, 17, 9]
173
+ @d17s.results.should == [5, 16, 1, 17, 9]
174
+ end
175
+ it "should drop as many items as are specified" do
176
+ p = @d17s.drop_lowest(2)
177
+ p.results.should == [16, 17, 9]
178
+ end
179
+ end
180
+ describe "#drop" do
181
+ it "should drop any dice of the specified value" do
182
+ ore = Pool.new("10d10")
183
+ ore.results.should == [4, 1, 5, 7, 9, 2, 9, 5, 2, 4]
184
+ at_least_two = ore.drop(1)
185
+ at_least_two.results.should == [4, 5, 7, 9, 2, 9, 5, 2, 4]
186
+ at_least_three = ore.drop([1,2])
187
+ at_least_three.results.should == [4, 5, 7, 9, 9, 5, 4]
188
+ end
189
+ end
190
+ context "pool has been emptied" do
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,19 @@
1
+ require 'bundler'
2
+ begin
3
+ Bundler.setup
4
+ rescue Bundler::BundlerError => e
5
+ $stderr.puts e.message
6
+ $stderr.puts "Run `bundle install` to install missing gems"
7
+ exit e.status_code
8
+ end
9
+
10
+ require 'rspec'
11
+ require 'tabletop'
12
+
13
+ # Requires supporting files with custom matchers and macros, etc,
14
+ # in ./support/ and its subdirectories.
15
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
16
+
17
+ RSpec.configure do |config|
18
+
19
+ end
data/tabletop.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require 'tabletop/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'tabletop'
6
+ s.version = Tabletop::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.date = '2011-08-10'
9
+ s.authors = ['Nick Novitski']
10
+ s.email = 'nicknovitski@gmail.com'
11
+ s.homepage = 'http://github.com/njay/tabletop'
12
+ s.summary = 'A Ruby DSL for role-playing games'
13
+ s.description = 'Tabletop aims to provide a simple way of describing, automating and tracking the tools and tasks involved in "analog" games, determining results from the motions and properties of various dice and chips.'
14
+ s.extra_rdoc_files = [
15
+ 'LICENSE',
16
+ 'README.markdown',
17
+ ]
18
+
19
+ s.required_rubygems_version = Gem::Requirement.new('>= 1.3.7')
20
+ s.rubygems_version = '1.3.7'
21
+ s.specification_version = 3
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
25
+ s.require_paths = ['lib']
26
+
27
+ s.add_development_dependency 'rspec'
28
+ s.add_development_dependency 'bundler'
29
+ s.add_development_dependency 'bueller'
30
+ s.add_development_dependency 'rake'
31
+ s.add_development_dependency 'rdoc'
32
+ end
33
+
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tabletop
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Nick Novitski
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-08-10 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :development
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: bueller
48
+ prerelease: false
49
+ requirement: &id003 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ type: :development
58
+ version_requirements: *id003
59
+ - !ruby/object:Gem::Dependency
60
+ name: rake
61
+ prerelease: false
62
+ requirement: &id004 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ type: :development
71
+ version_requirements: *id004
72
+ - !ruby/object:Gem::Dependency
73
+ name: rdoc
74
+ prerelease: false
75
+ requirement: &id005 !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ type: :development
84
+ version_requirements: *id005
85
+ description: Tabletop aims to provide a simple way of describing, automating and tracking the tools and tasks involved in "analog" games, determining results from the motions and properties of various dice and chips.
86
+ email: nicknovitski@gmail.com
87
+ executables: []
88
+
89
+ extensions: []
90
+
91
+ extra_rdoc_files:
92
+ - LICENSE
93
+ - README.markdown
94
+ files:
95
+ - .gitignore
96
+ - Gemfile
97
+ - LICENSE
98
+ - README.markdown
99
+ - Rakefile
100
+ - lib/fixnum.rb
101
+ - lib/tabletop.rb
102
+ - lib/tabletop/die.rb
103
+ - lib/tabletop/pool.rb
104
+ - lib/tabletop/version.rb
105
+ - spec/die_spec.rb
106
+ - spec/fixnum_spec.rb
107
+ - spec/pool_spec.rb
108
+ - spec/spec_helper.rb
109
+ - tabletop.gemspec
110
+ has_rdoc: true
111
+ homepage: http://github.com/njay/tabletop
112
+ licenses: []
113
+
114
+ post_install_message:
115
+ rdoc_options: []
116
+
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ segments:
125
+ - 0
126
+ version: "0"
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ segments:
133
+ - 1
134
+ - 3
135
+ - 7
136
+ version: 1.3.7
137
+ requirements: []
138
+
139
+ rubyforge_project:
140
+ rubygems_version: 1.3.7
141
+ signing_key:
142
+ specification_version: 3
143
+ summary: A Ruby DSL for role-playing games
144
+ test_files:
145
+ - spec/die_spec.rb
146
+ - spec/fixnum_spec.rb
147
+ - spec/pool_spec.rb
148
+ - spec/spec_helper.rb