patience 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,142 @@
1
+ require_relative '../helper'
2
+
3
+ module Patience
4
+ class TestClick < TestCase
5
+
6
+ class Dummy < EventHandler::Click
7
+ attr_accessor :area, :pile, :card, :cards, :scenario
8
+
9
+ def initialize(mouse_pos, areas)
10
+ @mouse_pos = mouse_pos
11
+ @areas = areas
12
+ end
13
+ end
14
+
15
+ def setup
16
+ @mouse_pos_missclick = Ray::Vector2[0, 0]
17
+ @mouse_pos_hit = Ray::Vector2[32, 166]
18
+ @deck = Deck.new
19
+ @areas = { :tableau => Tableau.new(@deck.shuffle_off! 28),
20
+ :waste => Waste.new,
21
+ :stock => Stock.new(@deck.shuffle_off! 10) }
22
+ @dummy_click_miss = Dummy.new(@mouse_pos_missclick, @areas)
23
+ @dummy_click_hit = Dummy.new(@mouse_pos_hit, @areas)
24
+ @stock_hit = Dummy.new(Ray::Vector2[32, 24], @areas)
25
+ end
26
+
27
+ def fill_attributes_up(click)
28
+ click.area = click.send(:detect_area)
29
+ click.pile = click.send(:detect_pile)
30
+ cards = click.send(:collect_cards)
31
+ click.cards = cards.map(&:first) if cards
32
+ click.card = click.cards.first
33
+ end
34
+
35
+ test 'An area can be selected by click' do
36
+ assert_nil @dummy_click_hit.area
37
+ @dummy_click_hit.area = @dummy_click_hit.send(:detect_area)
38
+ assert_instance_of Tableau, @dummy_click_hit.area
39
+ assert_kind_of Area, @dummy_click_hit.area
40
+
41
+ assert_nil @dummy_click_miss.area
42
+ @dummy_click_miss.area = @dummy_click_miss.send(:detect_area)
43
+ assert_nil @dummy_click_miss.area
44
+ end
45
+
46
+ test 'A pile can be selected by click' do
47
+ assert_nil @dummy_click_hit.pile
48
+ @dummy_click_hit.pile = @dummy_click_hit.send(:detect_pile)
49
+ assert_instance_of Pile, @dummy_click_hit.pile
50
+
51
+ assert_nil @dummy_click_miss.pile
52
+ @dummy_click_miss.pile = @dummy_click_miss.send(:detect_pile)
53
+ assert_nil @dummy_click_miss.pile
54
+ end
55
+
56
+ test 'A card can be selected by click' do
57
+ # Hit
58
+ tableau_click = Dummy.new(Ray::Vector2[472, 270], @areas)
59
+ assert_nil tableau_click.card
60
+ assert_nil tableau_click.cards
61
+ tableau_click.pile = @areas[:tableau].piles[4]
62
+
63
+ [Card.new(3, 1), Card.new(2, 4)].each do |card|
64
+ @areas[:tableau].piles[4] << card
65
+ card.pos = @areas[:tableau].piles[4].cards[-2].pos + [0, 20]
66
+ end
67
+
68
+ tableau_click.cards = tableau_click.send(:collect_cards).map(&:first)
69
+ assert tableau_click.cards
70
+ assert_instance_of Card::Rank::Four, tableau_click.cards[0].rank
71
+ assert_instance_of Card::Rank::Three, tableau_click.cards[1].rank
72
+ assert_instance_of Card::Rank::Two, tableau_click.cards[2].rank
73
+
74
+ # Miss
75
+ assert_nil @dummy_click_miss.card
76
+ assert_nil @dummy_click_miss.cards
77
+ @dummy_click_miss.cards = @dummy_click_miss.send(:collect_cards)
78
+ assert_nil @dummy_click_miss.card
79
+ assert_nil @dummy_click_miss.cards
80
+ end
81
+
82
+ test 'Stock can be refilled by a click' do
83
+ assert_equal 10, @areas[:stock].cards.size
84
+ assert_equal 0, @areas[:waste].cards.size
85
+
86
+ @areas[:stock].cards.each do |card|
87
+ @areas[:waste].piles[0] << card
88
+ end
89
+ @areas[:stock].piles[0].cards.clear
90
+
91
+ assert_equal 0, @areas[:stock].cards.size
92
+ assert_equal 10, @areas[:waste].cards.size
93
+
94
+ @dummy_click_hit.send(:refill_stock)
95
+ assert_equal 10, @areas[:stock].cards.size
96
+ assert_equal 0, @areas[:waste].cards.size
97
+ end
98
+
99
+ test 'A card can be displaced from Stock to Waste by a click' do
100
+ assert_equal 10, @areas[:stock].cards.size
101
+ assert_equal 0, @areas[:waste].cards.size
102
+
103
+ fill_attributes_up(@stock_hit)
104
+ @stock_hit.send(:displace_to_waste)
105
+ assert_equal 9, @areas[:stock].cards.size
106
+ assert_equal 1, @areas[:waste].cards.size
107
+
108
+ fill_attributes_up(@stock_hit)
109
+ @stock_hit.send(:displace_to_waste)
110
+ assert_equal 8, @areas[:stock].cards.size
111
+ assert_equal 2, @areas[:waste].cards.size
112
+ end
113
+
114
+ test 'Stock can change its background as a function of conditions' do
115
+ stock = @areas[:stock].piles[0]
116
+ @stock_hit.scenario = -> { @stock_hit.send(:stock) }
117
+ normal_background = @areas[:stock].piles[0].background.object_id
118
+ assert normal_background, stock.background.object_id
119
+ assert_equal 10, stock.size
120
+
121
+ fill_attributes_up(@stock_hit)
122
+ @stock_hit.scenario.call
123
+ assert normal_background, stock.background.object_id
124
+ assert_equal 9, stock.size
125
+
126
+ stock.size.times do
127
+ fill_attributes_up(@stock_hit)
128
+ @stock_hit.scenario.call
129
+ end
130
+
131
+ empty_background = stock.background.object_id
132
+ refute_equal normal_background, empty_background
133
+ assert_equal 0, stock.size
134
+
135
+ fill_attributes_up(@stock_hit)
136
+ @stock_hit.scenario.call
137
+ refute_equal empty_background, stock.background.object_id
138
+ refute_equal empty_background, normal_background
139
+ end
140
+
141
+ end
142
+ end
@@ -0,0 +1,45 @@
1
+ require_relative '../helper'
2
+
3
+ module Patience
4
+ class TestDrag < TestCase
5
+
6
+ class Dummy < EventHandler::Drag
7
+ def initialize
8
+ @card = Card.new(1, 1)
9
+ @tail_cards = {@card => 0, Card.new(2, 2) => 0, Card.new(3, 3) => 0}
10
+ @offset = Ray::Vector2[20, 20]
11
+ end
12
+ end
13
+
14
+ def setup
15
+ @mouse_pos = Ray::Vector2[0, 0]
16
+ @dummy = Dummy.new
17
+ @areas = { :tableau => Tableau.new([Card.new(1, 1)]) }
18
+ @cursor = Cursor.new
19
+ @cursor.mouse_pos = @mouse_pos
20
+ @cursor.click = EventHandler::Click.new(@cursor.mouse_pos, @areas)
21
+ end
22
+
23
+ test 'A drag can move cards' do
24
+ assert_equal Ray::Vector2[0, 0], @dummy.card.sprite.pos
25
+
26
+ @mouse_pos += [200, 200]
27
+ @dummy.move(@mouse_pos)
28
+ assert_equal Ray::Vector2[220, 220], @dummy.card.sprite.pos
29
+
30
+ @mouse_pos += [-231, -365]
31
+ @dummy.move(@mouse_pos)
32
+ assert_equal Ray::Vector2[-11, -145], @dummy.card.sprite.pos
33
+ end
34
+
35
+ test 'A drag can check, whether a card is draggable' do
36
+ assert @dummy.draggable?
37
+
38
+ @cursor.mouse_pos = Ray::Vector2[800, 500]
39
+ @cursor.click = EventHandler::Click.new(@cursor.mouse_pos, @areas)
40
+ drag = EventHandler::Drag.new(@cursor)
41
+ refute drag.draggable?
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,175 @@
1
+ require_relative '../helper'
2
+
3
+ module Patience
4
+ class TestDrop < TestCase
5
+
6
+ class EventHandler::Click
7
+ attr_accessor :mouse_pos
8
+ end
9
+
10
+ class Dummy < EventHandler::Drop
11
+ attr_accessor :card_to_drop, :pile_beneath, :card_beneath, :area, :pile
12
+ end
13
+
14
+ def setup
15
+ @mouse_pos = Ray::Vector2[361, 243]
16
+ @deck = Deck.new
17
+ @areas = { :tableau => Tableau.new(@deck.shuffle_off! 28),
18
+ :waste => Waste.new,
19
+ :foundation => Foundation.new }
20
+ @click = EventHandler::Click.new(@mouse_pos, @areas)
21
+ @drop = Dummy.new(@click, @areas)
22
+ end
23
+
24
+ def fill_attributes_up(drop)
25
+ @drop.card_beneath = @drop.send(:find_card_beneath)
26
+ @drop.pile_beneath = @drop.send(:find_pile_beneath)
27
+ end
28
+
29
+ test 'An area can be found by drop' do
30
+ @drop.card_to_drop.pos = Ray::Vector2[0, 0]
31
+ fill_attributes_up(@drop)
32
+
33
+ assert_nil @drop.send(:find_area_beneath)
34
+
35
+ @drop.card_to_drop.pos = Ray::Vector2[252, 218]
36
+ fill_attributes_up(@drop)
37
+ assert_nil @drop.send(:find_area_beneath)
38
+
39
+ @drop.card_to_drop.pos = Ray::Vector2[472, 270]
40
+ fill_attributes_up(@drop)
41
+ assert_equal Tableau, @drop.send(:find_area_beneath).class
42
+
43
+ assert_kind_of Area, @drop.send(:find_area_beneath)
44
+ end
45
+
46
+ test 'A pile can be found by drop' do
47
+ @drop.card_to_drop.pos = Ray::Vector2[0, 0]
48
+ assert_nil @drop.send(:find_pile_beneath)
49
+
50
+ @drop.card_to_drop.pos = Ray::Vector2[252, 218]
51
+ assert_nil @drop.send(:find_pile_beneath)
52
+
53
+ @drop.card_to_drop.pos = Ray::Vector2[472, 270]
54
+ @drop.card_beneath = @drop.send(:find_card_beneath)
55
+
56
+ assert_equal Pile, @drop.send(:find_pile_beneath).class
57
+ end
58
+
59
+ test 'A card can be found by drop' do
60
+ @drop.card_to_drop.pos = Ray::Vector2[0, 0]
61
+ assert_nil @drop.send(:find_card_beneath)
62
+
63
+ @drop.card_to_drop.pos = Ray::Vector2[252, 218]
64
+ assert_nil @drop.send(:find_card_beneath)
65
+
66
+ @drop.card_to_drop.pos = Ray::Vector2[472, 270]
67
+ assert_equal Card, @drop.send(:find_card_beneath).class
68
+ end
69
+
70
+ test 'A drop can decide whether a card meets conditions of Tableau' do
71
+ @drop.card_to_drop = Card.new(8, 1)
72
+ nine_of_clubs = Card.new(9, 4)
73
+ king_of_diamonds = Card.new(13, 2)
74
+ nine_of_hearts = Card.new(9, 1)
75
+
76
+ assert @drop.send(:tableau_conditions?, nine_of_clubs)
77
+ refute @drop.send(:tableau_conditions?, king_of_diamonds)
78
+ refute @drop.send(:tableau_conditions?, nine_of_hearts)
79
+ end
80
+
81
+ test 'A drop can decide whether a card meets conditions of Foundation' do
82
+ @drop.card_to_drop = Card.new(10, 1)
83
+ nine_of_clubs = Card.new(9, 4)
84
+ king_of_diamonds = Card.new(13, 2)
85
+ nine_of_hearts = Card.new(9, 1)
86
+
87
+ refute @drop.send(:foundation_conditions?, nine_of_clubs)
88
+ refute @drop.send(:foundation_conditions?, king_of_diamonds)
89
+ assert @drop.send(:foundation_conditions?, nine_of_hearts)
90
+ end
91
+
92
+ test 'A dropped card can be called off' do
93
+ assert_equal Ray::Vector2[361, 243], @drop.card_to_drop.pos
94
+
95
+ @drop.card_to_drop.pos = Ray::Vector2[0, 0]
96
+ assert_equal Ray::Vector2[0, 0], @drop.card_to_drop.pos
97
+
98
+ @drop.send(:call_off)
99
+ assert_equal Ray::Vector2[361, 243], @drop.card_to_drop.pos
100
+ end
101
+
102
+ test 'A dropped card can be added to the pile beneath' do
103
+ @drop.pile_beneath = Pile.new
104
+ @drop.pile = Pile.new([Card.new(1, 1)])
105
+
106
+ assert_equal 0, @drop.pile_beneath.size
107
+ assert_equal 1, @drop.pile.size
108
+
109
+ @drop.send(:add_to_pile_beneath, @drop.pile.cards[0])
110
+ assert_equal 1, @drop.pile_beneath.size
111
+ assert_instance_of Card, @drop.pile_beneath.cards[0]
112
+ assert_equal Card::Rank::Ace, @drop.pile_beneath.cards[0].rank.class
113
+ assert_equal 0, @drop.pile.size
114
+ end
115
+
116
+ # Not complete.
117
+ test "A dropped card can be checked, if it's allowed to be put in Tableau" do
118
+ @drop.card_to_drop.pos = Ray::Vector2[472, 270]
119
+ fill_attributes_up(@drop)
120
+ assert @drop.send(:can_put_in_tableau?)
121
+
122
+ @drop.card_to_drop = Card.new(1, 1)
123
+ @drop.card_to_drop.pos = Ray::Vector2[472, 270]
124
+ refute @drop.send(:can_put_in_tableau?)
125
+ end
126
+
127
+ # Not complete.
128
+ test "A dropped card can be checked, if it's allowed to be put in Foundation" do
129
+ @drop.card_to_drop = Card.new(1, 1)
130
+ @drop.card_to_drop.pos = Ray::Vector2[362, 23]
131
+ fill_attributes_up(@drop)
132
+ assert @drop.send(:can_put_in_foundation?)
133
+
134
+ @drop.card_to_drop = Card.new(10, 1)
135
+ refute @drop.send(:can_put_in_foundation?)
136
+ end
137
+
138
+ test 'A dropped card can be put in Tableau' do
139
+ @drop.card_to_drop.pos = Ray::Vector2[472, 270]
140
+ fill_attributes_up(@drop)
141
+ assert_equal 5, @areas[:tableau].piles[4].size
142
+ @drop.send(:put_in_tableau)
143
+ assert_equal 6, @areas[:tableau].piles[4].size
144
+
145
+ @areas[:tableau].piles[3] << Card.new(2, 3)
146
+ @areas[:tableau].piles[3].cards.last.pos = @mouse_pos
147
+ @click = EventHandler::Click.new(@mouse_pos, @areas)
148
+ @drop = Dummy.new(@click, @areas)
149
+ @drop.card_to_drop.pos = Ray::Vector2[472, 270]
150
+ fill_attributes_up(@drop)
151
+ @drop.send(:put_in_tableau)
152
+ assert_equal 7, @areas[:tableau].piles[4].size
153
+ end
154
+
155
+ test 'A dropped card can be put in Foundation' do
156
+ @click = EventHandler::Click.new(Ray::Vector2[32, 165], @areas)
157
+ @drop = Dummy.new(@click, @areas)
158
+ @drop.card_to_drop.pos = Ray::Vector2[362, 23]
159
+ fill_attributes_up(@drop)
160
+ @drop.send(:put_in_foundation)
161
+ assert_equal 1, @areas[:foundation].piles[0].size
162
+
163
+ last_card = @areas[:tableau].piles[2].cards.last
164
+ @areas[:tableau].piles[2].cards.delete(last_card)
165
+ @areas[:tableau].piles[2].cards.last.flip!
166
+ @click = EventHandler::Click.new(Ray::Vector2[252, 192], @areas)
167
+ @drop = Dummy.new(@click, @areas)
168
+ @drop.card_to_drop.pos = Ray::Vector2[362, 23]
169
+ fill_attributes_up(@drop)
170
+ @drop.send(:put_in_foundation)
171
+ assert_equal 2, @areas[:foundation].piles[0].size
172
+ end
173
+
174
+ end
175
+ end
@@ -0,0 +1,8 @@
1
+ require 'minitest/autorun'
2
+ require_relative '../../lib/patience'
3
+
4
+ class TestCase < MiniTest::Unit::TestCase
5
+ def self.test(name, &blk)
6
+ define_method('test_' + name, &blk) if blk
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+ require_relative '../helper'
2
+
3
+ module Patience
4
+ class TestGameScene < MiniTest::Unit::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
+ end
14
+ end
@@ -0,0 +1,74 @@
1
+ require_relative 'helper'
2
+
3
+ module Patience
4
+ class TestArea < TestCase
5
+
6
+ def setup
7
+ @area = Area.new
8
+ @cards = [Card.new(1, 1)]
9
+ end
10
+
11
+ test 'A new area should contain at least one pile' do
12
+ assert_equal 1, Area.new.piles.size
13
+ end
14
+
15
+ test 'An area can contain several piles' do
16
+ assert_equal 1, Area.new(@cards, 1).piles.size
17
+ assert_equal 10, Area.new(@cards, 10).piles.size
18
+ assert_equal 100, Area.new(@cards, 100).piles.size
19
+ end
20
+
21
+ test 'An area can return array of the piles' do
22
+ assert_instance_of Array, @area.piles
23
+ assert_instance_of Pile, @area.piles.first
24
+ end
25
+
26
+ test 'An area can be disposed' do
27
+ assert_equal Ray::Vector2[0, 0], @area.piles[0].pos
28
+ @area.pos = [20, 20]
29
+ assert_equal Ray::Vector2[20, 20], @area.piles[0].pos
30
+ @area.pos = [-100, 20]
31
+ assert_equal Ray::Vector2[-100, 20], @area.piles[0].pos
32
+
33
+ area = Area.new([], 4)
34
+ assert_equal Ray::Vector2[0, 0], area.piles[0].pos
35
+ assert_equal Ray::Vector2[0, 0], area.piles[3].pos
36
+ area.pos = [20, 20]
37
+ assert_equal Ray::Vector2[20, 20], area.piles[0].pos
38
+ assert_equal Ray::Vector2[20, 20], area.piles[3].pos
39
+ area.pos = [-100, 20]
40
+ assert_equal Ray::Vector2[-100, 20], area.piles[0].pos
41
+ assert_equal Ray::Vector2[-100, 20], area.piles[3].pos
42
+ end
43
+
44
+ test 'An area can tell its position' do
45
+ assert_equal Ray::Vector2[0, 0], @area.pos
46
+ @area.pos = [20, 20]
47
+ assert_equal Ray::Vector2[20, 20], @area.pos
48
+ @area.pos = [-100, 20]
49
+ assert_equal Ray::Vector2[-100, 20], @area.pos
50
+ end
51
+
52
+ test 'An area can show all its cards' do
53
+ assert_equal [], @area.cards
54
+ @area.piles[0].cards << @cards
55
+ assert_equal ["Ace of Hearts"], @area.cards.map(&:to_s)
56
+ end
57
+
58
+ test 'An area can tell, if its card has been clicked' do
59
+ assert @area.hit?(Ray::Vector2[20, 20])
60
+ refute @area.hit?(Ray::Vector2[1000, 0])
61
+ end
62
+
63
+ test 'A card can be added to the first pile of area from the given pile' do
64
+ pile = Pile.new([Card.new(1, 1)])
65
+ assert pile.cards.first.face_up?
66
+ assert_equal 0, @area.cards.size
67
+ @area.add_from(pile, pile.cards.first)
68
+ assert_equal 1, @area.cards.size
69
+ assert @area.cards.first.face_down?
70
+ assert_instance_of Card, @area.cards.first
71
+ end
72
+
73
+ end
74
+ end