dl-tetris 0.0.1 → 0.0.2
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/README.markdown +9 -0
- data/bin/dl-tetris +3 -0
- data/bin/tetris~ +1 -2
- data/lib/tetris/game.rb +12 -9
- data/lib/tetris/game.rb~ +79 -0
- data/lib/tetris/map.rb +24 -45
- data/lib/tetris/map.rb~ +68 -0
- data/lib/tetris/piece.rb +24 -24
- data/lib/tetris/piece.rb~ +82 -0
- metadata +7 -4
- data/bin/tetris +0 -2
data/README.markdown
CHANGED
@@ -9,6 +9,15 @@ Arrow keys move, up arrow rotates and space drops your piece.
|
|
9
9
|
|
10
10
|

|
11
11
|
|
12
|
+
Installation
|
13
|
+
------------
|
14
|
+
|
15
|
+
`gem install dl-tetris`
|
16
|
+
|
17
|
+
`dl-tetris`
|
18
|
+
|
19
|
+
(Checkout [Rubygems.org](https://rubygems.org/gems/dl-tetris) for more info.)
|
20
|
+
|
12
21
|
Notes
|
13
22
|
-----
|
14
23
|
|
data/bin/dl-tetris
ADDED
data/bin/tetris~
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
|
2
|
-
load boot.rb
|
1
|
+
%x[rsdl $PWD/boot.rb]
|
data/lib/tetris/game.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Game
|
2
2
|
def initialize(w, h, speed, font_file)
|
3
3
|
# Setup rubygame stuff
|
4
|
-
@screen = Rubygame::Screen.new([w * $TileSize, h * $TileSize], 0,
|
4
|
+
@screen = Rubygame::Screen.new([w * $TileSize, h * $TileSize], 0,
|
5
5
|
[Rubygame::HWSURFACE, Rubygame::DOUBLEBUF])
|
6
6
|
@queue = Rubygame::EventQueue.new
|
7
7
|
@clock = Rubygame::Clock.new
|
@@ -18,14 +18,14 @@ class Game
|
|
18
18
|
@step = 0
|
19
19
|
@score = 0
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def run
|
23
23
|
loop do
|
24
24
|
update(@clock.tick)
|
25
25
|
draw
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def update(time_delta)
|
30
30
|
# Process the event queue
|
31
31
|
@queue.each do |ev|
|
@@ -45,7 +45,7 @@ class Game
|
|
45
45
|
end
|
46
46
|
when Rubygame::QuitEvent
|
47
47
|
Rubygame.quit
|
48
|
-
exit
|
48
|
+
exit
|
49
49
|
end
|
50
50
|
end
|
51
51
|
# Update the game state
|
@@ -57,7 +57,7 @@ class Game
|
|
57
57
|
@piece.update(@map) {|x, y, colour| @map.set(x, y, colour)}
|
58
58
|
@score += @map.update
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
def draw_square(x, y, colour, border=true)
|
62
62
|
# Setup the points for SDL
|
63
63
|
x_pos = x * $TileSize
|
@@ -68,12 +68,15 @@ class Game
|
|
68
68
|
@screen.draw_box_s(pt1, pt2, colour)
|
69
69
|
@screen.draw_box(pt1, pt2, :black) if border
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
def draw
|
73
73
|
@screen.fill(@background)
|
74
|
-
|
75
|
-
|
74
|
+
|
75
|
+
draw_squares = lambda {|x, y, colour| draw_square(x, y, colour)}
|
76
|
+
@piece.squares.each &draw_squares
|
77
|
+
@map.squares.each &draw_squares
|
78
|
+
|
76
79
|
@ttf.render("Score: " + @score.to_s, true, :black).blit(@screen, [0,0])
|
77
80
|
@screen.flip
|
78
81
|
end
|
79
|
-
end
|
82
|
+
end
|
data/lib/tetris/game.rb~
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
class Game
|
2
|
+
def initialize(w, h, speed, font_file)
|
3
|
+
# Setup rubygame stuff
|
4
|
+
@screen = Rubygame::Screen.new([w * $TileSize, h * $TileSize], 0,
|
5
|
+
[Rubygame::HWSURFACE, Rubygame::DOUBLEBUF])
|
6
|
+
@queue = Rubygame::EventQueue.new
|
7
|
+
@clock = Rubygame::Clock.new
|
8
|
+
@clock.target_framerate = 30
|
9
|
+
Rubygame::TTF.setup
|
10
|
+
@ttf = Rubygame::TTF.new(font_file, 20)
|
11
|
+
|
12
|
+
# Setup the game of tetris
|
13
|
+
@screen.title = "Tetris"
|
14
|
+
@map = Map.new(w, h)
|
15
|
+
@piece = Piece.new
|
16
|
+
@background = :white
|
17
|
+
@speed = speed
|
18
|
+
@step = 0
|
19
|
+
@score = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
loop do
|
24
|
+
update(@clock.tick)
|
25
|
+
draw
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def update(time_delta)
|
30
|
+
# Process the event queue
|
31
|
+
@queue.each do |ev|
|
32
|
+
case ev
|
33
|
+
when Rubygame::KeyDownEvent
|
34
|
+
case(ev.key)
|
35
|
+
when Rubygame::K_LEFT
|
36
|
+
@piece.move(-1, 0, @map)
|
37
|
+
when Rubygame::K_RIGHT
|
38
|
+
@piece.move(1, 0, @map)
|
39
|
+
when Rubygame::K_DOWN
|
40
|
+
@piece.move(0, 1, @map)
|
41
|
+
when Rubygame::K_UP
|
42
|
+
@piece.rotate(@map)
|
43
|
+
when Rubygame::K_SPACE
|
44
|
+
@piece.drop(@map)
|
45
|
+
end
|
46
|
+
when Rubygame::QuitEvent
|
47
|
+
Rubygame.quit
|
48
|
+
exit
|
49
|
+
end
|
50
|
+
end
|
51
|
+
# Update the game state
|
52
|
+
@step += time_delta
|
53
|
+
if @step > @speed
|
54
|
+
@step -= @speed
|
55
|
+
@piece.move(0, 1, @map)
|
56
|
+
end
|
57
|
+
@piece.update(@map) {|x, y, colour| @map.set(x, y, colour)}
|
58
|
+
@score += @map.update
|
59
|
+
end
|
60
|
+
|
61
|
+
def draw_square(x, y, colour, border=true)
|
62
|
+
# Setup the points for SDL
|
63
|
+
x_pos = x * $TileSize
|
64
|
+
y_pos = y * $TileSize
|
65
|
+
pt1 = [x_pos, y_pos]
|
66
|
+
pt2 = [x_pos + $TileSize, y_pos + $TileSize]
|
67
|
+
# Draw the square and then the border
|
68
|
+
@screen.draw_box_s(pt1, pt2, colour)
|
69
|
+
@screen.draw_box(pt1, pt2, :black) if border
|
70
|
+
end
|
71
|
+
|
72
|
+
def draw
|
73
|
+
@screen.fill(@background)
|
74
|
+
@piece.squares {|x, y, colour| draw_square(x, y, colour)}
|
75
|
+
@map.draw {|coords, colour| draw_square(coords[0], coords[1], colour)}
|
76
|
+
@ttf.render("Score: " + @score.to_s, true, :black).blit(@screen, [0,0])
|
77
|
+
@screen.flip
|
78
|
+
end
|
79
|
+
end
|
data/lib/tetris/map.rb
CHANGED
@@ -2,67 +2,46 @@ class Map
|
|
2
2
|
def initialize(w, h)
|
3
3
|
@w = w
|
4
4
|
@h = h
|
5
|
-
@tiles = Array.new(w, nil)
|
6
|
-
end
|
7
|
-
|
8
|
-
def clear(x, y, w, h)
|
9
|
-
(x..(x + w)).each do |x|
|
10
|
-
(y..(y + h)).each do |y|
|
11
|
-
set(x, y, nil)
|
12
|
-
end
|
13
|
-
end
|
5
|
+
@tiles = Array.new(h) {Array.new(w, nil)}
|
14
6
|
end
|
15
7
|
|
16
8
|
def set(x, y, colour)
|
17
|
-
@tiles[
|
18
|
-
end
|
19
|
-
|
20
|
-
def
|
21
|
-
|
22
|
-
|
9
|
+
@tiles[y][x] = colour
|
10
|
+
end
|
11
|
+
|
12
|
+
def squares
|
13
|
+
Enumerator.new do |yielder|
|
14
|
+
@tiles.each_with_index do |line, y|
|
15
|
+
line.each_with_index do |colour, x|
|
16
|
+
yielder.yield(x, y, colour) if colour
|
17
|
+
end
|
18
|
+
end
|
23
19
|
end
|
24
20
|
end
|
25
21
|
|
26
22
|
def free?(x, y)
|
27
|
-
x >= 0 and x < @w and y >= 0 and y < @h and not @tiles[
|
23
|
+
x >= 0 and x < @w and y >= 0 and y < @h and not @tiles[y][x]
|
28
24
|
end
|
29
25
|
|
30
26
|
def update
|
31
27
|
points = 0
|
32
|
-
shift_lines!
|
33
|
-
# Enumerable should have an every? method
|
34
|
-
if not line.each.any? {|tile| not tile} then
|
35
|
-
points += 1
|
36
|
-
true
|
37
|
-
end
|
38
|
-
end
|
28
|
+
shift_lines! {|line| points += 1 if line.all?}
|
39
29
|
points
|
40
30
|
end
|
41
31
|
|
42
32
|
private
|
43
33
|
|
44
|
-
def coords(p)
|
45
|
-
[p % @w, p / @w]
|
46
|
-
end
|
47
|
-
|
48
|
-
def pos(x, y)
|
49
|
-
x + y * @w
|
50
|
-
end
|
51
|
-
|
52
34
|
def shift_lines!
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
@tiles[
|
62
|
-
|
63
|
-
@tiles[pos(0,y)..pos(@w-1,y)] =
|
64
|
-
@tiles[pos(0,y-distance)..pos(@w-1,y-distance)]
|
65
|
-
shift_line(y-1, distance)
|
35
|
+
@tiles.each_with_index {|line, y| shift_line(y) if yield line}
|
36
|
+
end
|
37
|
+
|
38
|
+
def shift_line(y)
|
39
|
+
case y
|
40
|
+
when 0
|
41
|
+
@tiles[y].fill(nil)
|
42
|
+
when 1..@h
|
43
|
+
@tiles[y] = @tiles[y - 1]
|
44
|
+
shift_line(y - 1)
|
66
45
|
end
|
67
46
|
end
|
68
|
-
end
|
47
|
+
end
|
data/lib/tetris/map.rb~
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
class Map
|
2
|
+
def initialize(w, h)
|
3
|
+
@w = w
|
4
|
+
@h = h
|
5
|
+
@tiles = Array.new(w, nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
def clear(x, y, w, h)
|
9
|
+
(x..(x + w)).each do |x|
|
10
|
+
(y..(y + h)).each do |y|
|
11
|
+
set(x, y, nil)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(x, y, colour)
|
17
|
+
@tiles[pos(x,y)] = colour
|
18
|
+
end
|
19
|
+
|
20
|
+
def draw
|
21
|
+
@tiles.each_with_index do |colour, p|
|
22
|
+
yield(coords(p), colour) if colour
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def free?(x, y)
|
27
|
+
x >= 0 and x < @w and y >= 0 and y < @h and not @tiles[pos(x,y)]
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
points = 0
|
32
|
+
shift_lines! do |line|
|
33
|
+
# Enumerable should have an every? method
|
34
|
+
if not line.each.any? {|tile| not tile} then
|
35
|
+
points += 1
|
36
|
+
true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
points
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def coords(p)
|
45
|
+
[p % @w, p / @w]
|
46
|
+
end
|
47
|
+
|
48
|
+
def pos(x, y)
|
49
|
+
x + y * @w
|
50
|
+
end
|
51
|
+
|
52
|
+
def shift_lines!
|
53
|
+
(0..@h).each do |y|
|
54
|
+
row = (0..@w-1).collect {|x| @tiles[pos(x,y-1)] }
|
55
|
+
shift_line(y-1, 1) if yield row
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def shift_line(y, distance)
|
60
|
+
if y < 1 then
|
61
|
+
@tiles[pos(0,y + distance)..pos(@w-1,y + distance)] = [nil] * @w
|
62
|
+
else
|
63
|
+
@tiles[pos(0,y)..pos(@w-1,y)] =
|
64
|
+
@tiles[pos(0,y-distance)..pos(@w-1,y-distance)]
|
65
|
+
shift_line(y-1, distance)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/tetris/piece.rb
CHANGED
@@ -11,29 +11,13 @@ class Piece
|
|
11
11
|
@colour = $Colours.rand_item
|
12
12
|
end
|
13
13
|
|
14
|
-
def parse_piece_string(s)
|
15
|
-
s.chars.each_with_object([]) do |c, result|
|
16
|
-
case c
|
17
|
-
when " " then result << false
|
18
|
-
when "," then next
|
19
|
-
else result << true
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def load_pieces(pieces)
|
25
|
-
pieces.collect do |piece|
|
26
|
-
piece.collect {|rotation| parse_piece_string rotation}
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
14
|
def squares(piece=current)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
15
|
+
Enumerator.new do |yielder|
|
16
|
+
piece.each_with_index do |tile, i|
|
17
|
+
x, y = coords(i)
|
18
|
+
yielder.yield(@x+x, @y+y, @colour) if tile
|
19
|
+
end
|
35
20
|
end
|
36
|
-
return result
|
37
21
|
end
|
38
22
|
|
39
23
|
def move(x, y, map)
|
@@ -53,13 +37,29 @@ class Piece
|
|
53
37
|
|
54
38
|
def update(map)
|
55
39
|
if collision?(map, 0, 1)
|
56
|
-
squares {|x, y, colour| map.set(x, y, colour)}
|
40
|
+
squares.each {|x, y, colour| map.set(x, y, colour)}
|
57
41
|
initialize
|
58
42
|
end
|
59
43
|
end
|
60
44
|
|
61
45
|
private
|
62
46
|
|
47
|
+
def parse_piece_string(s)
|
48
|
+
s.chars.each_with_object([]) do |c, result|
|
49
|
+
case c
|
50
|
+
when " " then result << false
|
51
|
+
when "," then next
|
52
|
+
else result << true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def load_pieces(pieces)
|
58
|
+
pieces.collect do |piece|
|
59
|
+
piece.collect {|rotation| parse_piece_string rotation}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
63
|
def current
|
64
64
|
@type[@rotation]
|
65
65
|
end
|
@@ -77,6 +77,6 @@ class Piece
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def collision?(map, x_offset, y_offset, piece=current)
|
80
|
-
squares(piece) {|x, y, c| not map.free?(x + x_offset, y + y_offset)}
|
80
|
+
squares(piece).any? {|x, y, c| not map.free?(x + x_offset, y + y_offset)}
|
81
81
|
end
|
82
|
-
end
|
82
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
class Piece
|
2
|
+
@@type_width = 4
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@@types ||= load_pieces($Pieces)
|
6
|
+
|
7
|
+
@type = @@types.rand_item
|
8
|
+
@rotation = 0
|
9
|
+
@x = 0
|
10
|
+
@y = 0
|
11
|
+
@colour = $Colours.rand_item
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_piece_string(s)
|
15
|
+
s.chars.each_with_object([]) do |c, result|
|
16
|
+
case c
|
17
|
+
when " " then result << false
|
18
|
+
when "," then next
|
19
|
+
else result << true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def load_pieces(pieces)
|
25
|
+
pieces.collect do |piece|
|
26
|
+
piece.collect {|rotation| parse_piece_string rotation}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def squares(piece=current)
|
31
|
+
result = []
|
32
|
+
piece.each_with_index do |tile, i|
|
33
|
+
x, y = coords(i)
|
34
|
+
result << yield(@x+x, @y+y, @colour) if tile
|
35
|
+
end
|
36
|
+
return result
|
37
|
+
end
|
38
|
+
|
39
|
+
def move(x, y, map)
|
40
|
+
unless collision?(map, x, y)
|
41
|
+
@x += x
|
42
|
+
@y += y
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def drop(map)
|
47
|
+
@y += 1 while not collision?(map, 0, 1)
|
48
|
+
end
|
49
|
+
|
50
|
+
def rotate(map)
|
51
|
+
@rotation = next_rotation unless collision?(map, 0, 0, @type[next_rotation])
|
52
|
+
end
|
53
|
+
|
54
|
+
def update(map)
|
55
|
+
if collision?(map, 0, 1)
|
56
|
+
squares {|x, y, colour| map.set(x, y, colour)}
|
57
|
+
initialize
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def current
|
64
|
+
@type[@rotation]
|
65
|
+
end
|
66
|
+
|
67
|
+
def next_rotation
|
68
|
+
if @rotation > @type.count - 2
|
69
|
+
return 0
|
70
|
+
else
|
71
|
+
return @rotation + 1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def coords(p)
|
76
|
+
[p % @@type_width, p / @@type_width]
|
77
|
+
end
|
78
|
+
|
79
|
+
def collision?(map, x_offset, y_offset, piece=current)
|
80
|
+
squares(piece) {|x, y, c| not map.free?(x + x_offset, y + y_offset)}.any?
|
81
|
+
end
|
82
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Dave Barker
|
@@ -52,7 +52,7 @@ description: Simple tetris clone written using the rubygame library. Arrow keys
|
|
52
52
|
email:
|
53
53
|
- kzar@kzar.co.uk
|
54
54
|
executables:
|
55
|
-
- tetris
|
55
|
+
- dl-tetris
|
56
56
|
extensions: []
|
57
57
|
|
58
58
|
extra_rdoc_files: []
|
@@ -60,12 +60,15 @@ extra_rdoc_files: []
|
|
60
60
|
files:
|
61
61
|
- bin/boot.rb
|
62
62
|
- bin/boot.rb~
|
63
|
-
- bin/tetris
|
63
|
+
- bin/dl-tetris
|
64
64
|
- bin/tetris~
|
65
65
|
- lib/tetris/core_ruby_ext.rb
|
66
66
|
- lib/tetris/game.rb
|
67
|
+
- lib/tetris/game.rb~
|
67
68
|
- lib/tetris/map.rb
|
69
|
+
- lib/tetris/map.rb~
|
68
70
|
- lib/tetris/piece.rb
|
71
|
+
- lib/tetris/piece.rb~
|
69
72
|
- lib/tetris.rb
|
70
73
|
- test/game_test.rb
|
71
74
|
- test/test_helper.rb
|
data/bin/tetris
DELETED