pentix 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/status.rb ADDED
@@ -0,0 +1,110 @@
1
+ #
2
+ # This class handles the game status and things like
3
+ # the next figure, the score and so one
4
+ #
5
+ # Copyright (C) 2011 Nikolay Nemshilov
6
+ #
7
+ class Status
8
+ attr_accessor :figure, :pos_x, :pos_y, :level, :lines, :figures, :score
9
+
10
+ HEAD_FONT = ['Courier', Block::SIZE + 5, Color::GRAY].freeze
11
+ TEXT_FONT = ['Courier New', Block::SIZE, Color::GRAY].freeze
12
+ TEXT_WIDTH = 22 # chars
13
+
14
+ SCORING_SYSTEM = {
15
+ 1 => 100,
16
+ 2 => 300,
17
+ 3 => 500,
18
+ 4 => 800,
19
+ 5 => 1200
20
+ }
21
+
22
+ LEVELUP = 10 # the number of lines to level up
23
+
24
+ def initialize(window, x, y)
25
+ @pos_x = x
26
+ @pos_y = y
27
+
28
+ @head_font = Font.new(window, HEAD_FONT[0], HEAD_FONT[1])
29
+ @text_font = Font.new(window, TEXT_FONT[0], TEXT_FONT[1])
30
+
31
+ reset!
32
+ end
33
+
34
+ def draw
35
+ draw_head "Next:", 0
36
+ @figure.pos_x = @pos_x
37
+ @figure.pos_y = @pos_y + 2
38
+ @figure.draw
39
+
40
+ draw_head "Score:", 9
41
+ draw_text "Level", @level, 10
42
+ draw_text "Score", @score, 11
43
+ draw_text "Lines", @lines, 12
44
+ draw_text "Figures", @figures, 13
45
+
46
+ draw_head "Winnars:", 18
47
+ @records.each_with_index do |entry, i|
48
+ draw_text entry[0], entry[1], 19 + i
49
+ end
50
+ end
51
+
52
+ def reset!
53
+ @level = 1
54
+ @lines = 0
55
+ @score = 0
56
+ @figures = 0
57
+
58
+ # the next levelup lines num
59
+ @levelup = LEVELUP
60
+
61
+ @records = Records.top(6)
62
+ end
63
+
64
+ def count_drop(figure)
65
+ if figure.distance > 0
66
+ @score += figure.distance * @level
67
+ @figures += 1
68
+ end
69
+ end
70
+
71
+ def count_kill(lines)
72
+ if lines.size > 0
73
+ @score += SCORING_SYSTEM[lines.size] * @level
74
+ @lines += lines.size
75
+
76
+ if @lines >= @levelup
77
+ @level += 1
78
+ @levelup = @lines + LEVELUP - @lines % LEVELUP
79
+ end
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ #
86
+ # A shortcut to draw a header text
87
+ #
88
+ def draw_head(text, pos)
89
+ @head_font.draw(
90
+ text, @pos_x * Block::SIZE,
91
+ (@pos_y + pos) * Block::SIZE - 5, # -5 is to shift the too large font a bit
92
+ 0, 1.0, 1.0, HEAD_FONT[2]
93
+ )
94
+ end
95
+
96
+ #
97
+ # A shortcut to draw a normal text
98
+ #
99
+ def draw_text(text, value, pos)
100
+ value = "..#{value}"
101
+ text = text.slice(0, TEXT_WIDTH - value.size)
102
+
103
+ @text_font.draw(
104
+ text.ljust(TEXT_WIDTH - value.size, '.') + value,
105
+ @pos_x * Block::SIZE, (@pos_y + pos) * Block::SIZE,
106
+ 0, 1.0, 1.0, TEXT_FONT[2]
107
+ )
108
+ end
109
+
110
+ end
data/media/block.png ADDED
Binary file
data/pentix.rb ADDED
@@ -0,0 +1,22 @@
1
+ #
2
+ # The main script
3
+ #
4
+ # Copyright (C) 2011 Nikolay Nemshilov
5
+ #
6
+
7
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
8
+
9
+ require 'gosu'
10
+ include Gosu
11
+
12
+ require 'block'
13
+ require 'figure'
14
+ require 'glass'
15
+ require 'status'
16
+ require 'controls'
17
+ require 'records'
18
+ require 'finish'
19
+ require 'game'
20
+
21
+
22
+ Game.new.show if $0 == __FILE__
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Block do
4
+ before :all do
5
+ @window = DummyWindow.new
6
+ @i_args = [@window, 'media/block.png', true]
7
+ @image = Image.new(*@i_args)
8
+ end
9
+
10
+ it "should instance only one image" do
11
+ Image.should_receive(:new).with(*@i_args).once.and_return(@image)
12
+
13
+ @block1 = Block.new(@window, Color::WHITE)
14
+ @block2 = Block.new(@window, Color::WHITE)
15
+ @block3 = Block.new(@window, Color::WHITE)
16
+ end
17
+
18
+ it "should allow access to the block color" do
19
+ Block.new(@window, Color::WHITE).color.should == Color::WHITE
20
+ Block.new(@window, Color::GREEN).color.should == Color::GREEN
21
+ end
22
+
23
+ it "should draw the block in the given position with assigned color" do
24
+ @color = Color::BLUE
25
+ @pos_x = 10
26
+ @pos_y = 20
27
+
28
+ @image.should_receive(:draw).with(@pos_x * Block::SIZE, @pos_y * Block::SIZE, 0, 1.0, 1.0, @color)
29
+
30
+ Block.new(@window, @color).draw(@pos_x, @pos_y)
31
+ end
32
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Controls do
4
+ before :all do
5
+ @controls = Controls.new($test_window)
6
+ end
7
+
8
+ Controls::BUTTONS.each do |command, button|
9
+ it "should recognize the '#{command}' command" do
10
+ @controls.command_for(button).should == command
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,318 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ class DummyWindow
4
+ def show_next_figure
5
+ end
6
+ end
7
+
8
+ describe Figure do
9
+ before :all do
10
+ @window = DummyWindow.new
11
+
12
+ @window.glass = @glass = Glass.new(@window, 1, 2)
13
+ @window.status = @status = Status.new(@window, 20, 2)
14
+ end
15
+
16
+ describe "initialization" do
17
+
18
+ describe "by name" do
19
+ before do
20
+ @name = :stairs
21
+ @color = Figure::COLORS[Figure::FIGURES[@name].split('|').last.to_sym]
22
+ @figure = Figure.new(@window, @name)
23
+ end
24
+
25
+ it "should assign the figure name" do
26
+ @figure.name.should == @name
27
+ end
28
+
29
+ it "should set the right color" do
30
+ @figure.color.should == @color
31
+ end
32
+
33
+ it "should assign a correct matrix" do
34
+ @figure.should have_matrix(%Q{
35
+ |x. . |
36
+ |x.x. |
37
+ | .x.x|
38
+ })
39
+ end
40
+
41
+ it "should preset initial position 0:0" do
42
+ @figure.pos_x.should == 0
43
+ @figure.pos_y.should == 0
44
+ end
45
+
46
+ it "should preset the figure sizes" do
47
+ @figure.size_x.should == 3
48
+ @figure.size_y.should == 3
49
+ end
50
+ end
51
+
52
+ it "should instance random figures if called without a name" do
53
+ [
54
+ Figure.new(@window),
55
+ Figure.new(@window),
56
+ Figure.new(@window),
57
+ Figure.new(@window),
58
+ Figure.new(@window)
59
+ ].map(&:name).uniq.size.should > 1
60
+ end
61
+
62
+ end
63
+
64
+ describe "#draw" do
65
+
66
+ it "should correctly render the cross figure" do
67
+ Figure.new(@window, :cross).should render_blocks(%Q{
68
+ | .x. |
69
+ |x.x.x|
70
+ | .x. |
71
+ })
72
+ end
73
+
74
+ it "should correctly render the stairs figure" do
75
+ Figure.new(@window, :stairs).should render_blocks(%Q{
76
+ |x. . |
77
+ |x.x. |
78
+ | .x.x|
79
+ })
80
+ end
81
+ end
82
+
83
+ describe "manipulations" do
84
+ before do
85
+ @pos_x = @glass.pos_x + 4
86
+ @pos_y = @glass.pos_y
87
+
88
+ @figure = Figure.new(@window, :l_crutch)
89
+ @figure.move_to(@pos_x, @pos_y)
90
+
91
+ @distance = 10
92
+ @glass.stub!(:spaces_below).and_return(@distance)
93
+ end
94
+
95
+ describe "#move_to" do
96
+ before do
97
+ @figure.move_to(10, 20)
98
+ end
99
+
100
+ it "should set the x-position" do
101
+ @figure.pos_x.should == 10
102
+ end
103
+
104
+ it "should set the y-position" do
105
+ @figure.pos_y.should == 20
106
+ end
107
+
108
+ it "should recalc the distance" do
109
+ @figure.distance.should == @distance
110
+ end
111
+ end
112
+
113
+ describe "#move_left" do
114
+ before do
115
+ @figure.move_left
116
+ end
117
+
118
+ it "should decrease the x-position by 1" do
119
+ @figure.pos_x.should == @pos_x - 1
120
+ end
121
+
122
+ it "should set the figure's distance" do
123
+ @figure.distance.should == @distance
124
+ end
125
+
126
+ it "should not move the figure beyond the left border" do
127
+ @pos_x = @figure.pos_x = @glass.pos_x + 1
128
+ @figure.move_left
129
+ @figure.pos_x.should == @pos_x
130
+ end
131
+ end
132
+
133
+ describe "#move_right" do
134
+ before do
135
+ @figure.move_right
136
+ end
137
+
138
+ it "should increase the x-position by 1" do
139
+ @figure.pos_x.should == @pos_x + 1
140
+ end
141
+
142
+ it "should set the figure's distance" do
143
+ @figure.distance.should == @distance
144
+ end
145
+
146
+ it "should not move the figure beyond the right border" do
147
+ @pos_x = @figure.pos_x = @glass.pos_x + Glass::WIDTH + 2 - @figure.size_x
148
+ @figure.move_right
149
+ @figure.pos_x.should == @pos_x
150
+ end
151
+ end
152
+
153
+ describe "#rotate_left" do
154
+ before do
155
+ @figure.turn_left
156
+ end
157
+
158
+ it "should rotate the matrix contr-clockwise" do
159
+ @figure.should have_matrix(%Q{
160
+ | .x. . |
161
+ |x.x.x.x|
162
+ })
163
+ @figure.turn_left
164
+ @figure.should have_matrix(%Q{
165
+ | .x|
166
+ | .x|
167
+ |x.x|
168
+ | .x|
169
+ })
170
+ @figure.turn_left
171
+ @figure.should have_matrix(%Q{
172
+ |x.x.x.x|
173
+ | . .x. |
174
+ })
175
+ @figure.turn_left
176
+ @figure.should have_matrix(%Q{
177
+ |x. |
178
+ |x.x|
179
+ |x. |
180
+ |x. |
181
+ })
182
+ end
183
+
184
+ it "should recalculate the matrix size" do
185
+ @figure.size_x.should == 4
186
+ @figure.size_y.should == 2
187
+
188
+ @figure.turn_left
189
+ @figure.size_x.should == 2
190
+ @figure.size_y.should == 4
191
+ end
192
+
193
+ it "should adjust figure's position to make it look centered" do
194
+ @figure.pos_x.should == @pos_x - 1
195
+ @figure.turn_left #making it vertical again
196
+ @figure.pos_x.should == @pos_x
197
+ end
198
+
199
+ it "should set the figure's distance" do
200
+ @figure.distance.should == @distance
201
+ end
202
+
203
+ it "should not turn the figure if there is no space for that" do
204
+ figure = Figure.new(@window, :h_stick)
205
+
206
+ # setting it vertically
207
+ figure.move_to(@glass.pos_x + 1, @glass.pos_y)
208
+ figure.turn_left
209
+ figure.should have_matrix(%Q{
210
+ |x|
211
+ |x|
212
+ |x|
213
+ |x|
214
+ |x|
215
+ })
216
+
217
+ # moving it to the left border
218
+ figure.move_to(@glass.pos_x + 1, @glass.pos_y)
219
+ figure.turn_left
220
+ figure.should have_matrix(%Q{
221
+ |x|
222
+ |x|
223
+ |x|
224
+ |x|
225
+ |x|
226
+ })
227
+ end
228
+ end
229
+
230
+ describe "#rotate_right" do
231
+ before do
232
+ @figure.turn_right
233
+ end
234
+
235
+ it "should rotate the matrix clockwise" do
236
+ @figure.should have_matrix(%Q{
237
+ |x.x.x.x|
238
+ | . .x. |
239
+ })
240
+ @figure.turn_right
241
+ @figure.should have_matrix(%Q{
242
+ | .x|
243
+ | .x|
244
+ |x.x|
245
+ | .x|
246
+ })
247
+ @figure.turn_right
248
+ @figure.should have_matrix(%Q{
249
+ | .x. . |
250
+ |x.x.x.x|
251
+ })
252
+ @figure.turn_right
253
+ @figure.should have_matrix(%Q{
254
+ |x. |
255
+ |x.x|
256
+ |x. |
257
+ |x. |
258
+ })
259
+ end
260
+
261
+ it "should recalculate the matrix size" do
262
+ @figure.size_x.should == 4
263
+ @figure.size_y.should == 2
264
+
265
+ @figure.turn_right
266
+ @figure.size_x.should == 2
267
+ @figure.size_y.should == 4
268
+ end
269
+
270
+ it "should adjust figure's position to make it look centered" do
271
+ @figure.pos_x.should == @pos_x - 1
272
+ @figure.turn_left #making it vertical again
273
+ @figure.pos_x.should == @pos_x
274
+ end
275
+
276
+ it "should set the figure's distance" do
277
+ @figure.distance.should == @distance
278
+ end
279
+
280
+ it "should not turn the figure if there is no space for that" do
281
+ figure = Figure.new(@window, :h_stick)
282
+
283
+ # setting it vertically
284
+ figure.move_to(@glass.pos_x + 1, @glass.pos_y)
285
+ figure.turn_right
286
+
287
+ # moving it to the left border
288
+ figure.move_to(@glass.pos_x + 1, @glass.pos_y)
289
+ figure.turn_right
290
+
291
+ figure.should have_matrix(%Q{
292
+ |x|
293
+ |x|
294
+ |x|
295
+ |x|
296
+ |x|
297
+ })
298
+ end
299
+ end
300
+ end
301
+
302
+ describe "#drop" do
303
+ before do
304
+ @figure = Figure.new(@window)
305
+ @figure.move_to(@glass.pos_x + 1, @glass.pos_y)
306
+ end
307
+
308
+ it "should call the glass to #glue_in the figure" do
309
+ @glass.should_receive(:glue_in).with(@figure)
310
+ @figure.drop
311
+ end
312
+
313
+ it "should call the @window to #show_next_figure" do
314
+ @window.should_receive(:show_next_figure)
315
+ @figure.drop
316
+ end
317
+ end
318
+ end
@@ -0,0 +1,4 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Game do
4
+ end