tabletop 0.3.0 → 0.4.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.
- data/.gitignore +2 -1
- data/README.markdown +16 -1
- data/lib/tabletop.rb +2 -1
- data/lib/tabletop/deck.rb +111 -0
- data/lib/tabletop/pool.rb +22 -5
- data/lib/tabletop/version.rb +1 -1
- data/spec/deck_spec.rb +155 -0
- data/spec/fixnum_spec.rb +2 -2
- data/spec/pool_spec.rb +48 -25
- data/spec/spec_helper.rb +3 -14
- data/tabletop.gemspec +1 -0
- metadata +166 -2
data/.gitignore
CHANGED
data/README.markdown
CHANGED
|
@@ -124,7 +124,22 @@ So, possible results for our cool AW roll:
|
|
|
124
124
|
open_brain.roll
|
|
125
125
|
puts open_brain.result #=> 10
|
|
126
126
|
puts open_brain.effects #=> ["the MC will tell you something new and interesting about the current situation", "...and it's a good detail"]
|
|
127
|
-
|
|
127
|
+
|
|
128
|
+
### Decks
|
|
129
|
+
|
|
130
|
+
Decks are essentially weighted hashes with a random #draw method. You can put whatever hashable object you like in a
|
|
131
|
+
deck (there's no Card class yet) as a key to a value that indicates the number of copies of that object in the deck.
|
|
132
|
+
|
|
133
|
+
#draw returns another deck, and reduces the number of cards in the original deck appropriately.
|
|
134
|
+
|
|
135
|
+
d = Deck.new
|
|
136
|
+
d["card A"] = 20
|
|
137
|
+
d["card B"] = 19
|
|
138
|
+
d.deck_size #=> 39
|
|
139
|
+
hand = d.draw(3) #=> {"card A"=>1, "card B" =>2}
|
|
140
|
+
d #=> {"card A" => 19, "card B"=>17}
|
|
141
|
+
d << hand #=> {"card A" => 20, "card B"=>19}
|
|
142
|
+
|
|
128
143
|
### Coming Soon
|
|
129
144
|
|
|
130
145
|
That's already enough functionality to do many different kinds of rolls, but there's a lot more in store.
|
data/lib/tabletop.rb
CHANGED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
module Tabletop
|
|
2
|
+
class DrawMoreCardsThanDeckHasError < StandardError
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
class Deck < Hash
|
|
6
|
+
def initialize
|
|
7
|
+
super(0)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def << object
|
|
11
|
+
if object.respond_to? :merge
|
|
12
|
+
merge(object) {|card,ours,new| ours+new}
|
|
13
|
+
else
|
|
14
|
+
self[object] = 1
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def deck_size
|
|
19
|
+
self.values.inject(:+)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def draw(cards=1)
|
|
23
|
+
raise DrawMoreCardsThanDeckHasError if cards > self.deck_size
|
|
24
|
+
drawable_cards = self.clone
|
|
25
|
+
if block_given?
|
|
26
|
+
drawable_cards = drawable_cards.keep_if {|card,copies| yield(card,copies) }
|
|
27
|
+
return nil if drawable_cards.empty?
|
|
28
|
+
# can't use select here, since that returns a Hash instead of a Deck
|
|
29
|
+
end
|
|
30
|
+
drawn = Deck.new
|
|
31
|
+
cards.times do
|
|
32
|
+
running_weight = 0
|
|
33
|
+
n = rand*drawable_cards.deck_size
|
|
34
|
+
drawable_cards.each do |card, weight|
|
|
35
|
+
if running_weight < n && n <= running_weight + weight
|
|
36
|
+
self[card] -= 1
|
|
37
|
+
drawable_cards[card] -= 1
|
|
38
|
+
drawn << card
|
|
39
|
+
end
|
|
40
|
+
running_weight += weight
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
drawn
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def possible_starting_hands(hand_size=7)
|
|
47
|
+
|
|
48
|
+
# at any moment, there is some set of cards A that have the highest values, countA
|
|
49
|
+
# (ie, there's the most of them in the deck)
|
|
50
|
+
# there may also be some set of cards B that have the next-highest values, countB
|
|
51
|
+
#
|
|
52
|
+
# in the case of there only being As
|
|
53
|
+
# the most likely combinations are equal numbers of each of them, or as close to that as possible.
|
|
54
|
+
# if A.size is 1, and countA is greater than hand_size
|
|
55
|
+
# the first and last combination would be {A1=>hand_size}
|
|
56
|
+
# if A.size is 1, and countA is less than hand_size...
|
|
57
|
+
# then raise an exception, of course
|
|
58
|
+
# if A.size is 2, and countA is greater than hand_size
|
|
59
|
+
# the first combination would be {A1=>hand}
|
|
60
|
+
# if A.size is 2, and 2*countA is greater than hand_size
|
|
61
|
+
# if A.size is 2, and 2*countA is less than hand_size, then again, exception
|
|
62
|
+
#
|
|
63
|
+
# So the first set of combinations has as it's left term
|
|
64
|
+
# countA-countB of each card in A
|
|
65
|
+
# and as it's right term,
|
|
66
|
+
#
|
|
67
|
+
# they are likely
|
|
68
|
+
# n = copies of most popular card - copies of next most popular card
|
|
69
|
+
#
|
|
70
|
+
# first_hand = n copies of most popular card, up to seven
|
|
71
|
+
# now there is some number A>=2 of cards that are equally likely
|
|
72
|
+
# If A >= 7-n
|
|
73
|
+
# first_hand << unique (k-n)-combinations of those A cards
|
|
74
|
+
# if A < 7-n (that is, if )
|
|
75
|
+
cards_uniq = self.keys
|
|
76
|
+
Enumerator.new do |hands|
|
|
77
|
+
|
|
78
|
+
counts = self.values.uniq.sort
|
|
79
|
+
|
|
80
|
+
cards_uniq.repeated_combination(hand_size).each do |a|
|
|
81
|
+
hands << a if self.possible_hand?(a)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def possible_hand?(array)
|
|
87
|
+
hand = Hash.new(0)
|
|
88
|
+
array.each { |e| hand[e] +=1 }
|
|
89
|
+
hand.each {|card, number| return false if (self[card].nil? or self[card] < number) }
|
|
90
|
+
true
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def chance_to_draw(cards)
|
|
94
|
+
if Array === cards
|
|
95
|
+
copy = self.clone
|
|
96
|
+
odds = 1
|
|
97
|
+
cards.each do |card|
|
|
98
|
+
odds *= copy.chance_to_draw(card)
|
|
99
|
+
copy[card] -= 1
|
|
100
|
+
end
|
|
101
|
+
odds
|
|
102
|
+
else
|
|
103
|
+
if self[cards] and self[cards] != 0
|
|
104
|
+
Float(self[cards])/self.deck_size
|
|
105
|
+
else
|
|
106
|
+
0
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
data/lib/tabletop/pool.rb
CHANGED
|
@@ -77,7 +77,7 @@ module Tabletop
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
# Returns a string of the pool's dice in d-notation
|
|
80
|
-
def
|
|
80
|
+
def d_notation
|
|
81
81
|
fudge = nil
|
|
82
82
|
result = {}
|
|
83
83
|
each do |die|
|
|
@@ -100,9 +100,26 @@ module Tabletop
|
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
# Rolls every die in the pool, and returns the Pool.
|
|
103
|
-
def roll
|
|
103
|
+
def roll(params={})
|
|
104
104
|
each do |die|
|
|
105
|
-
|
|
105
|
+
|
|
106
|
+
meets_all_conditions = true
|
|
107
|
+
|
|
108
|
+
params.each do |condition, term|
|
|
109
|
+
attribute, comparison = condition.to_s.split("_")
|
|
110
|
+
die_att = die.send(attribute.to_sym)
|
|
111
|
+
|
|
112
|
+
case comparison
|
|
113
|
+
when "under"
|
|
114
|
+
meets_all_conditions = false unless die_att < term
|
|
115
|
+
when "over"
|
|
116
|
+
meets_all_conditions = false unless die_att > term
|
|
117
|
+
when "equals"
|
|
118
|
+
meets_all_conditions = false unless die_att == term
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
die.roll if meets_all_conditions
|
|
106
123
|
end
|
|
107
124
|
self
|
|
108
125
|
end
|
|
@@ -167,13 +184,13 @@ module Tabletop
|
|
|
167
184
|
# of values) passed.
|
|
168
185
|
def drop(to_drop)
|
|
169
186
|
to_drop = [to_drop].flatten #turn it into an array if it isn't one.
|
|
170
|
-
kept = reject{|die| to_drop.
|
|
187
|
+
kept = reject{|die| to_drop.include?{die.value}}
|
|
171
188
|
Pool.new(kept)
|
|
172
189
|
end
|
|
173
190
|
|
|
174
191
|
private
|
|
175
192
|
def new_union(array)
|
|
176
|
-
union = [self, array].flatten
|
|
193
|
+
union = [self, array].flatten # avoid using + in implementation of +
|
|
177
194
|
new_pool =[]
|
|
178
195
|
union.each do |die|
|
|
179
196
|
new_pool << die.class.new(sides:die.sides, value:die.value)
|
data/lib/tabletop/version.rb
CHANGED
data/spec/deck_spec.rb
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Tabletop
|
|
5
|
+
describe Deck do
|
|
6
|
+
let(:d) do
|
|
7
|
+
deck = Deck.new
|
|
8
|
+
deck["Forest"] = 8
|
|
9
|
+
deck["Mountain"] = 3
|
|
10
|
+
deck["Island"] = 3
|
|
11
|
+
deck["Rootbound Crag"] = 4
|
|
12
|
+
deck["Hinterland Harbor"] = 4
|
|
13
|
+
deck["Llanowar Elves"] = 3
|
|
14
|
+
deck["Birds of Paradise"] = 4
|
|
15
|
+
deck["Phantasmal Image"] = 4
|
|
16
|
+
deck["Viridian Emissary"] = 4
|
|
17
|
+
deck["Phyrexian Metamorph"] = 4
|
|
18
|
+
deck["Acidic Slime"] = 4
|
|
19
|
+
deck["Inferno Titan"] = 4
|
|
20
|
+
deck["Wurmcoil Engine"] = 4
|
|
21
|
+
deck["Rampant Growth"] = 4
|
|
22
|
+
deck["Lead the Stampede"] = 3
|
|
23
|
+
deck
|
|
24
|
+
end
|
|
25
|
+
it "defaults to having zero of things" do
|
|
26
|
+
subject["Random Object"].should == 0
|
|
27
|
+
end
|
|
28
|
+
describe "#deck_size" do
|
|
29
|
+
it "counts all the cards" do
|
|
30
|
+
d.deck_size.should == 60
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
describe "<<" do
|
|
34
|
+
it "merges, summing together the values of collisions" do
|
|
35
|
+
deck_a = Deck.new()
|
|
36
|
+
deck_a["card A"] =1
|
|
37
|
+
deck_a["card B"] = 1
|
|
38
|
+
deck_b = Deck.new()
|
|
39
|
+
deck_b["card B"] =2
|
|
40
|
+
deck_b["card C"] =2
|
|
41
|
+
merged_deck = deck_a.merge(deck_b) {|k,o,n| o+n}
|
|
42
|
+
(deck_a << deck_b).should == merged_deck
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
describe "#draw" do
|
|
46
|
+
it "returns a deck containing a random card and decrements that card's copy count in the calling object" do
|
|
47
|
+
srand(1841922)
|
|
48
|
+
d.draw.should == {"Acidic Slime"=>1}
|
|
49
|
+
d["Acidic Slime"].should == 3
|
|
50
|
+
end
|
|
51
|
+
context "with one parameter" do
|
|
52
|
+
it "returns that many cards" do
|
|
53
|
+
d.draw(3).length.should == 3
|
|
54
|
+
end
|
|
55
|
+
it "raises an exception when you try to draw too many" do
|
|
56
|
+
expect {d.draw(61)}.to raise_error DrawMoreCardsThanDeckHasError
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
context "when passed a block " do
|
|
60
|
+
it "returns a random card for which the block returns true" do
|
|
61
|
+
srand(1841922)
|
|
62
|
+
d.draw {|card, copies| true}.should == {"Acidic Slime"=>1}
|
|
63
|
+
srand(1841922)
|
|
64
|
+
d.draw do |card, copies|
|
|
65
|
+
card == "Forest" or card == "Island" or card == "Mountain"
|
|
66
|
+
end.should == {"Mountain"=> 1}
|
|
67
|
+
end
|
|
68
|
+
it "returns nil if the card is not present" do
|
|
69
|
+
srand(1841922)
|
|
70
|
+
d.draw {|card, copies| false}.should be_nil
|
|
71
|
+
d.draw do |card, copies|
|
|
72
|
+
card == "Sir Not Appearing in this Test"
|
|
73
|
+
end.should be_nil
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
describe "#chance_to_draw" do
|
|
78
|
+
context "when passed a card" do
|
|
79
|
+
it "returns the odds of drawing that card from the deck" do
|
|
80
|
+
size = d.deck_size
|
|
81
|
+
d.each do |card,copies|
|
|
82
|
+
d.chance_to_draw(card).should == Float(copies)/size
|
|
83
|
+
end
|
|
84
|
+
d.chance_to_draw("A Card it Doesn't Have").should == 0
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
context "when passed an array of cards" do
|
|
88
|
+
it "returns the odds of drawing all the cards in the array from a draw of {array.length} cards" do
|
|
89
|
+
d.chance_to_draw(["Acidic Slime"]).should == d.chance_to_draw("Acidic Slime")
|
|
90
|
+
d.chance_to_draw(["Acidic Slime", "Phyrexian Metamorph"]).should == Float(4*4)/(60*59)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
describe "#possible_starting_hands" do
|
|
95
|
+
def factorial(number)
|
|
96
|
+
(1..number).inject(:*)
|
|
97
|
+
end
|
|
98
|
+
def combinations(n,k)
|
|
99
|
+
factorial(n) / (factorial(k) * factorial(n-k))
|
|
100
|
+
end
|
|
101
|
+
def check_psh(deck, hand_size)
|
|
102
|
+
number_of_unique_cards = deck.length
|
|
103
|
+
guess_hands = combinations(hand_size+number_of_unique_cards-1, hand_size)
|
|
104
|
+
# Important note: the following only calculates combinations which have too many of any single card
|
|
105
|
+
# for a hand of size N, there are some combinations of K cards (c1, c2, ... ck) which are impossible
|
|
106
|
+
# how many integers between 2 and N are there which add to N?
|
|
107
|
+
# make a recursive function for that, tail case
|
|
108
|
+
# answer << [self]
|
|
109
|
+
# if == 2, return 1, 1
|
|
110
|
+
# then return (1..self-1).each {|v| add_up_to(self-v).each {|w| [v,w]}}
|
|
111
|
+
unless hand_size == 1
|
|
112
|
+
deck.each do |card, copies|
|
|
113
|
+
if copies == hand_size-1
|
|
114
|
+
guess_hands -= 1 #there is only one impossible hand in that case: a full hand of the card in question
|
|
115
|
+
elsif copies < hand_size # that is, if more copies of the card than exist might be in a possible hand
|
|
116
|
+
guess_hands -= combinations(hand_size - (copies+1) + number_of_unique_cards - 1,
|
|
117
|
+
hand_size - (copies+1))
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
if hand_size == 7
|
|
123
|
+
deck.possible_starting_hands.to_a.length.should == guess_hands
|
|
124
|
+
else
|
|
125
|
+
deck.possible_starting_hands(hand_size).to_a.length.should == guess_hands
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
it "enumerates all possible hand of a passed size (default 7)" do
|
|
129
|
+
7.downto(1).each do |hand|
|
|
130
|
+
check_psh(d, hand)
|
|
131
|
+
end
|
|
132
|
+
deck = Deck.new
|
|
133
|
+
deck["card a"] = 20
|
|
134
|
+
deck["card b"] = 20
|
|
135
|
+
thing = []
|
|
136
|
+
deck.possible_starting_hands.each do |hand|
|
|
137
|
+
thing << [-1*deck.chance_to_draw(hand), hand]
|
|
138
|
+
end
|
|
139
|
+
p thing.sort
|
|
140
|
+
end
|
|
141
|
+
it "enumerates in descending order of likelihood" do
|
|
142
|
+
pending "discovery of the algorithm"
|
|
143
|
+
best_odds = 1
|
|
144
|
+
deck = Deck.new
|
|
145
|
+
deck["card a"] = 20
|
|
146
|
+
deck["card b"] = 20
|
|
147
|
+
deck.possible_starting_hands.each do |hand|
|
|
148
|
+
chance = deck.chance_to_draw(hand)
|
|
149
|
+
chance.should <= best_odds
|
|
150
|
+
best_odds = chance
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
data/spec/fixnum_spec.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Tabletop
|
|
|
5
5
|
describe "#dX" do
|
|
6
6
|
it "generates a pool of the appropriate size and type" do
|
|
7
7
|
1.d6.should be_instance_of(Pool)
|
|
8
|
-
4.d7.
|
|
8
|
+
4.d7.d_notation.should == ["4d7"]
|
|
9
9
|
10.d100.should be_instance_of(Pool)
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -23,7 +23,7 @@ module Tabletop
|
|
|
23
23
|
sotc = 4.dF
|
|
24
24
|
sotc.should be_instance_of(Pool)
|
|
25
25
|
sotc.all? { |d| d.instance_of?(FudgeDie) }.should be_true
|
|
26
|
-
sotc.
|
|
26
|
+
sotc.d_notation.should == ["4dF"]
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
end
|
data/spec/pool_spec.rb
CHANGED
|
@@ -33,9 +33,9 @@ module Tabletop
|
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
describe "#
|
|
36
|
+
describe "#d_notation" do
|
|
37
37
|
it "should return an array of dice notation" do
|
|
38
|
-
Pool.new("d20 2dF 2d10").
|
|
38
|
+
Pool.new("d20 2dF 2d10").d_notation.should == ["2d10","d20", "2dF"]
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -48,42 +48,39 @@ module Tabletop
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
describe "+" do
|
|
51
|
-
before(:each) do
|
|
52
|
-
@a = 5.d6
|
|
53
|
-
end
|
|
54
51
|
context "adding a number" do
|
|
55
52
|
it "should return the pool's sum plus the number" do
|
|
56
|
-
(
|
|
53
|
+
(d6_set + 5).should == d6_set.sum + 5
|
|
57
54
|
end
|
|
58
55
|
end
|
|
59
56
|
context "adding a randomizer" do
|
|
60
57
|
it "adds to the pool" do
|
|
61
|
-
|
|
62
|
-
mixed.length.should == 6
|
|
58
|
+
(d6_set + Die.new).length.should == 7
|
|
63
59
|
end
|
|
64
60
|
it "preserves class" do
|
|
65
|
-
(
|
|
66
|
-
(
|
|
61
|
+
(d6_set + FudgeDie.new(value:-1))[-1].value.should == -1
|
|
62
|
+
(d6_set + Coin.new)[-1].should respond_to :flip
|
|
67
63
|
end
|
|
68
64
|
end
|
|
69
65
|
context "adding another pool" do
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
@merge = @a+@b
|
|
73
|
-
end
|
|
66
|
+
let(:d4_set) { 4.d4 }
|
|
67
|
+
let(:merge) { d6_set+d4_set }
|
|
74
68
|
it "should make a union of the pools" do
|
|
75
|
-
|
|
69
|
+
merge.values.should == d6_set.values + d4_set.values
|
|
76
70
|
end
|
|
77
71
|
it "should make new die objects" do
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
a = 1.d6
|
|
73
|
+
b = 1.d4
|
|
74
|
+
merge = a+b
|
|
75
|
+
merge.roll
|
|
76
|
+
merge.values.should_not == a.values + b.values
|
|
80
77
|
end
|
|
81
78
|
it "should persist die types" do
|
|
82
79
|
(Pool.new("d6")+Pool.new("dF"))[1].should be_instance_of(FudgeDie)
|
|
83
80
|
(Pool.new("d6")+Pool.new([Coin.new]))[1].should respond_to(:flip)
|
|
84
81
|
end
|
|
85
82
|
it "should alter #dice accordingly" do
|
|
86
|
-
(Pool.new("2d17 d6")+Pool.new("3d17")).
|
|
83
|
+
(Pool.new("2d17 d6")+Pool.new("3d17")).d_notation.should == ["d6", "5d17"]
|
|
87
84
|
end
|
|
88
85
|
end
|
|
89
86
|
context "adding anything else" do
|
|
@@ -121,6 +118,13 @@ module Tabletop
|
|
|
121
118
|
end
|
|
122
119
|
|
|
123
120
|
describe "#roll" do
|
|
121
|
+
before :each do
|
|
122
|
+
@d1, @d2, @d3= double("a die"), double("a die"), double("a die")
|
|
123
|
+
@d1.stub(:value).and_return(1)
|
|
124
|
+
@d2.stub(:value).and_return(2)
|
|
125
|
+
@d3.stub(:value).and_return(3)
|
|
126
|
+
@p = Pool.new([@d1, @d2, @d3])
|
|
127
|
+
end
|
|
124
128
|
it "should return the Pool itself" do
|
|
125
129
|
actual = d6_set.roll
|
|
126
130
|
d6_set.length.times do |i|
|
|
@@ -128,15 +132,34 @@ module Tabletop
|
|
|
128
132
|
actual[i].sides.should == d6_set[i].sides
|
|
129
133
|
end
|
|
130
134
|
end
|
|
131
|
-
|
|
135
|
+
|
|
132
136
|
it "calls roll on its contents" do
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
137
|
+
@d1.should_receive(:roll)
|
|
138
|
+
@d2.should_receive(:roll)
|
|
139
|
+
@d3.should_receive(:roll)
|
|
140
|
+
@p.roll
|
|
141
|
+
end
|
|
142
|
+
it "can roll only dice less than a certain value" do
|
|
143
|
+
@d1.should_receive(:roll)
|
|
144
|
+
@d2.should_not_receive(:roll)
|
|
145
|
+
@d3.should_not_receive(:roll)
|
|
146
|
+
|
|
147
|
+
@p.roll(:value_under=>2)
|
|
148
|
+
end
|
|
149
|
+
it "can roll only dice above a certain value" do
|
|
150
|
+
@d1.should_not_receive(:roll)
|
|
151
|
+
@d2.should_not_receive(:roll)
|
|
152
|
+
@d3.should_receive(:roll)
|
|
153
|
+
|
|
154
|
+
@p.roll(:value_over=>2)
|
|
155
|
+
end
|
|
156
|
+
it "can roll only dice equal to a certain value" do
|
|
157
|
+
@d1.should_not_receive(:roll)
|
|
158
|
+
@d2.should_receive(:roll)
|
|
159
|
+
@d3.should_not_receive(:roll)
|
|
160
|
+
|
|
161
|
+
@p.roll(:value_equals=>2)
|
|
136
162
|
end
|
|
137
|
-
it "can roll only dice below a certain value"
|
|
138
|
-
it "can roll only dice above a certain value"
|
|
139
|
-
it "can roll only dice equal to a certain value"
|
|
140
163
|
end
|
|
141
164
|
|
|
142
165
|
describe "#roll_if" do
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
require '
|
|
2
|
-
|
|
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
|
-
|
|
1
|
+
require 'simplecov'
|
|
2
|
+
SimpleCov.start
|
|
10
3
|
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}
|
|
4
|
+
require 'tabletop'
|
data/tabletop.gemspec
CHANGED
metadata
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: tabletop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease:
|
|
5
|
-
version: 0.
|
|
5
|
+
version: 0.4.0
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
8
8
|
- Nick Novitski
|
|
@@ -67,6 +67,17 @@ dependencies:
|
|
|
67
67
|
type: :development
|
|
68
68
|
prerelease: false
|
|
69
69
|
version_requirements: *id005
|
|
70
|
+
- !ruby/object:Gem::Dependency
|
|
71
|
+
name: simplecov
|
|
72
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
|
73
|
+
none: false
|
|
74
|
+
requirements:
|
|
75
|
+
- - ">="
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: "0"
|
|
78
|
+
type: :development
|
|
79
|
+
prerelease: false
|
|
80
|
+
version_requirements: *id006
|
|
70
81
|
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.
|
|
71
82
|
email: nicknovitski@gmail.com
|
|
72
83
|
executables: []
|
|
@@ -77,6 +88,56 @@ extra_rdoc_files:
|
|
|
77
88
|
- LICENSE
|
|
78
89
|
- README.markdown
|
|
79
90
|
files:
|
|
91
|
+
- coverage/assets/0.5.3/app.js
|
|
92
|
+
- coverage/assets/0.5.3/fancybox/blank.gif
|
|
93
|
+
- coverage/assets/0.5.3/fancybox/fancy_close.png
|
|
94
|
+
- coverage/assets/0.5.3/fancybox/fancy_loading.png
|
|
95
|
+
- coverage/assets/0.5.3/fancybox/fancy_nav_left.png
|
|
96
|
+
- coverage/assets/0.5.3/fancybox/fancy_nav_right.png
|
|
97
|
+
- coverage/assets/0.5.3/fancybox/fancy_shadow_e.png
|
|
98
|
+
- coverage/assets/0.5.3/fancybox/fancy_shadow_n.png
|
|
99
|
+
- coverage/assets/0.5.3/fancybox/fancy_shadow_ne.png
|
|
100
|
+
- coverage/assets/0.5.3/fancybox/fancy_shadow_nw.png
|
|
101
|
+
- coverage/assets/0.5.3/fancybox/fancy_shadow_s.png
|
|
102
|
+
- coverage/assets/0.5.3/fancybox/fancy_shadow_se.png
|
|
103
|
+
- coverage/assets/0.5.3/fancybox/fancy_shadow_sw.png
|
|
104
|
+
- coverage/assets/0.5.3/fancybox/fancy_shadow_w.png
|
|
105
|
+
- coverage/assets/0.5.3/fancybox/fancy_title_left.png
|
|
106
|
+
- coverage/assets/0.5.3/fancybox/fancy_title_main.png
|
|
107
|
+
- coverage/assets/0.5.3/fancybox/fancy_title_over.png
|
|
108
|
+
- coverage/assets/0.5.3/fancybox/fancy_title_right.png
|
|
109
|
+
- coverage/assets/0.5.3/fancybox/fancybox-x.png
|
|
110
|
+
- coverage/assets/0.5.3/fancybox/fancybox-y.png
|
|
111
|
+
- coverage/assets/0.5.3/fancybox/fancybox.png
|
|
112
|
+
- coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.css
|
|
113
|
+
- coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.pack.js
|
|
114
|
+
- coverage/assets/0.5.3/favicon_green.png
|
|
115
|
+
- coverage/assets/0.5.3/favicon_red.png
|
|
116
|
+
- coverage/assets/0.5.3/favicon_yellow.png
|
|
117
|
+
- coverage/assets/0.5.3/highlight.css
|
|
118
|
+
- coverage/assets/0.5.3/highlight.pack.js
|
|
119
|
+
- coverage/assets/0.5.3/jquery-1.6.2.min.js
|
|
120
|
+
- coverage/assets/0.5.3/jquery.dataTables.min.js
|
|
121
|
+
- coverage/assets/0.5.3/jquery.timeago.js
|
|
122
|
+
- coverage/assets/0.5.3/jquery.url.js
|
|
123
|
+
- coverage/assets/0.5.3/loading.gif
|
|
124
|
+
- coverage/assets/0.5.3/magnify.png
|
|
125
|
+
- coverage/assets/0.5.3/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
|
|
126
|
+
- coverage/assets/0.5.3/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
|
|
127
|
+
- coverage/assets/0.5.3/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
|
|
128
|
+
- coverage/assets/0.5.3/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
|
|
129
|
+
- coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_dadada_1x400.png
|
|
130
|
+
- coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
|
|
131
|
+
- coverage/assets/0.5.3/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
|
|
132
|
+
- coverage/assets/0.5.3/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
|
|
133
|
+
- coverage/assets/0.5.3/smoothness/images/ui-icons_222222_256x240.png
|
|
134
|
+
- coverage/assets/0.5.3/smoothness/images/ui-icons_2e83ff_256x240.png
|
|
135
|
+
- coverage/assets/0.5.3/smoothness/images/ui-icons_454545_256x240.png
|
|
136
|
+
- coverage/assets/0.5.3/smoothness/images/ui-icons_888888_256x240.png
|
|
137
|
+
- coverage/assets/0.5.3/smoothness/images/ui-icons_cd0a0a_256x240.png
|
|
138
|
+
- coverage/assets/0.5.3/smoothness/jquery-ui-1.8.4.custom.css
|
|
139
|
+
- coverage/assets/0.5.3/stylesheet.css
|
|
140
|
+
- coverage/index.html
|
|
80
141
|
- doc/created.rid
|
|
81
142
|
- doc/Fixnum.html
|
|
82
143
|
- doc/images/brick.png
|
|
@@ -124,6 +185,7 @@ files:
|
|
|
124
185
|
- Gemfile
|
|
125
186
|
- lib/fixnum.rb
|
|
126
187
|
- lib/tabletop/condition.rb
|
|
188
|
+
- lib/tabletop/deck.rb
|
|
127
189
|
- lib/tabletop/pool.rb
|
|
128
190
|
- lib/tabletop/randomizers.rb
|
|
129
191
|
- lib/tabletop/roll.rb
|
|
@@ -134,6 +196,57 @@ files:
|
|
|
134
196
|
- Rakefile
|
|
135
197
|
- README.markdown
|
|
136
198
|
- spec/condition_spec.rb
|
|
199
|
+
- spec/coverage/assets/0.5.3/app.js
|
|
200
|
+
- spec/coverage/assets/0.5.3/fancybox/blank.gif
|
|
201
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_close.png
|
|
202
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_loading.png
|
|
203
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_nav_left.png
|
|
204
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_nav_right.png
|
|
205
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_e.png
|
|
206
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_n.png
|
|
207
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_ne.png
|
|
208
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_nw.png
|
|
209
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_s.png
|
|
210
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_se.png
|
|
211
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_sw.png
|
|
212
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_w.png
|
|
213
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_title_left.png
|
|
214
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_title_main.png
|
|
215
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_title_over.png
|
|
216
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_title_right.png
|
|
217
|
+
- spec/coverage/assets/0.5.3/fancybox/fancybox-x.png
|
|
218
|
+
- spec/coverage/assets/0.5.3/fancybox/fancybox-y.png
|
|
219
|
+
- spec/coverage/assets/0.5.3/fancybox/fancybox.png
|
|
220
|
+
- spec/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.css
|
|
221
|
+
- spec/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.pack.js
|
|
222
|
+
- spec/coverage/assets/0.5.3/favicon_green.png
|
|
223
|
+
- spec/coverage/assets/0.5.3/favicon_red.png
|
|
224
|
+
- spec/coverage/assets/0.5.3/favicon_yellow.png
|
|
225
|
+
- spec/coverage/assets/0.5.3/highlight.css
|
|
226
|
+
- spec/coverage/assets/0.5.3/highlight.pack.js
|
|
227
|
+
- spec/coverage/assets/0.5.3/jquery-1.6.2.min.js
|
|
228
|
+
- spec/coverage/assets/0.5.3/jquery.dataTables.min.js
|
|
229
|
+
- spec/coverage/assets/0.5.3/jquery.timeago.js
|
|
230
|
+
- spec/coverage/assets/0.5.3/jquery.url.js
|
|
231
|
+
- spec/coverage/assets/0.5.3/loading.gif
|
|
232
|
+
- spec/coverage/assets/0.5.3/magnify.png
|
|
233
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
|
|
234
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
|
|
235
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
|
|
236
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
|
|
237
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_dadada_1x400.png
|
|
238
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
|
|
239
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
|
|
240
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
|
|
241
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-icons_222222_256x240.png
|
|
242
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-icons_2e83ff_256x240.png
|
|
243
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-icons_454545_256x240.png
|
|
244
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-icons_888888_256x240.png
|
|
245
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-icons_cd0a0a_256x240.png
|
|
246
|
+
- spec/coverage/assets/0.5.3/smoothness/jquery-ui-1.8.4.custom.css
|
|
247
|
+
- spec/coverage/assets/0.5.3/stylesheet.css
|
|
248
|
+
- spec/coverage/index.html
|
|
249
|
+
- spec/deck_spec.rb
|
|
137
250
|
- spec/fixnum_spec.rb
|
|
138
251
|
- spec/pool_spec.rb
|
|
139
252
|
- spec/randomizers_spec.rb
|
|
@@ -155,7 +268,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
155
268
|
requirements:
|
|
156
269
|
- - ">="
|
|
157
270
|
- !ruby/object:Gem::Version
|
|
158
|
-
hash:
|
|
271
|
+
hash: -2442987682132944901
|
|
159
272
|
segments:
|
|
160
273
|
- 0
|
|
161
274
|
version: "0"
|
|
@@ -174,6 +287,57 @@ specification_version: 3
|
|
|
174
287
|
summary: An RPG and tabletop game library
|
|
175
288
|
test_files:
|
|
176
289
|
- spec/condition_spec.rb
|
|
290
|
+
- spec/coverage/assets/0.5.3/app.js
|
|
291
|
+
- spec/coverage/assets/0.5.3/fancybox/blank.gif
|
|
292
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_close.png
|
|
293
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_loading.png
|
|
294
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_nav_left.png
|
|
295
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_nav_right.png
|
|
296
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_e.png
|
|
297
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_n.png
|
|
298
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_ne.png
|
|
299
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_nw.png
|
|
300
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_s.png
|
|
301
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_se.png
|
|
302
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_sw.png
|
|
303
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_shadow_w.png
|
|
304
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_title_left.png
|
|
305
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_title_main.png
|
|
306
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_title_over.png
|
|
307
|
+
- spec/coverage/assets/0.5.3/fancybox/fancy_title_right.png
|
|
308
|
+
- spec/coverage/assets/0.5.3/fancybox/fancybox-x.png
|
|
309
|
+
- spec/coverage/assets/0.5.3/fancybox/fancybox-y.png
|
|
310
|
+
- spec/coverage/assets/0.5.3/fancybox/fancybox.png
|
|
311
|
+
- spec/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.css
|
|
312
|
+
- spec/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.pack.js
|
|
313
|
+
- spec/coverage/assets/0.5.3/favicon_green.png
|
|
314
|
+
- spec/coverage/assets/0.5.3/favicon_red.png
|
|
315
|
+
- spec/coverage/assets/0.5.3/favicon_yellow.png
|
|
316
|
+
- spec/coverage/assets/0.5.3/highlight.css
|
|
317
|
+
- spec/coverage/assets/0.5.3/highlight.pack.js
|
|
318
|
+
- spec/coverage/assets/0.5.3/jquery-1.6.2.min.js
|
|
319
|
+
- spec/coverage/assets/0.5.3/jquery.dataTables.min.js
|
|
320
|
+
- spec/coverage/assets/0.5.3/jquery.timeago.js
|
|
321
|
+
- spec/coverage/assets/0.5.3/jquery.url.js
|
|
322
|
+
- spec/coverage/assets/0.5.3/loading.gif
|
|
323
|
+
- spec/coverage/assets/0.5.3/magnify.png
|
|
324
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
|
|
325
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
|
|
326
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
|
|
327
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
|
|
328
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_dadada_1x400.png
|
|
329
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
|
|
330
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
|
|
331
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
|
|
332
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-icons_222222_256x240.png
|
|
333
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-icons_2e83ff_256x240.png
|
|
334
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-icons_454545_256x240.png
|
|
335
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-icons_888888_256x240.png
|
|
336
|
+
- spec/coverage/assets/0.5.3/smoothness/images/ui-icons_cd0a0a_256x240.png
|
|
337
|
+
- spec/coverage/assets/0.5.3/smoothness/jquery-ui-1.8.4.custom.css
|
|
338
|
+
- spec/coverage/assets/0.5.3/stylesheet.css
|
|
339
|
+
- spec/coverage/index.html
|
|
340
|
+
- spec/deck_spec.rb
|
|
177
341
|
- spec/fixnum_spec.rb
|
|
178
342
|
- spec/pool_spec.rb
|
|
179
343
|
- spec/randomizers_spec.rb
|