/
field.rb
78 lines (62 loc) · 1.74 KB
/
field.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
require_relative 'field/wall'
require_relative 'field/row'
# ゲームの盤面を表すクラス
class Field
# 縦20マス、横10マス に壁を足したサイズ
HEIGHT = 22
WIDTH = 12
def initialize
@rows = Array.new(HEIGHT) { |y| Row.new(y, WIDTH) }
end
# フィールドのブロックを一つずつ処理します。
def each_blocks
each_cells do |cell|
yield cell.block if cell.block
end
end
def [](y, x)
@rows[y][x]
end
def add_block(block)
self[block.y, block.x].block = block
end
def paint(color)
each_cells { |cell| cell.paint color }
end
def clear_lines!
filled_rows = in_field_rows.select { |row| row.filled? }
return if filled_rows.empty?
# 埋まった行を消す
filled_rows.each { |row| row.clear! }
# 消した行より上の、インフィールド内のすべてのブロックを消した行分下にずらす
# 下から順番にずらす
# 上からずらすと、ずらしたブロックがずらす前のブロックと衝突してしまう
y = filled_rows.last.y
in_field_blocks_over(y).reverse.each { |block| block.down filled_rows.size, self }
rescue => e
raise "#{self.inspect}\n#{e.message}\n#{e.backtrace.join("\n")}"
end
def nth_cell_down(n, cell)
self[cell.y + n, cell.x]
end
def inspect
@rows.map(&:inspect).join("\n")
end
private
def each_cells
@rows.each do |row|
row.each do |cell|
yield cell
end
end
end
def in_field_rows
@rows.select { |row| row.is_in_field }
end
def in_field_cells_over(y)
in_field_rows.select { |row| row.y < y }.flat_map(&:in_field_cells)
end
def in_field_blocks_over(y)
in_field_cells_over(y).map(&:block).compact
end
end