-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathboard.rb
107 lines (77 loc) · 2.56 KB
/
board.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
class BoardOverflowError < StandardError; end
####################################################################################################
#
# Board - a tetris game board
#
# Stored as an x-y grid. Stores either nil or true if the location is occupied
# (0,0) is upper left, and the first corrdinate is height
class Board
attr_accessor :width, :height
def initialize(width, height)
raise "Invalid dimenstions" if width <= 0 || height <= 0
@width, @height = width, height
@grid = (0...@height).map{|_| (0...@width).map{|_| nil}}
end
# adds a piece to the board at a specific x coordinate for the leftmost column of the piece
# removes filled rows at the bottom & returns the number of said rows
def addPiece(piece, x_coord)
raise "invalid coordinate" if x_coord < 0 || x_coord + piece.width > @width
# first, compute width & height offsets where the upper left corner of the piece will go on the board
w_ofs = x_coord
# for each relevant column, compute the location of the uppermost filled square
board_profile = (0...piece.width).map {|w| @grid.transpose[w_ofs + w].index(true) || @height}
# for each column, compute the location of the bottommost filled square(counting from the bottom)
piece_profile = (0...piece.width).map do |w|
(0...piece.height).map{|h| piece.at(h, w)}.reverse.index(true) || 0
end
# get the max distance the piece can be lowered
h_ofs = (0...piece.width).map{|i| board_profile[i] + piece_profile[i]}.min - piece.height
# Example of above algorithm:
#
# 101 <- piece profile
# ---
# *** <- piece
# .*.
# --- <- start of game board
# ...
# ...
# *..
# *..
# *..
# ***
# ---
# 255 <- board profile
# 356 <- board + piece profile
# 3 <- # of squares piece can be lowered
if h_ofs < 0
raise BoardOverflowError
end
# place piece
(0...piece.width).each do |w|
(0...piece.height).each do |h|
@grid[h_ofs + h][w_ofs + w] ||= piece.at(h, w)
end
end
return scoreRows!()
end
def to_s
@grid.map{|row| row.map{|elt| elt ? '*' : '.'}.join()}.join("\n")
end
def at(h, w)
@grid[h][w]
end
private
# finds & removes filled rows at the bottom of the grid. returns number of rows removed
def scoreRows!()
score = 0
while(@grid[@height - 1].all?)
(@height - 1).downto(1).each do |h|
(0...@width).each do |w|
@grid[h][w] = @grid[h - 1][w]
end
end
score += 1
end
return score
end
end