-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path14-2.rb
executable file
·113 lines (101 loc) · 2.75 KB
/
14-2.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
108
109
110
111
112
113
#!/usr/bin/env ruby
require 'numo/narray'
class Map
attr_accessor :sand
def initialize(input)
min_x = 2**16 - 1
max_x = 0
max_y = 0
input.each do |path|
path.each do |segment|
min_x = segment[0] if segment[0] < min_x
max_x = segment[0] if segment[0] > max_x
max_y = segment[1] if segment[1] > max_y
end
end
@width = max_y * 2 + 5
@height = max_y + 2
@offset = 500 - (@width / 2)
@map = Numo::UInt8.zeros(@width, @height)
@source = [500 - @offset, 0]
@map[@source[0], @source[1]] = 2
@sand = 0
input.each do |path|
last_segment = nil
path.each do |segment|
if last_segment
if last_segment[0] == segment[0] and last_segment[1] < segment[1]
last_segment[1].upto(segment[1]) { |row| @map[segment[0] - @offset, row] = 1 }
elsif last_segment[0] == segment[0] and last_segment[1] > segment[1]
last_segment[1].downto(segment[1]) { |row| @map[segment[0] - @offset, row] = 1 }
elsif last_segment[0] < segment[0] and last_segment[1] == segment[1]
last_segment[0].upto(segment[0]) { |col| @map[col - @offset, segment[1]] = 1 }
elsif last_segment[0] > segment[0] and last_segment[1] == segment[1]
last_segment[0].downto(segment[0]) { |col| @map[col - @offset, segment[1]] = 1 }
end
end
last_segment = segment
end
end
end
def fill!
@sand += 1 while round!
@sand += 1
end
def round!
sand = @source.clone
while true
if sand[1] == @height - 1
@map[sand[0], sand[1]] = 3
return true
elsif @map[sand[0], sand[1] + 1] == 0
sand[1] += 1
elsif @map[sand[0] - 1, sand[1] + 1] == 0
sand[0] -= 1
sand[1] += 1
elsif @map[sand[0] + 1, sand[1] + 1] == 0
sand[0] += 1
sand[1] += 1
else
@map[sand[0], sand[1]] = 3
if sand[0] == @source[0] and sand[1] == @source[1]
return false
else
return true
end
end
end
end
def to_s
s = "<#{self.class}:\n"
s += "Offset: #{@offset}\n"
@height.times do |row|
@width.times do |col|
s += case @map[col, row]
when 0
'.'
when 1
'#'
when 2
'+'
when 3
'o'
end
end
s += "\n"
end
s += "Height: #{@height}>"
s
end
alias inspect to_s
end
input = File.read('14.input').lines
.map(&:strip)
.map do |l| (l.split ' -> ')
.map do |coords| (coords.split ',')
.map(&:to_i)
end
end
map = Map.new(input)
map.fill!
print map.sand, "\n"