patience 0.1.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/CHANGELOG.md +6 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +17 -0
- data/LICENSE +19 -0
- data/README.md +111 -0
- data/Rakefile +11 -0
- data/bin/patience +5 -0
- data/lib/patience.rb +13 -0
- data/lib/patience/area.rb +62 -0
- data/lib/patience/card.rb +107 -0
- data/lib/patience/core_ext/class.rb +17 -0
- data/lib/patience/core_ext/core_ext.rb +1 -0
- data/lib/patience/core_ext/object.rb +37 -0
- data/lib/patience/core_ext/string.rb +33 -0
- data/lib/patience/cursor.rb +66 -0
- data/lib/patience/deck.rb +21 -0
- data/lib/patience/event_handlers/click.rb +99 -0
- data/lib/patience/event_handlers/drag.rb +36 -0
- data/lib/patience/event_handlers/drop.rb +147 -0
- data/lib/patience/foundation.rb +30 -0
- data/lib/patience/game.rb +10 -0
- data/lib/patience/pile.rb +78 -0
- data/lib/patience/processable.rb +87 -0
- data/lib/patience/rank.rb +56 -0
- data/lib/patience/scenes/game_scene.rb +66 -0
- data/lib/patience/sprites/card_deck.png +0 -0
- data/lib/patience/sprites/empty_stock.png +0 -0
- data/lib/patience/sprites/pile_background.png +0 -0
- data/lib/patience/stock.rb +20 -0
- data/lib/patience/suit.rb +73 -0
- data/lib/patience/tableau.rb +42 -0
- data/lib/patience/version.rb +3 -0
- data/lib/patience/waste.rb +18 -0
- data/test/patience/core_ext/test_class.rb +28 -0
- data/test/patience/core_ext/test_object.rb +15 -0
- data/test/patience/core_ext/test_string.rb +35 -0
- data/test/patience/event_handlers/test_click.rb +142 -0
- data/test/patience/event_handlers/test_drag.rb +45 -0
- data/test/patience/event_handlers/test_drop.rb +175 -0
- data/test/patience/helper.rb +8 -0
- data/test/patience/scenes/test_game_scene.rb +14 -0
- data/test/patience/test_area.rb +74 -0
- data/test/patience/test_card.rb +165 -0
- data/test/patience/test_cursor.rb +77 -0
- data/test/patience/test_deck.rb +53 -0
- data/test/patience/test_foundation.rb +38 -0
- data/test/patience/test_game.rb +29 -0
- data/test/patience/test_pile.rb +83 -0
- data/test/patience/test_processable.rb +159 -0
- data/test/patience/test_rank.rb +88 -0
- data/test/patience/test_stock.rb +43 -0
- data/test/patience/test_suit.rb +87 -0
- data/test/patience/test_tableau.rb +57 -0
- data/test/patience/test_version.rb +11 -0
- data/test/patience/test_waste.rb +35 -0
- metadata +135 -0
@@ -0,0 +1,165 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
module Patience
|
4
|
+
class TestCard < TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@card = Card.new(13, 3)
|
8
|
+
@ranks = %w[Two Three Four Five Six Seven Eight
|
9
|
+
Nine Ten Jack Queen King Ace].map { |rank|
|
10
|
+
"Patience::Card::Rank::#{rank}".constantize
|
11
|
+
}
|
12
|
+
@suits = %w[Heart Diamond Spade Club].map { |suit|
|
13
|
+
"Patience::Card::Suit::#{suit}".constantize
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
test 'A card accepts only valid ranks' do
|
18
|
+
@ranks.size.times { |i| assert Card.new(i+1, 1) }
|
19
|
+
assert_raises(Card::DefunctRank) { Card.new(0, 1) }
|
20
|
+
assert_raises(Card::DefunctRank) { Card.new(14, 2) }
|
21
|
+
assert_raises(Card::DefunctRank) { Card.new(-5, 3) }
|
22
|
+
assert_raises(Card::DefunctRank) { Card.new(114, 2) }
|
23
|
+
end
|
24
|
+
|
25
|
+
test 'A card accepts only valid suits' do
|
26
|
+
@suits.size.times { |i| assert Card.new(13, i+1) }
|
27
|
+
assert_raises(Card::DefunctSuit) { Card.new(6, 0) }
|
28
|
+
assert_raises(Card::DefunctSuit) { Card.new(11, 5) }
|
29
|
+
assert_raises(Card::DefunctSuit) { Card.new(10, -3) }
|
30
|
+
assert_raises(Card::DefunctSuit) { Card.new(8, 144) }
|
31
|
+
end
|
32
|
+
|
33
|
+
test 'A card has rank' do
|
34
|
+
assert_respond_to @card, :rank
|
35
|
+
end
|
36
|
+
|
37
|
+
test 'A card rank can be represented as integer' do
|
38
|
+
assert_equal 4, Card.new(4, 2).rank.to_i
|
39
|
+
assert_equal 1, Card.new(1, 2).rank.to_i
|
40
|
+
assert_equal 13, Card.new(13, 2).rank.to_i
|
41
|
+
end
|
42
|
+
|
43
|
+
test 'A card rank can be represented as string' do
|
44
|
+
assert_equal "King", Card.new(13, 3).rank.to_s
|
45
|
+
assert_equal "Ace", Card.new(1, 4).rank.to_s
|
46
|
+
assert_equal "Five", Card.new(5, 2).rank.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
test 'A card has suit' do
|
50
|
+
assert_respond_to @card, :suit
|
51
|
+
end
|
52
|
+
|
53
|
+
test 'A card suit can be represented as integer' do
|
54
|
+
assert_equal 1, Card.new(4, 1).suit.to_i
|
55
|
+
assert_equal 4, Card.new(1, 4).suit.to_i
|
56
|
+
assert_equal 3, Card.new(13, 3).suit.to_i
|
57
|
+
end
|
58
|
+
|
59
|
+
test 'A card suit can be represented as string' do
|
60
|
+
assert_equal "Spades", Card.new(13, 3).suit.to_s
|
61
|
+
assert_equal "Clubs", Card.new(1, 4).suit.to_s
|
62
|
+
assert_equal "Diamonds", Card.new(5, 2).suit.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
test 'A card can be of the red suit' do
|
66
|
+
assert Card.new(5, 1).suit.red?
|
67
|
+
assert Card.new(12, 2).suit.red?
|
68
|
+
refute Card.new(12, 3).suit.red?
|
69
|
+
refute Card.new(1, 4).suit.red?
|
70
|
+
end
|
71
|
+
|
72
|
+
test 'A card can be of the black suit' do
|
73
|
+
assert Card.new(2, 3).suit.black?
|
74
|
+
assert Card.new(2, 4).suit.black?
|
75
|
+
refute Card.new(10, 2).suit.black?
|
76
|
+
refute Card.new(5, 1).suit.black?
|
77
|
+
end
|
78
|
+
|
79
|
+
test 'A card can be readable by human' do
|
80
|
+
assert_equal "King of Spades", @card.to_s
|
81
|
+
assert_equal "Ace of Hearts", Card.new(1, 1).to_s
|
82
|
+
assert_equal "Six of Diamonds", Card.new(6, 2).to_s
|
83
|
+
end
|
84
|
+
|
85
|
+
test 'A card has sprite' do
|
86
|
+
assert_respond_to @card, :sprite
|
87
|
+
end
|
88
|
+
|
89
|
+
test "Card's sprite sheet has size" do
|
90
|
+
assert_respond_to @card.sprite, :sheet_size
|
91
|
+
end
|
92
|
+
|
93
|
+
test "Card's sprite sheet has position" do
|
94
|
+
assert_respond_to @card.sprite, :sheet_pos
|
95
|
+
end
|
96
|
+
|
97
|
+
test 'A card can turn its face upwards' do
|
98
|
+
assert @card.face_up
|
99
|
+
assert_equal [13, 3], @card.face_up
|
100
|
+
end
|
101
|
+
|
102
|
+
test 'A card can be checked, if its face looks upwards' do
|
103
|
+
assert @card.face_up?
|
104
|
+
refute @card.face_down?
|
105
|
+
end
|
106
|
+
|
107
|
+
test 'A card can turn its face downwards' do
|
108
|
+
assert @card.face_down
|
109
|
+
assert_equal [0, 0], @card.face_down
|
110
|
+
end
|
111
|
+
|
112
|
+
test 'A card can be checked, if its face looks downwards' do
|
113
|
+
assert @card.face_down
|
114
|
+
@card.sprite.sheet_pos = [0, 0]
|
115
|
+
assert @card.face_down?
|
116
|
+
refute @card.face_up?
|
117
|
+
end
|
118
|
+
|
119
|
+
test 'A card can be flipped' do
|
120
|
+
assert @card.face_up?
|
121
|
+
refute @card.face_down?
|
122
|
+
|
123
|
+
@card.flip!
|
124
|
+
assert @card.face_down?
|
125
|
+
refute @card.face_up?
|
126
|
+
|
127
|
+
@card.flip!
|
128
|
+
assert @card.face_up?
|
129
|
+
refute @card.face_down?
|
130
|
+
end
|
131
|
+
|
132
|
+
test 'A card can be checked for overlapping another card' do
|
133
|
+
another_card = Card.new(10, 1)
|
134
|
+
another_card.pos = Ray::Vector2[20, 20]
|
135
|
+
assert @card.overlaps?(another_card)
|
136
|
+
assert another_card.overlaps?(@card)
|
137
|
+
|
138
|
+
another_card.pos = Ray::Vector2[200, 200]
|
139
|
+
refute @card.overlaps?(another_card)
|
140
|
+
refute another_card.overlaps?(@card)
|
141
|
+
|
142
|
+
equal_card = Card.new(10, 1)
|
143
|
+
equal_card.pos = Ray::Vector2[200, 200]
|
144
|
+
assert_equal another_card.pos, equal_card.pos
|
145
|
+
refute another_card.overlaps?(equal_card)
|
146
|
+
refute equal_card.overlaps?(another_card)
|
147
|
+
end
|
148
|
+
|
149
|
+
test 'Cards can be checked for equality on the basis of ranks and suits' do
|
150
|
+
same_card = Card.new(13, 3)
|
151
|
+
only_same_rank = Card.new(13, 1)
|
152
|
+
only_same_suit = Card.new(1, 3)
|
153
|
+
not_same_at_all = Card.new(5, 4)
|
154
|
+
|
155
|
+
assert @card.eql?(same_card)
|
156
|
+
assert same_card.eql?(@card)
|
157
|
+
refute @card.eql?(only_same_rank)
|
158
|
+
refute @card.eql?(only_same_suit)
|
159
|
+
refute only_same_suit.eql?(@card)
|
160
|
+
refute @card.eql?(not_same_at_all)
|
161
|
+
refute not_same_at_all.eql?(@card)
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
module Patience
|
4
|
+
class TestCursor < TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@cursor = Cursor.new
|
8
|
+
@card = Card.new(1, 3)
|
9
|
+
@areas = { :area => Area.new }
|
10
|
+
@areas[:area].piles.first << @card
|
11
|
+
|
12
|
+
offset = Ray::Vector2[20, 20]
|
13
|
+
mouse_pos = Ray::Vector2.new
|
14
|
+
|
15
|
+
@cursor.mouse_pos = mouse_pos
|
16
|
+
@cursor.click = EventHandler::Click.new(mouse_pos, @areas)
|
17
|
+
@cursor.drag = EventHandler::Drag.new(@cursor)
|
18
|
+
@cursor.drop = EventHandler::Drop.new(@cursor, @areas)
|
19
|
+
end
|
20
|
+
|
21
|
+
test 'A cursor can drop objects' do
|
22
|
+
assert @cursor.click
|
23
|
+
assert @cursor.drag
|
24
|
+
|
25
|
+
@cursor.drop!
|
26
|
+
|
27
|
+
refute @cursor.click
|
28
|
+
refute @cursor.drag
|
29
|
+
end
|
30
|
+
|
31
|
+
test 'A cursor can check, whether it clicked something' do
|
32
|
+
assert @cursor.clicked_something?
|
33
|
+
|
34
|
+
@cursor.drop!
|
35
|
+
|
36
|
+
refute @cursor.clicked_something?
|
37
|
+
end
|
38
|
+
|
39
|
+
test 'A cursor can check, whether it still hovers the clicked object' do
|
40
|
+
assert @cursor.still_on_something?
|
41
|
+
|
42
|
+
@areas[:area].piles.first << @card
|
43
|
+
@cursor.click = EventHandler::Click.new(@cursor.mouse_pos, @areas)
|
44
|
+
assert @cursor.still_on_something?
|
45
|
+
|
46
|
+
@cursor.mouse_pos = Ray::Vector2[1000, 1000]
|
47
|
+
refute @cursor.still_on_something?
|
48
|
+
|
49
|
+
@cursor.card.sprite.pos = @cursor.mouse_pos
|
50
|
+
assert @cursor.still_on_something?
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
test 'A cursor can check, if the object is movable' do
|
55
|
+
assert @cursor.movable?
|
56
|
+
@cursor.card.face_down
|
57
|
+
refute @cursor.movable?
|
58
|
+
|
59
|
+
@cursor.drop!
|
60
|
+
|
61
|
+
refute @cursor.movable?
|
62
|
+
end
|
63
|
+
|
64
|
+
test 'A cursor can check whether it is carrying a card' do
|
65
|
+
assert @cursor.carrying_card?
|
66
|
+
|
67
|
+
@cursor.drop!
|
68
|
+
|
69
|
+
refute @cursor.carrying_card?
|
70
|
+
|
71
|
+
cursor = Cursor.new
|
72
|
+
cursor.click = EventHandler::Click.new(Ray::Vector2[800, 800], @areas)
|
73
|
+
refute cursor.carrying_card?
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
module Patience
|
4
|
+
class TestDeck < TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@deck = Deck.new
|
8
|
+
@cards = @deck.cards.map(&:to_s)
|
9
|
+
@ranks = %w[Two Three Four Five Six Seven Eight Nine Ten]
|
10
|
+
@suits = %w[Hearts Diamonds Spades Clubs]
|
11
|
+
end
|
12
|
+
|
13
|
+
def assert_deck_includes_all_suits_of(rank)
|
14
|
+
rank = @ranks[rank-2] unless rank.instance_of? String
|
15
|
+
@suits.each { |suit| assert_includes @cards, "#{rank} of #{suit}" }
|
16
|
+
end
|
17
|
+
|
18
|
+
test 'Initial size of a deck should be equal to 52' do
|
19
|
+
assert_equal 52, @deck.size
|
20
|
+
end
|
21
|
+
|
22
|
+
(2..10).each do |n|
|
23
|
+
define_method "test_initial_deck_has_#{n}_of_each_suit" do
|
24
|
+
assert_deck_includes_all_suits_of n
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
test 'Initial deck has jacks of each suit' do
|
29
|
+
assert_deck_includes_all_suits_of 'Jack'
|
30
|
+
end
|
31
|
+
|
32
|
+
test 'Initial deck has queens of each suit' do
|
33
|
+
assert_deck_includes_all_suits_of 'Queen'
|
34
|
+
end
|
35
|
+
|
36
|
+
test 'Initial deck has kings of each suit' do
|
37
|
+
assert_deck_includes_all_suits_of 'King'
|
38
|
+
end
|
39
|
+
|
40
|
+
test 'Initial deck has aces of each suit' do
|
41
|
+
assert_deck_includes_all_suits_of 'Ace'
|
42
|
+
end
|
43
|
+
|
44
|
+
test 'Cards of a deck can be accessed via their positon in the deck' do
|
45
|
+
assert_equal 'King of Spades', @cards[50].to_s
|
46
|
+
assert_equal 'Ace of Clubs', @cards[3].to_s
|
47
|
+
assert_equal 'Nine of Diamonds', @cards[33].to_s
|
48
|
+
assert_equal 'Ten of Hearts', @cards[36].to_s
|
49
|
+
assert_equal 'Ace of Hearts', @cards[0].to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
module Patience
|
4
|
+
class TestFoundationArea < TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@foundation = Foundation.new
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'Foundation is a child of Area' do
|
11
|
+
assert_kind_of Area, @foundation
|
12
|
+
end
|
13
|
+
|
14
|
+
test 'Initial foundation has no cards' do
|
15
|
+
@foundation.piles.each { |pile| assert_equal 0, pile.cards.size }
|
16
|
+
end
|
17
|
+
|
18
|
+
test 'Overall position of foundation can be gotten' do
|
19
|
+
assert_equal Ray::Vector2[361, 23], @foundation.pos
|
20
|
+
assert_equal Ray::Vector2[361, 23], @foundation.piles.first.pos
|
21
|
+
end
|
22
|
+
|
23
|
+
test 'Particular position of a pile in foundation can be gotten' do
|
24
|
+
assert_equal Ray::Vector2[471, 23], @foundation.piles[1].pos
|
25
|
+
assert_equal Ray::Vector2[581, 23], @foundation.piles[2].pos
|
26
|
+
end
|
27
|
+
|
28
|
+
test 'Foundation can be disposed in the window' do
|
29
|
+
@foundation.send(:pos=, [0, 0])
|
30
|
+
assert_equal Ray::Vector2[0, 0], @foundation.pos
|
31
|
+
assert_equal Ray::Vector2[330, 0], @foundation.piles.last.pos
|
32
|
+
@foundation.send(:pos=, [200, 300])
|
33
|
+
assert_equal Ray::Vector2[200, 300], @foundation.pos
|
34
|
+
assert_equal Ray::Vector2[530, 300], @foundation.piles.last.pos
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
module Patience
|
4
|
+
class TestGame < TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@game = Patience::Game.new
|
8
|
+
@scene = @game.registered_scene(:game_scene)
|
9
|
+
@scene.register
|
10
|
+
@scene.setup
|
11
|
+
end
|
12
|
+
|
13
|
+
test 'Window size of the game is eight hundred by six hundred pixels' do
|
14
|
+
assert_equal Ray::Vector2[800, 600], @scene.window.size
|
15
|
+
end
|
16
|
+
|
17
|
+
test 'Test the game has GameScene' do
|
18
|
+
assert_instance_of GameScene,
|
19
|
+
@game.scenes.to_a.find { |scene|
|
20
|
+
scene.instance_of? GameScene
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
test 'Main scene is GameScene' do
|
25
|
+
assert_instance_of GameScene, @game.scenes.current
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
module Patience
|
4
|
+
class TestPile < TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@cards = Array.new(10) { Card.new(12, 3) }
|
8
|
+
@pile = Pile.new(@cards)
|
9
|
+
end
|
10
|
+
|
11
|
+
test 'A pile has cards' do
|
12
|
+
assert @pile.cards
|
13
|
+
end
|
14
|
+
|
15
|
+
test 'A card can be appended to the pile' do
|
16
|
+
@pile << Card.new(13, 3)
|
17
|
+
assert_equal "King of Spades", @pile.cards.last.to_s
|
18
|
+
@pile << Card.new(1, 4)
|
19
|
+
assert_equal "Ace of Clubs", @pile.cards.last.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
test 'A pile has background' do
|
23
|
+
assert @pile.background
|
24
|
+
assert_instance_of Ray::Sprite, @pile.background
|
25
|
+
end
|
26
|
+
|
27
|
+
test 'The background of a pile can be changed' do
|
28
|
+
assert_equal Ray::Vector2[0, 0], @pile.background.pos
|
29
|
+
@pile.background.pos = [200, 200]
|
30
|
+
path = '../lib/patience/sprites/empty_stock.png'
|
31
|
+
assert @pile.background = Ray::Sprite.new(path_of(path))
|
32
|
+
assert_equal Ray::Vector2[200, 200], @pile.background.pos
|
33
|
+
end
|
34
|
+
|
35
|
+
test 'A pile has position' do
|
36
|
+
assert_equal [0, 0], @pile.pos.to_a
|
37
|
+
end
|
38
|
+
|
39
|
+
test 'The position of a pile can be set' do
|
40
|
+
@pile.pos = [105, 20]
|
41
|
+
assert_equal [105, 20], @pile.pos.to_a
|
42
|
+
end
|
43
|
+
|
44
|
+
test 'Cards can be counted in a pile' do
|
45
|
+
assert_equal 10, @pile.size
|
46
|
+
end
|
47
|
+
|
48
|
+
test 'Cards can be shuffled off from a pile' do
|
49
|
+
assert_equal 6, @pile.shuffle_off!(6).size
|
50
|
+
assert_equal 4, @pile.size
|
51
|
+
end
|
52
|
+
|
53
|
+
test "A pile's last card detects correctly" do
|
54
|
+
assert @pile.last_card?(@cards.last)
|
55
|
+
end
|
56
|
+
|
57
|
+
test 'A pile can tell, if its card has been clicked' do
|
58
|
+
# Pile with cards.
|
59
|
+
assert @pile.hit?(Ray::Vector2[20, 20])
|
60
|
+
refute @pile.hit?(Ray::Vector2[1000, 0])
|
61
|
+
|
62
|
+
# Empty pile.
|
63
|
+
pile = Pile.new
|
64
|
+
assert pile.hit?(Ray::Vector2[20, 20])
|
65
|
+
refute pile.hit?(Ray::Vector2[1000, 0])
|
66
|
+
end
|
67
|
+
|
68
|
+
test 'A pile can tell, if it overlaps with a card' do
|
69
|
+
empty_pile = Pile.new
|
70
|
+
assert empty_pile.overlaps?(@cards[0])
|
71
|
+
|
72
|
+
@cards[0].pos = Ray::Vector2[200, 200]
|
73
|
+
refute empty_pile.overlaps?(@cards[0])
|
74
|
+
|
75
|
+
non_empty_pile = Pile.new([Card.new(13, 3)])
|
76
|
+
assert non_empty_pile.overlaps?(@cards[1])
|
77
|
+
|
78
|
+
@cards[1].pos = Ray::Vector2[200, 200]
|
79
|
+
refute non_empty_pile.overlaps?(@cards[1])
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|