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.
Files changed (56) hide show
  1. data/CHANGELOG.md +6 -0
  2. data/Gemfile +5 -0
  3. data/Gemfile.lock +17 -0
  4. data/LICENSE +19 -0
  5. data/README.md +111 -0
  6. data/Rakefile +11 -0
  7. data/bin/patience +5 -0
  8. data/lib/patience.rb +13 -0
  9. data/lib/patience/area.rb +62 -0
  10. data/lib/patience/card.rb +107 -0
  11. data/lib/patience/core_ext/class.rb +17 -0
  12. data/lib/patience/core_ext/core_ext.rb +1 -0
  13. data/lib/patience/core_ext/object.rb +37 -0
  14. data/lib/patience/core_ext/string.rb +33 -0
  15. data/lib/patience/cursor.rb +66 -0
  16. data/lib/patience/deck.rb +21 -0
  17. data/lib/patience/event_handlers/click.rb +99 -0
  18. data/lib/patience/event_handlers/drag.rb +36 -0
  19. data/lib/patience/event_handlers/drop.rb +147 -0
  20. data/lib/patience/foundation.rb +30 -0
  21. data/lib/patience/game.rb +10 -0
  22. data/lib/patience/pile.rb +78 -0
  23. data/lib/patience/processable.rb +87 -0
  24. data/lib/patience/rank.rb +56 -0
  25. data/lib/patience/scenes/game_scene.rb +66 -0
  26. data/lib/patience/sprites/card_deck.png +0 -0
  27. data/lib/patience/sprites/empty_stock.png +0 -0
  28. data/lib/patience/sprites/pile_background.png +0 -0
  29. data/lib/patience/stock.rb +20 -0
  30. data/lib/patience/suit.rb +73 -0
  31. data/lib/patience/tableau.rb +42 -0
  32. data/lib/patience/version.rb +3 -0
  33. data/lib/patience/waste.rb +18 -0
  34. data/test/patience/core_ext/test_class.rb +28 -0
  35. data/test/patience/core_ext/test_object.rb +15 -0
  36. data/test/patience/core_ext/test_string.rb +35 -0
  37. data/test/patience/event_handlers/test_click.rb +142 -0
  38. data/test/patience/event_handlers/test_drag.rb +45 -0
  39. data/test/patience/event_handlers/test_drop.rb +175 -0
  40. data/test/patience/helper.rb +8 -0
  41. data/test/patience/scenes/test_game_scene.rb +14 -0
  42. data/test/patience/test_area.rb +74 -0
  43. data/test/patience/test_card.rb +165 -0
  44. data/test/patience/test_cursor.rb +77 -0
  45. data/test/patience/test_deck.rb +53 -0
  46. data/test/patience/test_foundation.rb +38 -0
  47. data/test/patience/test_game.rb +29 -0
  48. data/test/patience/test_pile.rb +83 -0
  49. data/test/patience/test_processable.rb +159 -0
  50. data/test/patience/test_rank.rb +88 -0
  51. data/test/patience/test_stock.rb +43 -0
  52. data/test/patience/test_suit.rb +87 -0
  53. data/test/patience/test_tableau.rb +57 -0
  54. data/test/patience/test_version.rb +11 -0
  55. data/test/patience/test_waste.rb +35 -0
  56. 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