ace_of_spades 0.0.1.pre
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 +18 -0
- data/.rbenv-version +1 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/Guardfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +188 -0
- data/Rakefile +1 -0
- data/ace_of_spades.gemspec +20 -0
- data/lib/ace_of_spades.rb +8 -0
- data/lib/ace_of_spades/card.rb +88 -0
- data/lib/ace_of_spades/deck.rb +95 -0
- data/lib/ace_of_spades/suit.rb +45 -0
- data/lib/ace_of_spades/value.rb +58 -0
- data/spec/lib/card_spec.rb +294 -0
- data/spec/lib/deck_spec.rb +291 -0
- data/spec/lib/suit_spec.rb +196 -0
- data/spec/lib/value_spec.rb +234 -0
- data/spec/spec_helper.rb +14 -0
- metadata +117 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
class AceOfSpades::Suit
|
2
|
+
include Comparable
|
3
|
+
attr_accessor :card
|
4
|
+
|
5
|
+
def initialize(suit)
|
6
|
+
@symbol = Suit.parse(suit)
|
7
|
+
raise "Invalid argument: #{suit}" unless @symbol
|
8
|
+
end
|
9
|
+
|
10
|
+
def <=>(suit)
|
11
|
+
return nil unless suit.instance_of?(Suit)
|
12
|
+
SUITS.index(@symbol) <=> SUITS.index(suit.to_sym)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_sym
|
16
|
+
@symbol
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
@symbol.to_s
|
21
|
+
end
|
22
|
+
alias_method :to_str, :to_s
|
23
|
+
|
24
|
+
def method_missing(method, *args, &block)
|
25
|
+
match = Suit.parse(%r(.+\?\z).match(method).to_s.chop)
|
26
|
+
return super unless match
|
27
|
+
@symbol == match
|
28
|
+
end
|
29
|
+
|
30
|
+
class << self
|
31
|
+
def suitable?(suit)
|
32
|
+
!!parse(suit)
|
33
|
+
end
|
34
|
+
|
35
|
+
def wrap(suit)
|
36
|
+
return suit if suit.instance_of?(Suit)
|
37
|
+
new(suit) if suitable?(suit)
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse(arg)
|
41
|
+
regex = arg.to_s.length == 1 ? %r(\A#{arg})i : %r(\A#{arg}(s*)\z)i
|
42
|
+
SUITS.grep(regex).first
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class AceOfSpades::Value
|
2
|
+
include Comparable
|
3
|
+
attr_accessor :card
|
4
|
+
|
5
|
+
def initialize(value)
|
6
|
+
@symbol = Value.parse(value)
|
7
|
+
raise "Invalid argument: #{value}" unless @symbol
|
8
|
+
end
|
9
|
+
|
10
|
+
def <=>(value)
|
11
|
+
return nil unless value.instance_of?(Value)
|
12
|
+
to_i <=> value.to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_sym
|
16
|
+
@symbol
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
@symbol.to_s
|
21
|
+
end
|
22
|
+
alias_method :to_str, :to_s
|
23
|
+
|
24
|
+
def to_i
|
25
|
+
aces_high? ? VALUES.rindex(@symbol) + 1 : VALUES.index(@symbol) + 1
|
26
|
+
end#
|
27
|
+
alias_method :to_int, :to_i
|
28
|
+
|
29
|
+
def aces_high?
|
30
|
+
return true unless card
|
31
|
+
card.aces_high?
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing(method, *args, &block)
|
35
|
+
match = Value.parse(%r(.+\?\z).match(method).to_s.chop)
|
36
|
+
return super unless match
|
37
|
+
@symbol == match
|
38
|
+
end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
def valuable?(value)
|
42
|
+
!!parse(value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def wrap(value)
|
46
|
+
return value if value.instance_of?(Value)
|
47
|
+
new(value) if valuable?(value)
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse(arg)
|
51
|
+
return VALUES[arg - 1] if (1..14).include?(arg)
|
52
|
+
short_arg = arg.to_s.length == 1
|
53
|
+
regex = short_arg ? %r(\A#{arg})i : %r(\A#{arg}\z)i
|
54
|
+
values = short_arg ? VALUES[-4..-1] : VALUES
|
55
|
+
values.grep(regex).first
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,294 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Card do
|
4
|
+
let(:ace_spades) { Card.new(:ace, :spades) }
|
5
|
+
let(:joker) { Card.new(:joker) }
|
6
|
+
|
7
|
+
describe '.new' do
|
8
|
+
context "when called with valid arguments" do
|
9
|
+
let(:ten_hearts) { Card.new(10, 'h') }
|
10
|
+
it "initializes" do
|
11
|
+
expect(ace_spades).to be_an_instance_of(Card)
|
12
|
+
expect(ten_hearts).to be_an_instance_of(Card)
|
13
|
+
end
|
14
|
+
it "correctly saves the suit" do
|
15
|
+
expect(ace_spades.suit.to_sym).to be(:Spades)
|
16
|
+
expect(ten_hearts.suit.to_sym).to be(:Hearts)
|
17
|
+
end
|
18
|
+
it "correctly saves the value" do
|
19
|
+
expect(ace_spades.value.to_sym).to be(:Ace)
|
20
|
+
expect(ten_hearts.value.to_sym).to be(:Ten)
|
21
|
+
end
|
22
|
+
it "saves self as value.card and suit.card" do
|
23
|
+
expect(ace_spades.value.card).to be(ace_spades)
|
24
|
+
expect(ace_spades.suit.card).to be(ace_spades)
|
25
|
+
end
|
26
|
+
context "when a joker" do
|
27
|
+
it "initializes as a joker" do
|
28
|
+
expect(joker.suit).to be_nil
|
29
|
+
expect(joker.value).to be_nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
context "when initialized with invalid arguments" do
|
34
|
+
it "raises an error" do
|
35
|
+
expect{Card.new}.to raise_error
|
36
|
+
expect{Card.new(:joker, :foo)}.to raise_error
|
37
|
+
expect{Card.new(:ace, :foo)}.to raise_error
|
38
|
+
expect{Card.new('a', 5)}.to raise_error
|
39
|
+
expect{Card.new(:foo)}.to raise_error
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '.wrap' do
|
45
|
+
context "when passed a Card instance" do
|
46
|
+
it "returns the card instance" do
|
47
|
+
expect(Card.wrap(joker)).to be(joker)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
context "when passed arguments that can be converted into a Card instance" do
|
51
|
+
it "returns the arguments as a Card instance" do
|
52
|
+
expect(Card.wrap(:ace, :spades)).to eq(ace_spades)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
context "when passed arguments that cannot me converted into a Card instance" do
|
56
|
+
it "returns nil" do
|
57
|
+
expect(Card.wrap(:foo)).to be_nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#value=' do
|
63
|
+
let(:card) { ace_spades }
|
64
|
+
context "when passed a Value instance" do
|
65
|
+
it "assigns the Value" do
|
66
|
+
card.value = Value.new(:king)
|
67
|
+
expect(card.value).to be_an_instance_of(Value)
|
68
|
+
expect(card.value.to_sym).to be(:King)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
context "when passed an object that can be converted to a Value" do
|
72
|
+
it "assigns the Value" do
|
73
|
+
card.value = :king
|
74
|
+
expect(card.value).to be_an_instance_of(Value)
|
75
|
+
expect(card.value.to_sym).to be(:King)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
context "when passed an object that cannot be converted to a Value" do
|
79
|
+
it "assigns nil" do
|
80
|
+
card.value = :foo
|
81
|
+
expect(card.value).to be_nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#suit=' do
|
87
|
+
let(:card) { ace_spades }
|
88
|
+
context "when passed a Suit instance" do
|
89
|
+
it "assigns the Suit" do
|
90
|
+
card.suit = Suit.new(:hearts)
|
91
|
+
expect(card.suit).to be_an_instance_of(Suit)
|
92
|
+
expect(card.suit.to_sym).to be(:Hearts)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
context "when passed an object that can be converted to a Suit" do
|
96
|
+
it "assigns the Suit" do
|
97
|
+
card.suit = :hearts
|
98
|
+
expect(card.suit).to be_an_instance_of(Suit)
|
99
|
+
expect(card.suit.to_sym).to be(:Hearts)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
context "when passed an object that cannot be converted to a Suit" do
|
103
|
+
it "assigns nil" do
|
104
|
+
card.suit = :foo
|
105
|
+
expect(card.suit).to be_nil
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe '#deck & #deck=' do
|
111
|
+
let(:deck) { Deck.new }
|
112
|
+
let(:card) { ace_spades }
|
113
|
+
it "retrieves the deck" do
|
114
|
+
expect(card.deck).to be_nil
|
115
|
+
end
|
116
|
+
it "assigns the deck" do
|
117
|
+
card.deck = deck
|
118
|
+
expect(card.deck).to be(deck)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#aces_high?' do
|
123
|
+
let(:deck) { Deck.new(aces_high: true) }
|
124
|
+
let(:card) { ace_spades }
|
125
|
+
it "returns the #aces_high? result from the deck" do
|
126
|
+
card.deck = deck
|
127
|
+
expect(card.aces_high?).to be(true)
|
128
|
+
deck.aces_high = false
|
129
|
+
expect(card.aces_high?).to be(false)
|
130
|
+
end
|
131
|
+
context "when the card has no deck" do
|
132
|
+
it "returns true" do
|
133
|
+
expect(card.aces_high?).to be(true)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe'#<=>' do
|
139
|
+
let(:ace_hearts) { Card.new(14, :H) }
|
140
|
+
let(:king_spades) { Card.new(13, :S) }
|
141
|
+
let(:king_hearts) { Card.new(13, :H) }
|
142
|
+
context "when passed an incomparable object" do
|
143
|
+
it "returns nil" do
|
144
|
+
expect(ace_spades <=> 5).to be_nil
|
145
|
+
end
|
146
|
+
end
|
147
|
+
context "when passed a card with the same value and suit" do
|
148
|
+
let(:ace_of_spades) { Card.new(14, :S) }
|
149
|
+
it "returns 0" do
|
150
|
+
expect(ace_spades <=> ace_of_spades).to be(0)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
context "when passed a card with a higher suit" do
|
154
|
+
it "returns -1" do
|
155
|
+
expect(ace_hearts <=> ace_spades).to be(-1)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
context "when passed a card with a lower suit" do
|
159
|
+
it "returns 1" do
|
160
|
+
expect(ace_spades <=> ace_hearts).to be(1)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
context "when passed a card with a higher suit and a lower value" do
|
164
|
+
it "returns -1" do
|
165
|
+
expect(ace_hearts <=> king_spades).to be(-1)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
context "when passed a card with a lower suit and a higher value" do
|
169
|
+
it "returns 1" do
|
170
|
+
expect(king_spades <=> ace_hearts).to be(1)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
context "when passed a joker" do
|
174
|
+
it "returns nil" do
|
175
|
+
expect(ace_spades <=> joker).to be_nil
|
176
|
+
end
|
177
|
+
end
|
178
|
+
describe Comparable do
|
179
|
+
it "compares correctly" do
|
180
|
+
expect(ace_spades == ace_spades).to be(true)
|
181
|
+
expect(ace_hearts < ace_spades).to be(true)
|
182
|
+
expect(ace_spades > ace_hearts).to be(true)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe '#to_s' do
|
188
|
+
context "when a joker" do
|
189
|
+
it "returns 'Joker'" do
|
190
|
+
expect(joker.to_s).to eq('Joker')
|
191
|
+
end
|
192
|
+
end
|
193
|
+
context "when not a joker" do
|
194
|
+
it "returns 'Value of Suit'" do
|
195
|
+
expect(ace_spades.to_s).to eq('Ace of Spades')
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe '#to_sym' do
|
201
|
+
context "when a joker" do
|
202
|
+
it "returns :Joker" do
|
203
|
+
expect(joker.to_sym).to eq(:Joker)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
context "when not a joker" do
|
207
|
+
it "returns :'Value of Suit'" do
|
208
|
+
expect(ace_spades.to_sym).to eq(:'Ace of Spades')
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe '#valid?' do
|
214
|
+
context "when valid" do
|
215
|
+
it "returns true" do
|
216
|
+
expect(ace_spades.valid?).to be(true)
|
217
|
+
expect(joker.valid?).to be(true)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
context "when invalid" do
|
221
|
+
it "returns false" do
|
222
|
+
ace_spades.instance_variable_set(:@value, 'foo')
|
223
|
+
ace_spades.instance_variable_set(:@suit, 'bar')
|
224
|
+
expect(ace_spades.valid?).to be(false)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
describe '#joker?' do
|
229
|
+
context "when a joker" do
|
230
|
+
it "returns true" do
|
231
|
+
expect(joker.joker?).to be(true)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
context "when not a joker" do
|
235
|
+
it "returns false" do
|
236
|
+
expect(ace_spades.joker?).to be(false)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe '#validate!' do
|
242
|
+
context "when valid" do
|
243
|
+
it "returns self" do
|
244
|
+
expect(ace_spades.validate!).to be(ace_spades)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
context "when invalid" do
|
248
|
+
it "raises error" do
|
249
|
+
ace_spades.instance_variable_set(:@value, false)
|
250
|
+
ace_spades.instance_variable_set(:@suit, false)
|
251
|
+
expect{ace_spades.validate!}.to raise_error
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe '#method_missing' do
|
257
|
+
context "when passed a valid predicate method" do
|
258
|
+
context "when a value" do
|
259
|
+
it "returns true or false" do
|
260
|
+
expect(ace_spades.ace?).to be(true)
|
261
|
+
expect(ace_spades.king?).to be(false)
|
262
|
+
expect(joker.ace?).to be(false)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
context "when a suit" do
|
266
|
+
it "returns true or false" do
|
267
|
+
expect(ace_spades.spade?).to be(true)
|
268
|
+
expect(ace_spades.spades?).to be(true)
|
269
|
+
expect(ace_spades.hearts?).to be(false)
|
270
|
+
expect(joker.spades?).to be(false)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
context "when a value and suit" do
|
274
|
+
it "returns true or false" do
|
275
|
+
expect(ace_spades.ace_spades?).to be(true)
|
276
|
+
expect(ace_spades.ace_of_spades?).to be(true)
|
277
|
+
expect(ace_spades.ace_of_hearts?).to be(false)
|
278
|
+
expect(ace_spades.king_spades?).to be(false)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
context "when passed an invalid predicate method" do
|
283
|
+
it "raises error" do
|
284
|
+
expect{ace_spades.foo?}.to raise_error(NoMethodError)
|
285
|
+
expect{ace_spades.ace_foo?}.to raise_error(NoMethodError)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
context "when passed an invalid method" do
|
289
|
+
it "raises error" do
|
290
|
+
expect{ace_spades.foo}.to raise_error(NoMethodError)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
@@ -0,0 +1,291 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Deck do
|
4
|
+
let(:deck) { Deck.new }
|
5
|
+
|
6
|
+
describe '.new' do
|
7
|
+
context "when passed valid params" do
|
8
|
+
it "initializes with 52 cards" do
|
9
|
+
expect(deck.length).to be(52)
|
10
|
+
end
|
11
|
+
it "initializes with 4 suits" do
|
12
|
+
expect(deck.group_by{|c|c.suit.to_sym}.count).to be(4)
|
13
|
+
end
|
14
|
+
it "initializes with 13 values" do
|
15
|
+
expect(deck.group_by{|c|c.value.to_sym}.count).to be(13)
|
16
|
+
end
|
17
|
+
it "initializes with 13 values per suit" do
|
18
|
+
values_per_suit = deck.group_by{|c|c.suit.to_sym}[:Spades].group_by{|c|c.value.to_sym}.count
|
19
|
+
expect(values_per_suit).to be(13)
|
20
|
+
end
|
21
|
+
it "initializes as shuffled" do
|
22
|
+
expect(deck[0..12].group_by{|c|c.suit.to_sym}.count).to_not be(1)
|
23
|
+
expect(deck[0..12].group_by{|c|c.value.to_sym}.count).to_not be(13)
|
24
|
+
end
|
25
|
+
it "initializes with aces high" do
|
26
|
+
expect(deck.aces_high?).to be(true)
|
27
|
+
end
|
28
|
+
context "when initialized with (false)" do
|
29
|
+
let(:deck) { Deck.new(false) }
|
30
|
+
it "creates the deck but does not add any cards" do
|
31
|
+
expect(deck.empty?).to be(true)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
context "when initialized with {jokers: true}" do
|
35
|
+
let(:deck) { Deck.new(jokers: true) }
|
36
|
+
it "initializes with 54 cards" do
|
37
|
+
expect(deck.length).to be(54)
|
38
|
+
end
|
39
|
+
it "initializes with 2 jokers" do
|
40
|
+
expect(deck.find_cards(:joker).count).to be(2)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
context "when initialized with {shuffle: false}" do
|
44
|
+
let(:deck) { Deck.new(shuffle: false) }
|
45
|
+
it "initializes in an unshuffled order by suit" do
|
46
|
+
expect(deck[0..12].group_by{|c|c.suit.to_sym}.count).to be(1)
|
47
|
+
end
|
48
|
+
it "initializes in an unshuffled order by value" do
|
49
|
+
deck[0..12].reduce do |memo, card|
|
50
|
+
expect(memo.value < card.value).to be(true)
|
51
|
+
card
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
context "when initialized with {aces_high: false}" do
|
56
|
+
let(:deck) { Deck.new(aces_high: false) }
|
57
|
+
it "initalizes with aces low" do
|
58
|
+
expect(deck.aces_high?).to be(false)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#find_card' do
|
65
|
+
context "when passed an argument" do
|
66
|
+
context "when the card exists" do
|
67
|
+
it "returns the card" do
|
68
|
+
card = deck.find_card(:ace, :spades)
|
69
|
+
expect(card.ace_of_spades?).to be(true)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
context "when the card does not exist" do
|
73
|
+
it "returns nil" do
|
74
|
+
card = deck.find_card(:foo)
|
75
|
+
expect(card).to be_nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
context "when passed a block" do
|
80
|
+
it "returns the first card that yields the block as true" do
|
81
|
+
card = deck.find_card { |c| c.ace? }
|
82
|
+
expect(card.ace?).to be(true)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '#find_cards' do
|
88
|
+
context "when passed an argument" do
|
89
|
+
context "when there are cards that match the argument" do
|
90
|
+
it "returns an array of matching cards" do
|
91
|
+
cards = deck.find_cards(:ace)
|
92
|
+
expect(cards.count).to be(4)
|
93
|
+
cards.each { |c| expect(c.ace?).to be(true) }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
context "when no cards match" do
|
97
|
+
it "returns an empty array" do
|
98
|
+
cards = deck.find_cards(:foo)
|
99
|
+
expect(cards.empty?).to be(true)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
context "when passed a block" do
|
104
|
+
it "returns cards that yield as true" do
|
105
|
+
cards = deck.find_cards { |c| c.ace? }
|
106
|
+
expect(cards.count).to be(4)
|
107
|
+
cards.each { |c| expect(c.ace?).to be(true) }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#add_card' do
|
113
|
+
it "adds specified card to self" do
|
114
|
+
deck.add_card('ace', 'spades')
|
115
|
+
expect(deck.count).to be(53)
|
116
|
+
expect(deck.last.to_s).to eq('Ace of Spades')
|
117
|
+
end
|
118
|
+
it "adds self as card.deck" do
|
119
|
+
expect(deck.sample.deck).to be(deck)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#remove_cards' do
|
124
|
+
context "when passed an argument" do
|
125
|
+
let(:aces) { deck.remove_cards(:ace) }
|
126
|
+
it "removes matching cards from the deck" do
|
127
|
+
expect(aces.count).to be(4)
|
128
|
+
expect(deck.find{|c|c.ace?}).to be_nil
|
129
|
+
end
|
130
|
+
end
|
131
|
+
context "when passed a block" do
|
132
|
+
let(:spades) { deck.remove_cards {|c|c.spade?} }
|
133
|
+
it "removes cards that yield to true" do
|
134
|
+
expect(spades.count).to be(13)
|
135
|
+
expect(deck.find{|c|c.spade?}).to be_nil
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#aces_high?' do
|
141
|
+
context "when aces are high" do
|
142
|
+
it "returns true" do
|
143
|
+
expect(deck.aces_high?).to be(true)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
context "when aces are low" do
|
147
|
+
it "returns false" do
|
148
|
+
deck.aces_high = false
|
149
|
+
expect(deck.aces_high?).to be(false)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe '#jokers?' do
|
155
|
+
context "there is a joker or jokers in the deck" do
|
156
|
+
it "returns true" do
|
157
|
+
deck.add_card(:joker)
|
158
|
+
expect(deck.jokers?).to be(true)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
context "when there are no jokers" do
|
162
|
+
it "returns false" do
|
163
|
+
expect(deck.jokers?).to be(false)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#deal' do
|
169
|
+
context "when called with no argument" do
|
170
|
+
it "deals 1 card when called with no argument" do
|
171
|
+
expect(deck.deal).to be_a(Card)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
context "when called with an integer argument" do
|
175
|
+
it "deals multiple cards in an array when called with an integer argument" do
|
176
|
+
cards = deck.deal(10)
|
177
|
+
expect(cards.count).to be(10)
|
178
|
+
expect(cards.all?{|c|c.instance_of?(Card)}).to be(true)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
it "removes dealt cards from deck" do
|
182
|
+
deck.deal
|
183
|
+
expect(deck.count).to be(51)
|
184
|
+
deck.deal(9)
|
185
|
+
expect(deck.count).to be(42)
|
186
|
+
end
|
187
|
+
it "stores dealt cards in another array" do
|
188
|
+
expect(deck.deal).to be(deck.dealt.first)
|
189
|
+
deck.deal(9)
|
190
|
+
expect(deck.dealt.count).to be(10)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe '#shuffle!' do
|
195
|
+
it "shuffles the deck" do
|
196
|
+
dup = deck.dup
|
197
|
+
expect(deck.shuffle!).to_not eq(dup)
|
198
|
+
end
|
199
|
+
it "returns dealt cards to the deck before shuffling" do
|
200
|
+
deck.deal(10)
|
201
|
+
deck.shuffle!
|
202
|
+
expect(deck.count).to be(52)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe '#shuffle' do
|
207
|
+
it "shuffles the deck non-destructively" do
|
208
|
+
expect(deck.shuffle).to_not be(deck)
|
209
|
+
end
|
210
|
+
it "returns dealt cards to the deck before shuffling" do
|
211
|
+
deck.deal(10)
|
212
|
+
expect(deck.count).to be(42)
|
213
|
+
expect(deck.shuffle.count).to be(52)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe '#unshuffle!' do
|
218
|
+
let(:deck) { Deck.new(jokers: true) }
|
219
|
+
it "returns any dealt cards to the deck" do
|
220
|
+
deck.deal(10)
|
221
|
+
expect(deck.unshuffle!.count).to be(54)
|
222
|
+
end
|
223
|
+
it "sorts the deck from lowest to highest" do
|
224
|
+
deck.remove_cards(:joker)
|
225
|
+
deck.unshuffle!.reduce do |memo, card|
|
226
|
+
expect(memo < card).to be(true)
|
227
|
+
card
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe '#unshuffle' do
|
233
|
+
let(:deck) { Deck.new(jokers: true, shuffle:true) }
|
234
|
+
it "it unshuffles nondestructively" do
|
235
|
+
deck.deal(10)
|
236
|
+
expect(deck.unshuffle.count).to be(54)
|
237
|
+
expect(deck.count).to be(44)
|
238
|
+
end
|
239
|
+
it "sorts the deck from lowest to highest nondestructively" do
|
240
|
+
deck.remove_cards(:joker)
|
241
|
+
deck.unshuffle.reduce do |memo, card|
|
242
|
+
expect(memo < card).to be(true)
|
243
|
+
card
|
244
|
+
end
|
245
|
+
first_suit = deck[0..12].group_by{|c|c.suit.to_sym}
|
246
|
+
expect(first_suit.count).to_not be(1)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe '#valid?' do
|
251
|
+
describe "without jokers" do
|
252
|
+
context "when valid" do
|
253
|
+
it "returns true" do
|
254
|
+
expect(deck.valid?).to be(true)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
context "when invalid" do
|
258
|
+
context "when wrong length" do
|
259
|
+
it "returns false" do
|
260
|
+
deck.remove_cards(:spades)
|
261
|
+
expect(deck.valid?).to be(false)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
context "when wrong cards" do
|
265
|
+
it "returns false" do
|
266
|
+
deck.remove_cards(:ace, :spades)
|
267
|
+
deck.add_card(:king, :spades)
|
268
|
+
expect(deck.valid?).to be(false)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
describe "with jokers" do
|
275
|
+
let(:deck) { Deck.new(jokers: true) }
|
276
|
+
context "when valid" do
|
277
|
+
it "returns true" do
|
278
|
+
expect(deck.valid?).to be(true)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
context "when invalid" do
|
282
|
+
context "when wrong cards" do
|
283
|
+
it "returns false" do
|
284
|
+
deck.remove_cards(:ace, :spades)
|
285
|
+
deck.add_card(:joker)
|
286
|
+
expect(deck.valid?).to be(false)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|