pentix 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,377 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Glass do
4
+
5
+ before do
6
+ @window = DummyWindow.new
7
+ @window.glass = @glass = Glass.new(@window, 1, 2)
8
+ @window.status = @status = Status.new(@window, 20, 2)
9
+ end
10
+
11
+ describe "initialization" do
12
+ it "should use correct blocks color" do
13
+ @glass.instance_variable_get('@block').color.should == Glass::COLOR
14
+ end
15
+
16
+ it "should assign the initial position" do
17
+ @glass.pos_x.should == 1
18
+ @glass.pos_y.should == 2
19
+ end
20
+
21
+ it "should render the glass walls correctly" do
22
+ @glass.should render_blocks(%Q{
23
+ |x. . . . . . . . . . . . .x|
24
+ |x. . . . . . . . . . . . .x|
25
+ |x. . . . . . . . . . . . .x|
26
+ |x. . . . . . . . . . . . .x|
27
+ |x. . . . . . . . . . . . .x|
28
+ |x. . . . . . . . . . . . .x|
29
+ |x. . . . . . . . . . . . .x|
30
+ |x. . . . . . . . . . . . .x|
31
+ |x. . . . . . . . . . . . .x|
32
+ |x. . . . . . . . . . . . .x|
33
+ |x. . . . . . . . . . . . .x|
34
+ |x. . . . . . . . . . . . .x|
35
+ |x. . . . . . . . . . . . .x|
36
+ |x. . . . . . . . . . . . .x|
37
+ |x. . . . . . . . . . . . .x|
38
+ |x. . . . . . . . . . . . .x|
39
+ |x. . . . . . . . . . . . .x|
40
+ |x. . . . . . . . . . . . .x|
41
+ |x. . . . . . . . . . . . .x|
42
+ |x. . . . . . . . . . . . .x|
43
+ |x. . . . . . . . . . . . .x|
44
+ |x. . . . . . . . . . . . .x|
45
+ |x. . . . . . . . . . . . .x|
46
+ |x. . . . . . . . . . . . .x|
47
+ |x.x.x.x.x.x.x.x.x.x.x.x.x.x|
48
+ })
49
+ end
50
+
51
+ it "should have an empty matrix" do
52
+ @glass.should have_matrix(%Q{
53
+ | . . . . . . . . . . . |
54
+ | . . . . . . . . . . . |
55
+ | . . . . . . . . . . . |
56
+ | . . . . . . . . . . . |
57
+ | . . . . . . . . . . . |
58
+ | . . . . . . . . . . . |
59
+ | . . . . . . . . . . . |
60
+ | . . . . . . . . . . . |
61
+ | . . . . . . . . . . . |
62
+ | . . . . . . . . . . . |
63
+ | . . . . . . . . . . . |
64
+ | . . . . . . . . . . . |
65
+ | . . . . . . . . . . . |
66
+ | . . . . . . . . . . . |
67
+ | . . . . . . . . . . . |
68
+ | . . . . . . . . . . . |
69
+ | . . . . . . . . . . . |
70
+ | . . . . . . . . . . . |
71
+ | . . . . . . . . . . . |
72
+ | . . . . . . . . . . . |
73
+ | . . . . . . . . . . . |
74
+ | . . . . . . . . . . . |
75
+ | . . . . . . . . . . . |
76
+ | . . . . . . . . . . . |
77
+ })
78
+ end
79
+ end
80
+
81
+ describe "#spaces_below" do
82
+ before do
83
+ @glass = Glass.new(@window, 1, 2)
84
+ @figure = Figure.new(@window, :l_crutch)
85
+ @figure.pos_x = 8
86
+ @figure.pos_y = 2
87
+ end
88
+
89
+ it "should calculate the distance correctly when the figure is vertical" do
90
+ @figure.rotate_left if @figure.size_x > @figure.size_y
91
+ @glass.spaces_below(@figure).should == Glass::HEIGHT - @figure.size_y
92
+ end
93
+
94
+ it "should calculate the distance correctly when the figure is vertical" do
95
+ @figure.rotate_left if @figure.size_y > @figure.size_y
96
+ @glass.spaces_below(@figure).should == Glass::HEIGHT - @figure.size_y
97
+ end
98
+
99
+ it "should calculate the distance correctly when a figure is hanging in the middle" do
100
+ @offset = Glass::HEIGHT / 2
101
+ @figure.pos_y = @glass.pos_y + @offset
102
+
103
+ @glass.spaces_below(@figure).should == Glass::HEIGHT - @figure.size_y - @offset
104
+ end
105
+
106
+ describe "with some blocks in the glass" do
107
+ before do
108
+ @stack_height = 3
109
+
110
+ @stack_height.times do |y|
111
+ 3.times do |x|
112
+ @glass.matrix[Glass::HEIGHT - 1 - y][x] = Color::WHITE
113
+ end
114
+ end
115
+ end
116
+
117
+ it "should subtract the blocks height when the figure is above them" do
118
+ @figure.pos_x = @glass.pos_x + 1
119
+ @glass.spaces_below(@figure).should == Glass::HEIGHT - @figure.size_y - @stack_height
120
+ end
121
+
122
+ it "should not calculate the blocks height when the figure is not above them" do
123
+ @figure.pos_x = @glass.pos_x + 6
124
+ @glass.spaces_below(@figure).should == Glass::HEIGHT - @figure.size_y
125
+ end
126
+
127
+ it "should calculate the distance correctly when the figure is in the middle" do
128
+ @figure.pos_x = @glass.pos_x + 1
129
+ @figure.pos_y = 10
130
+
131
+ @glass.spaces_below(@figure).should == Glass::HEIGHT -
132
+ @figure.size_y - @stack_height - @figure.pos_y + @glass.pos_y
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "#glue_in" do
138
+ before do
139
+ @figure = Figure.new(@window, :stairs)
140
+ end
141
+
142
+ it "should glue the figure in when it's on top" do
143
+ @figure.move_to(@glass.pos_x + 3, @glass.pos_y)
144
+ @glass.glue_in(@figure)
145
+ @glass.should have_matrix(%Q{
146
+ | . . . . . . . . . . . |
147
+ | . . . . . . . . . . . |
148
+ | . . . . . . . . . . . |
149
+ | . . . . . . . . . . . |
150
+ | . . . . . . . . . . . |
151
+ | . . . . . . . . . . . |
152
+ | . . . . . . . . . . . |
153
+ | . . . . . . . . . . . |
154
+ | . . . . . . . . . . . |
155
+ | . . . . . . . . . . . |
156
+ | . . . . . . . . . . . |
157
+ | . . . . . . . . . . . |
158
+ | . . . . . . . . . . . |
159
+ | . . . . . . . . . . . |
160
+ | . . . . . . . . . . . |
161
+ | . . . . . . . . . . . |
162
+ | . . . . . . . . . . . |
163
+ | . . . . . . . . . . . |
164
+ | . . . . . . . . . . . |
165
+ | . . . . . . . . . . . |
166
+ | . . . . . . . . . . . |
167
+ | . .x. . . . . . . . . |
168
+ | . .x.x. . . . . . . . |
169
+ | . . .x.x. . . . . . . |
170
+ })
171
+ end
172
+
173
+ it "should call the status for scores" do
174
+ @figure.move_to(@glass.pos_x + 3, @glass.pos_y)
175
+
176
+ @status.should_receive(:count_drop).with(@figure)
177
+ @status.should_receive(:count_kill).with([])
178
+
179
+ @glass.glue_in(@figure)
180
+ end
181
+
182
+ describe "with some blocks already in the glass" do
183
+ before do
184
+ figure = Figure.new(@window, :l_crutch)
185
+ figure.move_to(@glass.pos_x + 2, @glass.pos_y)
186
+ @glass.glue_in(figure)
187
+ end
188
+
189
+ it "should glue figures next to each other" do
190
+ @figure.move_to(@glass.pos_x + 7, @glass.pos_y + 6)
191
+ @glass.glue_in(@figure)
192
+
193
+ @glass.should have_matrix(%Q{
194
+ | . . . . . . . . . . . |
195
+ | . . . . . . . . . . . |
196
+ | . . . . . . . . . . . |
197
+ | . . . . . . . . . . . |
198
+ | . . . . . . . . . . . |
199
+ | . . . . . . . . . . . |
200
+ | . . . . . . . . . . . |
201
+ | . . . . . . . . . . . |
202
+ | . . . . . . . . . . . |
203
+ | . . . . . . . . . . . |
204
+ | . . . . . . . . . . . |
205
+ | . . . . . . . . . . . |
206
+ | . . . . . . . . . . . |
207
+ | . . . . . . . . . . . |
208
+ | . . . . . . . . . . . |
209
+ | . . . . . . . . . . . |
210
+ | . . . . . . . . . . . |
211
+ | . . . . . . . . . . . |
212
+ | . . . . . . . . . . . |
213
+ | . . . . . . . . . . . |
214
+ | .x. . . . . . . . . . |
215
+ | .x.x. . . .x. . . . . |
216
+ | .x. . . . .x.x. . . . |
217
+ | .x. . . . . .x.x. . . |
218
+ })
219
+ end
220
+
221
+ it "should glue figures on top of each other" do
222
+ @figure.move_to(@glass.pos_x + 3, @glass.pos_y)
223
+ @glass.glue_in(@figure)
224
+
225
+ @figure.move_to(@glass.pos_x + 2, @glass.pos_y)
226
+ @glass.glue_in(@figure)
227
+
228
+ @glass.should have_matrix(%Q{
229
+ | . . . . . . . . . . . |
230
+ | . . . . . . . . . . . |
231
+ | . . . . . . . . . . . |
232
+ | . . . . . . . . . . . |
233
+ | . . . . . . . . . . . |
234
+ | . . . . . . . . . . . |
235
+ | . . . . . . . . . . . |
236
+ | . . . . . . . . . . . |
237
+ | . . . . . . . . . . . |
238
+ | . . . . . . . . . . . |
239
+ | . . . . . . . . . . . |
240
+ | . . . . . . . . . . . |
241
+ | . . . . . . . . . . . |
242
+ | . . . . . . . . . . . |
243
+ | . . . . . . . . . . . |
244
+ | . . . . . . . . . . . |
245
+ | .x. . . . . . . . . . |
246
+ | .x.x. . . . . . . . . |
247
+ | . .x.x. . . . . . . . |
248
+ | . .x. . . . . . . . . |
249
+ | .x.x.x. . . . . . . . |
250
+ | .x.x.x.x. . . . . . . |
251
+ | .x. . . . . . . . . . |
252
+ | .x. . . . . . . . . . |
253
+ })
254
+ end
255
+ end
256
+ end
257
+
258
+ describe "#has_space_for?" do
259
+ before do
260
+ @figure = Figure.new(@window, :cross)
261
+ end
262
+
263
+ describe "in an empty glass" do
264
+ it "should say 'yes' when the figure is in the middle" do
265
+ @glass.should have_space_for(
266
+ @figure.matrix, @glass.pos_x + 4, @glass.pos_y + 4
267
+ )
268
+ end
269
+
270
+ it "should say 'nope' when the figure is out of the left border" do
271
+ @glass.should_not have_space_for(
272
+ @figure.matrix, @glass.pos_x, @glass.pos_y
273
+ )
274
+ end
275
+
276
+ it "should say 'nope' if a figure is out of the right border" do
277
+ @glass.should_not have_space_for(
278
+ @figure.matrix, @glass.pos_x + Glass::WIDTH + 2 - @figure.size_x, @glass.pos_y
279
+ )
280
+ end
281
+
282
+ it "should say 'nope' if a figure is below the bottom line" do
283
+ @glass.should_not have_space_for(
284
+ @figure.matrix, @glass.pos_x + 4, @glass.pos_y + Glass::HEIGHT - @figure.size_y + 1
285
+ )
286
+ end
287
+
288
+ it "should say 'yup' for a figure next to the left border" do
289
+ @glass.should have_space_for(
290
+ @figure.matrix, @glass.pos_x + 1, @glass.pos_y
291
+ )
292
+ end
293
+
294
+ it "should say 'yup' for a figure next to the right border" do
295
+ @glass.should have_space_for(
296
+ @figure.matrix, @glass.pos_x + Glass::WIDTH + 1 - @figure.size_x, @glass.pos_y
297
+ )
298
+ end
299
+
300
+ it "should say 'yup' for a figure next to the bottom border" do
301
+ @glass.should have_space_for(
302
+ @figure.matrix, @glass.pos_x + 4, @glass.pos_y + Glass::HEIGHT - @figure.size_y
303
+ )
304
+ end
305
+ end
306
+
307
+ describe "with some blocks in the glass" do
308
+ before do
309
+ 10.times do |i|
310
+ @glass.matrix[i][i] = Color::GRAY
311
+ end
312
+ end
313
+
314
+ it "should say 'yup' for figures that are away from the blocks" do
315
+ @glass.should have_space_for(
316
+ @figure.matrix, @glass.pos_x + 8, @glass.pos_y
317
+ )
318
+ end
319
+
320
+ it "should say 'yup' for figures that fit the landscape" do
321
+ @glass.should have_space_for(
322
+ @figure.matrix, @glass.pos_x + 3, @glass.pos_y
323
+ )
324
+ end
325
+
326
+ it "should say 'nope' for figures that intersect with the landscape" do
327
+ @glass.should_not have_space_for(
328
+ @figure.matrix, @glass.pos_x + 1, @glass.pos_y
329
+ )
330
+ end
331
+ end
332
+ end
333
+
334
+ describe "#remove_full_lines" do
335
+
336
+ before do
337
+ 10.times do |y|
338
+ @glass.matrix[y].each_with_index do |cell, x|
339
+ @glass.matrix[Glass::HEIGHT - y - 1][x] =
340
+ y % 2 == 0 || x % 2 == 0 ? 0xFFFFFFFF : nil
341
+ end
342
+ end
343
+
344
+ @glass.remove_full_lines
345
+ end
346
+
347
+ it "should have matrix like that" do
348
+ @glass.should have_matrix(%Q{
349
+ | . . . . . . . . . . . |
350
+ | . . . . . . . . . . . |
351
+ | . . . . . . . . . . . |
352
+ | . . . . . . . . . . . |
353
+ | . . . . . . . . . . . |
354
+ | . . . . . . . . . . . |
355
+ | . . . . . . . . . . . |
356
+ | . . . . . . . . . . . |
357
+ | . . . . . . . . . . . |
358
+ | . . . . . . . . . . . |
359
+ | . . . . . . . . . . . |
360
+ | . . . . . . . . . . . |
361
+ | . . . . . . . . . . . |
362
+ | . . . . . . . . . . . |
363
+ | . . . . . . . . . . . |
364
+ | . . . . . . . . . . . |
365
+ | . . . . . . . . . . . |
366
+ | . . . . . . . . . . . |
367
+ | . . . . . . . . . . . |
368
+ |x. .x. .x. .x. .x. .x. |
369
+ |x. .x. .x. .x. .x. .x. |
370
+ |x. .x. .x. .x. .x. .x. |
371
+ |x. .x. .x. .x. .x. .x. |
372
+ |x. .x. .x. .x. .x. .x. |
373
+ })
374
+ end
375
+ end
376
+
377
+ end
@@ -0,0 +1,194 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Status do
4
+ before :all do
5
+ @window = DummyWindow.new
6
+ @window.glass = Glass.new(@window, 1, 1)
7
+
8
+ @head_font_args = [@window, Status::HEAD_FONT[0], Status::HEAD_FONT[1]]
9
+ @text_font_args = [@window, Status::TEXT_FONT[0], Status::TEXT_FONT[1]]
10
+
11
+ @head_font = Font.new(*@head_font_args)
12
+ @text_font = Font.new(*@text_font_args)
13
+
14
+ @status = Status.new(@window, 10, 20)
15
+ end
16
+
17
+ describe "initialization" do
18
+ it "should instantiate correct fonts" do
19
+ Font.should_receive(:new).with(*@head_font_args).and_return(@head_font)
20
+ Font.should_receive(:new).with(*@text_font_args).and_return(@text_font)
21
+
22
+ @status = Status.new(@window, 10, 20)
23
+ end
24
+
25
+ it "should set correct positions" do
26
+ @status.pos_x.should == 10
27
+ @status.pos_y.should == 20
28
+ end
29
+
30
+ it "should set first level" do
31
+ @status.level.should == 1
32
+ end
33
+
34
+ it "should set zero lines" do
35
+ @status.lines.should == 0
36
+ end
37
+
38
+ it "should set zero figures" do
39
+ @status.figures.should == 0
40
+ end
41
+
42
+ it "should set zero score" do
43
+ @status.score.should == 0
44
+ end
45
+ end
46
+
47
+ describe '#reset!' do
48
+ before :all do
49
+ @status.level = 8
50
+ @status.score = 9999
51
+ @status.lines = 234
52
+ @status.figures = 1234
53
+
54
+ @status.reset!
55
+ end
56
+
57
+ it "should set the first level" do
58
+ @status.level.should == 1
59
+ end
60
+
61
+ it "should set zero lines" do
62
+ @status.lines.should == 0
63
+ end
64
+
65
+ it "should set zero figures" do
66
+ @status.figures.should == 0
67
+ end
68
+
69
+ it "should set zero score" do
70
+ @status.score.should == 0
71
+ end
72
+ end
73
+
74
+ describe "#draw" do
75
+ it "should draw the things" do
76
+ Font.should_receive(:new).with(*@head_font_args).and_return(@head_font)
77
+ Font.should_receive(:new).with(*@text_font_args).and_return(@text_font)
78
+
79
+ @figure = Figure.new(@window)
80
+ @status = Status.new(@window, 10, 20)
81
+ @status.figure = @figure
82
+
83
+ @figure.should_receive(:pos_x=).with(10)
84
+ @figure.should_receive(:pos_y=).with(22)
85
+ @figure.should_receive(:draw)
86
+
87
+ @head_font.should_receive(:draw).with("Next:", 200, 395, 0, 1.0, 1.0, Status::HEAD_FONT[2])
88
+ @head_font.should_receive(:draw).with("Score:", 200, 575, 0, 1.0, 1.0, Status::HEAD_FONT[2])
89
+ @head_font.should_receive(:draw).with("Winnars:", 200, 755, 0, 1.0, 1.0, Status::HEAD_FONT[2])
90
+
91
+ @status.draw
92
+ end
93
+ end
94
+
95
+ describe "scoring" do
96
+ before do
97
+ @figure = Figure.new(@window)
98
+
99
+ @status.score = 0
100
+ @status.level = 1
101
+ @status.lines = 0
102
+ @status.figures = 0
103
+ end
104
+
105
+ it "should calculate correctly a figure drop score" do
106
+ @figure.distance = 8
107
+
108
+ @status.count_drop @figure
109
+
110
+ @status.score.should == 8
111
+ @status.figures.should == 1
112
+ end
113
+
114
+ it "should multiply the drop score by the current level" do
115
+ @figure.distance = 9
116
+ @status.level = 3
117
+
118
+ @status.count_drop @figure
119
+
120
+ @status.score.should == 27
121
+ @status.figures.should == 1
122
+ end
123
+
124
+ it "should score lines kill according to the scoring system" do
125
+ Status::SCORING_SYSTEM.each do |lines_num, score|
126
+ @status.score = 0
127
+ @status.lines = 0
128
+
129
+ @status.count_kill Array.new(lines_num)
130
+
131
+ @status.score.should == score
132
+ @status.lines.should == lines_num
133
+ end
134
+ end
135
+
136
+ it "should multiply the lines kill score by the current level" do
137
+ Status::SCORING_SYSTEM.each do |lines_num, score|
138
+ @status.score = 0
139
+ @status.lines = 0
140
+ @status.level = 4
141
+
142
+ @status.count_kill Array.new(lines_num)
143
+
144
+ @status.score.should == score * 4
145
+ @status.lines.should == lines_num
146
+ end
147
+ end
148
+ end
149
+
150
+ describe "levelups" do
151
+ before do
152
+ @status.reset!
153
+ end
154
+
155
+ it "should not levelup until the user scores a minimum amount of lines" do
156
+ (Status::LEVELUP - 1).times do
157
+ @status.count_kill [1]
158
+ end
159
+
160
+ @status.level.should == 1
161
+ end
162
+
163
+ it "should levelup right after the user scores the needed amount of lines" do
164
+ Status::LEVELUP.times do
165
+ @status.count_kill [1]
166
+ end
167
+
168
+ @status.level.should == 2
169
+ end
170
+
171
+ it "should keep excessive lines count after each levelup" do
172
+ (Status::LEVELUP - 1).times do
173
+ @status.count_kill [1]
174
+ end
175
+
176
+ @status.level.should == 1
177
+
178
+ @status.count_kill [1,2,3]
179
+
180
+ @status.level.should == 2
181
+
182
+ (Status::LEVELUP - 3).times do
183
+ @status.count_kill [1]
184
+ end
185
+
186
+ @status.level.should == 2
187
+
188
+ @status.count_kill [1]
189
+
190
+ @status.level.should == 3
191
+ end
192
+ end
193
+
194
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,103 @@
1
+ require 'rspec'
2
+ require File.join(File.dirname(__FILE__), '..', 'pentix.rb')
3
+
4
+ # a dummy window class to test the modules separately from the main game
5
+ class DummyWindow < Gosu::Window
6
+ attr_accessor :glass, :status
7
+
8
+ # converting `.new` into a singleton to avoid memory leaks in Gosu
9
+ def self.new
10
+ @@win ||= super
11
+ end
12
+
13
+ def initialize
14
+ super(100, 100, false)
15
+ end
16
+
17
+ end
18
+
19
+ #
20
+ # Some pretty formatted matrixes handling helpers
21
+ #
22
+ module MatrixHelper
23
+ def str_to_matrix(str)
24
+ str.scan(/\s*\|(.+?)\|/).map do |line|
25
+ line[0].split('.').map{ |c| c != ' ' }
26
+ end
27
+ end
28
+
29
+ def matrix_to_str(matrix)
30
+ matrix.map do |row|
31
+ "|#{row.map{ |c| c ? 'x' : ' '}.join('.')}|"
32
+ end.join("\n ")
33
+ end
34
+
35
+ def draw_matrix(figure)
36
+ block = actual.instance_variable_get('@block')
37
+ matrix = figure.instance_variable_get('@matrix')
38
+ result = []
39
+ max_x = 0
40
+
41
+ block.class.instance_eval do
42
+ define_method :draw do |x, y|
43
+ x = x - figure.pos_x
44
+ y = y - figure.pos_y
45
+
46
+ result[y] ||= []
47
+ result[y][x] = true
48
+ max_x = x if max_x < x
49
+ end
50
+ end
51
+
52
+ figure.draw
53
+
54
+ # making the size of the rows even
55
+ result.map do |row|
56
+ (row || []).tap do |row|
57
+ (0..max_x).each do |x|
58
+ row[x] = false unless row[x]
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ # making a set of boolean values out of the matrix
65
+ def boolify(matrix)
66
+ matrix.map do |row|
67
+ row.map{ |cell| !!cell}
68
+ end
69
+ end
70
+ end
71
+
72
+ #
73
+ # Figures rendering matcher
74
+ #
75
+ RSpec::Matchers.define :render_blocks do |expected|
76
+ extend MatrixHelper
77
+
78
+ match do |actual|
79
+ boolify(draw_matrix(actual)) == boolify(str_to_matrix(expected))
80
+ end
81
+
82
+ failure_message_for_should do |actual|
83
+ "expected: #{matrix_to_str(str_to_matrix(expected))}\n\n" \
84
+ " got: #{matrix_to_str(draw_matrix(actual))}"
85
+ end
86
+ end
87
+
88
+
89
+ #
90
+ # a readable matrix matcher
91
+ #
92
+ RSpec::Matchers.define :have_matrix do |expected|
93
+ extend MatrixHelper
94
+
95
+ match do |actual|
96
+ boolify(actual.matrix) == boolify(str_to_matrix(expected))
97
+ end
98
+
99
+ failure_message_for_should do |actual|
100
+ "expected: #{matrix_to_str(str_to_matrix(expected))}\n\n" \
101
+ " got: #{matrix_to_str(actual.matrix)}"
102
+ end
103
+ end