cem 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/examples/aoc2018/.gitignore +2 -0
- data/examples/aoc2018/day10.rb +61 -0
- data/examples/aoc2018/day11.rb +66 -0
- data/examples/aoc2018/day12.rb +61 -0
- data/examples/aoc2018/day13.rb +167 -0
- data/examples/aoc2018/day14.rb +31 -0
- data/examples/aoc2018/day14_2.rb +71 -0
- data/examples/aoc2018/day15.rb +271 -0
- data/examples/aoc2018/day16.rb +158 -0
- data/examples/aoc2018/day17.rb +203 -0
- data/examples/aoc2018/day18.rb +113 -0
- data/examples/aoc2018/day18_rspec.rb +131 -0
- data/examples/aoc2018/day19.rb +145 -0
- data/examples/aoc2018/day20.rb +103 -0
- data/examples/aoc2018/day21.rb +158 -0
- data/examples/aoc2018/day21_v2.rb +137 -0
- data/examples/aoc2018/day21_v3.rb +157 -0
- data/examples/aoc2018/day21_v4.rb +141 -0
- data/examples/aoc2018/day22.rb +212 -0
- data/examples/aoc2018/day23.rb +148 -0
- data/examples/aoc2018/day24.rb +156 -0
- data/examples/aoc2018/day25.rb +52 -0
- data/examples/aoc2018/day9.rb +51 -0
- data/examples/aoc2018/day9_circular.rb +125 -0
- data/examples/aoc2018/inputs/day10_input.txt +395 -0
- data/examples/aoc2018/inputs/day11_input.txt +1 -0
- data/examples/aoc2018/inputs/day12_input.txt +34 -0
- data/examples/aoc2018/inputs/day12_input2.txt +16 -0
- data/examples/aoc2018/inputs/day13_input.txt +150 -0
- data/examples/aoc2018/inputs/day13_test.txt +6 -0
- data/examples/aoc2018/inputs/day14_input.txt +1 -0
- data/examples/aoc2018/inputs/day15_input.txt +32 -0
- data/examples/aoc2018/inputs/day15_input10.txt +32 -0
- data/examples/aoc2018/inputs/day15_input11.txt +32 -0
- data/examples/aoc2018/inputs/day15_input12.txt +32 -0
- data/examples/aoc2018/inputs/day15_input13.txt +32 -0
- data/examples/aoc2018/inputs/day15_input14.txt +32 -0
- data/examples/aoc2018/inputs/day15_input2.txt +7 -0
- data/examples/aoc2018/inputs/day15_input3.txt +9 -0
- data/examples/aoc2018/inputs/day15_input4.txt +7 -0
- data/examples/aoc2018/inputs/day15_input5.txt +7 -0
- data/examples/aoc2018/inputs/day15_input6.txt +7 -0
- data/examples/aoc2018/inputs/day15_input7.txt +7 -0
- data/examples/aoc2018/inputs/day15_input8.txt +5 -0
- data/examples/aoc2018/inputs/day15_input9.txt +7 -0
- data/examples/aoc2018/inputs/day15_test.txt +9 -0
- data/examples/aoc2018/inputs/day16_input.txt +3865 -0
- data/examples/aoc2018/inputs/day17_input.txt +2229 -0
- data/examples/aoc2018/inputs/day17_input_test.txt +8 -0
- data/examples/aoc2018/inputs/day18_input.txt +50 -0
- data/examples/aoc2018/inputs/day18_test.txt +10 -0
- data/examples/aoc2018/inputs/day19_input.txt +48 -0
- data/examples/aoc2018/inputs/day20_input.txt +1 -0
- data/examples/aoc2018/inputs/day21_input.txt +32 -0
- data/examples/aoc2018/inputs/day22_input.txt +2 -0
- data/examples/aoc2018/inputs/day23_input.txt +1000 -0
- data/examples/aoc2018/inputs/day23_input2.txt +9 -0
- data/examples/aoc2018/inputs/day24_input.txt +24 -0
- data/examples/aoc2018/inputs/day25_input.txt +1483 -0
- data/examples/aoc2018/inputs/day9_input.txt +1 -0
- data/lib/cem.rb +0 -6
- data/lib/cem/ccommon.rb +45 -0
- data/lib/cem/cruzzles.rb +93 -38
- data/lib/cem/version.rb +1 -1
- metadata +62 -2
@@ -0,0 +1,271 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/15 part 1 and part 2
|
4
|
+
#
|
5
|
+
# Demonstrate use of Point2D and Grid
|
6
|
+
#
|
7
|
+
# This task took me a long time, because I did a array.sort instead of array.sort!
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'cem'
|
11
|
+
|
12
|
+
Agent = Struct.new("Agent", :pos, :faction, :hp)
|
13
|
+
|
14
|
+
class Puzzle
|
15
|
+
|
16
|
+
attr_accessor :persons, :lines, :dirs
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@persons = []
|
20
|
+
@grid = []
|
21
|
+
@dirs = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def others(o)
|
25
|
+
@persons.select { |p| p.faction != o.faction }
|
26
|
+
end
|
27
|
+
|
28
|
+
def adjacents(o)
|
29
|
+
@dirs.map {|dir| o.pos + dir if @grid[o.pos + dir] == '.'}.compact
|
30
|
+
end
|
31
|
+
|
32
|
+
def free(pos)
|
33
|
+
@grid[pos] == '.' && @persons.find { |p| p.pos == pos } == nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def printBoard(overlay = nil)
|
37
|
+
|
38
|
+
@grid.data.each_with_index { |l, y|
|
39
|
+
l.each_with_index { |c, x|
|
40
|
+
|
41
|
+
pos = Point2D.new(x,y)
|
42
|
+
|
43
|
+
if overlay && overlay.has_key?(pos)
|
44
|
+
print overlay[pos]
|
45
|
+
else
|
46
|
+
p = @persons.find { |p| p.pos == pos }
|
47
|
+
if p
|
48
|
+
print p.faction
|
49
|
+
else
|
50
|
+
print c
|
51
|
+
end
|
52
|
+
end
|
53
|
+
}
|
54
|
+
|
55
|
+
puts " " + @persons.select{ |p| p.pos.y == y }.sort_by { |p| p.pos.x }.map {|p| "#{p.faction}(#{p.hp})"}.join(", ")
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def run(inputFilename, debug, elvenPower=3)
|
60
|
+
|
61
|
+
# Crucial to sort the directions as given in the problem description
|
62
|
+
@dirs = Dirs2D.sort_by { |pos| pos.y * 10000 + pos.x }
|
63
|
+
|
64
|
+
lines = []
|
65
|
+
File.readlines(inputFilename, chomp: true).each { |line|
|
66
|
+
lines << line.rstrip.chars
|
67
|
+
}
|
68
|
+
|
69
|
+
@grid = Grid.new(lines.size, lines[0].size, ' ')
|
70
|
+
@grid.data = lines
|
71
|
+
|
72
|
+
# Read board
|
73
|
+
@grid.map_a! { |p, c|
|
74
|
+
case c
|
75
|
+
when 'E', 'G'
|
76
|
+
@persons << Agent.new(p, c, 200)
|
77
|
+
next '.'
|
78
|
+
end
|
79
|
+
}
|
80
|
+
|
81
|
+
generation = -1
|
82
|
+
|
83
|
+
loop do
|
84
|
+
|
85
|
+
system "cls" if debug
|
86
|
+
|
87
|
+
generation += 1
|
88
|
+
|
89
|
+
if generation == 0
|
90
|
+
puts "Initial Generation with power #{elvenPower}" if debug
|
91
|
+
else
|
92
|
+
puts "After Generation: #{generation} with power #{elvenPower}" if debug
|
93
|
+
end
|
94
|
+
|
95
|
+
printBoard if debug
|
96
|
+
#gets if debug && generation >= 70
|
97
|
+
|
98
|
+
@persons.sort_by { |cart| cart.pos.y * 10000 + cart.pos.x }.each { |p|
|
99
|
+
|
100
|
+
next if !@persons.include?(p)
|
101
|
+
|
102
|
+
if @persons.select {|p| p.faction == 'E' }.size == 0 || @persons.select {|p| p.faction == 'G' }.size == 0
|
103
|
+
system "cls" if debug
|
104
|
+
puts "Before Generation: #{generation} finishes" if debug
|
105
|
+
printBoard if debug
|
106
|
+
|
107
|
+
puts "#{generation} * #{@persons.sum {|p| p.hp }} = #{generation * @persons.sum {|p| p.hp }}"
|
108
|
+
return (@persons[0].faction == 'E' ? 1 : -1) * generation * @persons.sum {|p| p.hp }
|
109
|
+
end
|
110
|
+
|
111
|
+
# puts p.inspect
|
112
|
+
|
113
|
+
# Moving
|
114
|
+
nearby = @persons.select { |o| o.faction != p.faction && dirs.any? { |dir| p.pos + dir == o.pos } }.group_by { |o| o.hp }.min_by { |k,v| k }
|
115
|
+
|
116
|
+
if nearby == nil || nearby.size == 0
|
117
|
+
distancemap = Array.new(@grid.data.size) { Array.new(@grid[0].size)}
|
118
|
+
|
119
|
+
targets = Set.new(others(p).map {|o| adjacents(o)}.flatten)
|
120
|
+
|
121
|
+
s = p.pos
|
122
|
+
distancemap[s.y][s.x] = 0
|
123
|
+
bfs = []
|
124
|
+
bfsNG = [s]
|
125
|
+
found = []
|
126
|
+
|
127
|
+
target = []
|
128
|
+
while bfsNG.size > 0 && found.size == 0
|
129
|
+
bfs = bfsNG
|
130
|
+
bfsNG = []
|
131
|
+
while bfs.size > 0
|
132
|
+
|
133
|
+
s = bfs.shift
|
134
|
+
|
135
|
+
dirs.each { |dir|
|
136
|
+
|
137
|
+
s2 = s + dir
|
138
|
+
|
139
|
+
if free(s2)
|
140
|
+
|
141
|
+
if distancemap[s2.y][s2.x] == nil
|
142
|
+
bfsNG << s2
|
143
|
+
#puts " free " + s2.inspect + " - " + dir.to_s
|
144
|
+
distancemap[s2.y][s2.x] = dir.flip
|
145
|
+
end
|
146
|
+
|
147
|
+
if targets.include?(s2)
|
148
|
+
found << s2
|
149
|
+
end
|
150
|
+
end
|
151
|
+
}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
if found.size > 0
|
156
|
+
found.sort_by! { |p| p.y * 10000 + p.x }
|
157
|
+
|
158
|
+
overlay = {}
|
159
|
+
|
160
|
+
if found.size > 1
|
161
|
+
found.each { |p| overlay[p] = '+' }
|
162
|
+
overlay[found[0]] = 'X'
|
163
|
+
end
|
164
|
+
|
165
|
+
target = found[0]
|
166
|
+
#puts " Target: #{target}"
|
167
|
+
|
168
|
+
lastMove = nil
|
169
|
+
|
170
|
+
while target && target != p.pos
|
171
|
+
lastMove = distancemap[target.y][target.x]
|
172
|
+
#puts target.inspect
|
173
|
+
overlay[target] = 'x'
|
174
|
+
target = target + lastMove
|
175
|
+
end
|
176
|
+
|
177
|
+
#if generation >= 77
|
178
|
+
# system('cls')
|
179
|
+
# printBoard(overlay)
|
180
|
+
# puts found.inspect
|
181
|
+
# gets
|
182
|
+
#end
|
183
|
+
|
184
|
+
p.pos = p.pos + lastMove.flip if lastMove
|
185
|
+
#puts " Moved to #{p.pos}"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Fighting
|
190
|
+
nearby = @persons.select { |o| o.faction != p.faction && dirs.any? { |dir| p.pos + dir == o.pos } }.group_by { |o| o.hp }.min_by { |k,v| k }
|
191
|
+
if nearby && nearby.size > 0
|
192
|
+
nearby = nearby[1]
|
193
|
+
|
194
|
+
#puts "Fighting"
|
195
|
+
nearby.sort_by! { |cart| cart.pos.y * 10000 + cart.pos.x }
|
196
|
+
|
197
|
+
if p.faction == 'E'
|
198
|
+
nearby[0].hp -= elvenPower
|
199
|
+
else
|
200
|
+
nearby[0].hp -= 3
|
201
|
+
end
|
202
|
+
|
203
|
+
if (nearby[0].hp <= 0)
|
204
|
+
@persons -= [nearby[0]]
|
205
|
+
|
206
|
+
if nearby[0].faction == 'E' && elvenPower > 3
|
207
|
+
return -1
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
}
|
213
|
+
|
214
|
+
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
part1 = {
|
221
|
+
# "inputs/day15_input14.txt" => -248848,
|
222
|
+
# "inputs/day15_input13.txt" => -261855,
|
223
|
+
# "inputs/day15_input12.txt" => -189000,
|
224
|
+
# "inputs/day15_input11.txt" => '?',
|
225
|
+
# "inputs/day15_input10.txt" => -261855,
|
226
|
+
# "inputs/day15_input2.txt" => -27730,
|
227
|
+
# "inputs/day15_input3.txt" => -18740,
|
228
|
+
# "inputs/day15_input4.txt" => 36334,
|
229
|
+
# "inputs/day15_input5.txt" => 39514,
|
230
|
+
# "inputs/day15_input6.txt" => -27755,
|
231
|
+
# "inputs/day15_input7.txt" => -28944,
|
232
|
+
"inputs/day15_input.txt" => '?'
|
233
|
+
}
|
234
|
+
|
235
|
+
debug = false
|
236
|
+
|
237
|
+
part1.each_pair { |k,v|
|
238
|
+
|
239
|
+
power = 3
|
240
|
+
is = Puzzle.new.run(k, debug, power)
|
241
|
+
|
242
|
+
puts "Part 1: #{k} == #{is}"
|
243
|
+
if is != v && v != '?'
|
244
|
+
puts "#{k} should be #{v}, but is #{is}"
|
245
|
+
exit
|
246
|
+
end
|
247
|
+
}
|
248
|
+
|
249
|
+
|
250
|
+
part2 = {
|
251
|
+
"inputs/day15_input.txt" => '?'
|
252
|
+
}
|
253
|
+
|
254
|
+
part2.each_pair { |k,v|
|
255
|
+
|
256
|
+
power = 4
|
257
|
+
while true
|
258
|
+
# puts "Elven Power: #{power} "
|
259
|
+
is = Puzzle.new.run(k, debug, power)
|
260
|
+
power += 1
|
261
|
+
if is > 0
|
262
|
+
break;
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
puts "Part 2: #{k} == #{is}"
|
267
|
+
if is != v && v != '?'
|
268
|
+
puts "#{k} should be #{v}, but is #{is}"
|
269
|
+
exit
|
270
|
+
end
|
271
|
+
}
|
@@ -0,0 +1,158 @@
|
|
1
|
+
#
|
2
|
+
# https://adventofcode.com/2018/day/16 part 1 and part 2
|
3
|
+
#
|
4
|
+
# Does not use any 'cem' functions
|
5
|
+
#
|
6
|
+
|
7
|
+
input = File.readlines("inputs/day16_input.txt", chomp: true)
|
8
|
+
|
9
|
+
data = []
|
10
|
+
inputs = []
|
11
|
+
|
12
|
+
input.each { |line|
|
13
|
+
|
14
|
+
if line =~ /^Before\: \[([+-]?\d+), ([+-]?\d+), ([+-]?\d+), ([+-]?\d+)\]$/
|
15
|
+
|
16
|
+
v1 = $1.to_i
|
17
|
+
v2 = $2.to_i
|
18
|
+
v3 = $3.to_i
|
19
|
+
v4 = $4.to_i
|
20
|
+
|
21
|
+
data << [v1,v2,v3,v4]
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
if line =~ /^([+-]?\d+) ([+-]?\d+) ([+-]?\d+) ([+-]?\d+)$/
|
26
|
+
|
27
|
+
|
28
|
+
v1 = $1.to_i
|
29
|
+
v2 = $2.to_i
|
30
|
+
v3 = $3.to_i
|
31
|
+
v4 = $4.to_i
|
32
|
+
|
33
|
+
data << [v1,v2,v3,v4]
|
34
|
+
end
|
35
|
+
|
36
|
+
if line =~ /^After\: \[([+-]?\d+), ([+-]?\d+), ([+-]?\d+), ([+-]?\d+)\]$/
|
37
|
+
v1 = $1.to_i
|
38
|
+
v2 = $2.to_i
|
39
|
+
v3 = $3.to_i
|
40
|
+
v4 = $4.to_i
|
41
|
+
|
42
|
+
data << [v1,v2,v3,v4]
|
43
|
+
|
44
|
+
# puts data.inspect
|
45
|
+
inputs << data
|
46
|
+
data = []
|
47
|
+
end
|
48
|
+
|
49
|
+
if line =~ /^$/
|
50
|
+
# data << $1.to_i
|
51
|
+
end
|
52
|
+
}
|
53
|
+
|
54
|
+
mapping = {}
|
55
|
+
|
56
|
+
def op(op, reg, command)
|
57
|
+
|
58
|
+
case op
|
59
|
+
|
60
|
+
when 0 # addr
|
61
|
+
reg[command[1]] + reg[command[2]]
|
62
|
+
|
63
|
+
when 1 # addi
|
64
|
+
reg[command[1]] + command[2]
|
65
|
+
|
66
|
+
when 2 # mulr
|
67
|
+
reg[command[1]] * reg[command[2]]
|
68
|
+
|
69
|
+
when 3 #muli
|
70
|
+
reg[command[1]] * command[2]
|
71
|
+
|
72
|
+
when 4 # banr
|
73
|
+
reg[command[1]] & reg[command[2]]
|
74
|
+
|
75
|
+
when 5 # bani
|
76
|
+
reg[command[1]] & command[2]
|
77
|
+
|
78
|
+
when 6 # borr
|
79
|
+
reg[command[1]] | reg[command[2]]
|
80
|
+
|
81
|
+
when 7 # bori
|
82
|
+
reg[command[1]] | command[2]
|
83
|
+
|
84
|
+
when 8 # setr
|
85
|
+
reg[command[1]]
|
86
|
+
|
87
|
+
when 9 # seti
|
88
|
+
command[1]
|
89
|
+
|
90
|
+
when 10 # gtir
|
91
|
+
command[1] > reg[command[2]] ? 1 : 0
|
92
|
+
|
93
|
+
when 11 # gtri
|
94
|
+
reg[command[1]] > command[2] ? 1 : 0
|
95
|
+
|
96
|
+
when 12 # gtrr
|
97
|
+
reg[command[1]] > reg[command[2]] ? 1 : 0
|
98
|
+
|
99
|
+
when 13 # eqir
|
100
|
+
command[1] == reg[command[2]] ? 1 : 0
|
101
|
+
|
102
|
+
when 14 # eqri
|
103
|
+
reg[command[1]] == command[2] ? 1 : 0
|
104
|
+
|
105
|
+
when 15 # eqrr
|
106
|
+
reg[command[1]] == reg[command[2]] ? 1 : 0
|
107
|
+
|
108
|
+
else
|
109
|
+
raise
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
result = 0
|
114
|
+
inputs.each { |data|
|
115
|
+
|
116
|
+
# puts data.inspect
|
117
|
+
|
118
|
+
# puts "Before: " + data[0].inspect
|
119
|
+
# puts "OP : " + data[1].inspect
|
120
|
+
# puts "After : " + data[2].inspect
|
121
|
+
|
122
|
+
# puts data[1].inspect + ": Cmd #{data[1][0]} on reg#{data[1][1]} val=#{data[0][data[1][1]]} op? reg#{data[1][2]} val=#{data[0][data[1][2]]} (imm #{data[1][2]}) == #{data[2][data[1][3]]} (was #{data[0][data[1][3]]})"
|
123
|
+
|
124
|
+
command = data[1]
|
125
|
+
matches = []
|
126
|
+
(0..15).each { |i|
|
127
|
+
|
128
|
+
reg = data[0].dup
|
129
|
+
|
130
|
+
reg[command[3]] = op(i, reg, command)
|
131
|
+
|
132
|
+
if reg == data[2]
|
133
|
+
matches << i
|
134
|
+
end
|
135
|
+
}
|
136
|
+
|
137
|
+
result += 1 if matches.size >= 3
|
138
|
+
|
139
|
+
matches = matches.select { |m| !mapping.values.include?(m) }
|
140
|
+
|
141
|
+
if matches.size == 1
|
142
|
+
mapping[data[1][0]] = matches[0]
|
143
|
+
end
|
144
|
+
|
145
|
+
# puts matches.inspect
|
146
|
+
}
|
147
|
+
|
148
|
+
# puts mapping.inspect
|
149
|
+
|
150
|
+
puts "Part 1: #{result}"
|
151
|
+
|
152
|
+
reg = [0,0,0,0]
|
153
|
+
|
154
|
+
data.each { |command|
|
155
|
+
reg[command[3]] = op(mapping[command[0]], reg, command)
|
156
|
+
}
|
157
|
+
|
158
|
+
puts "Part 2: #{reg[0]}"
|
@@ -0,0 +1,203 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/17 part 1 and 2
|
4
|
+
#
|
5
|
+
# Demonstrates Point2D and Dir2D in particular #left, #right, #down methods. Could use Grid!
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'cem'
|
9
|
+
require 'set'
|
10
|
+
|
11
|
+
input = File.readlines("inputs/day17_input.txt", chomp: true)
|
12
|
+
|
13
|
+
@vert = []
|
14
|
+
@hori = []
|
15
|
+
@waterTiles = Set.new
|
16
|
+
@deepWater = Set.new
|
17
|
+
|
18
|
+
input.each { |line|
|
19
|
+
|
20
|
+
if line =~ /^y=([+-]?\d+), x=([+-]?\d+)..([+-]?\d+)$/
|
21
|
+
v1 = $1.to_i
|
22
|
+
v2 = $2.to_i
|
23
|
+
v3 = $3.to_i
|
24
|
+
|
25
|
+
@vert << [v1,v2,v3]
|
26
|
+
end
|
27
|
+
|
28
|
+
if line =~ /^x=([+-]?\d+), y=([+-]?\d+)..([+-]?\d+)$/
|
29
|
+
v1 = $1.to_i
|
30
|
+
v2 = $2.to_i
|
31
|
+
v3 = $3.to_i
|
32
|
+
|
33
|
+
@hori << [v1,v2,v3]
|
34
|
+
end
|
35
|
+
}
|
36
|
+
|
37
|
+
@minY = [@vert.map { |v| v[0] }.min, @hori.map { |h| h[1] }.min].min
|
38
|
+
@maxY = [@vert.map { |v| v[0] }.max, @hori.map { |h| h[2] }.max].max
|
39
|
+
|
40
|
+
@minX = [@hori.map { |v| v[0] }.min, @vert.map { |h| h[1] }.min].min
|
41
|
+
@maxX = [@hori.map { |v| v[0] }.max, @vert.map { |h| h[2] }.max].max
|
42
|
+
|
43
|
+
cursor = Point2D.new(500, @minY)
|
44
|
+
|
45
|
+
@map = []
|
46
|
+
(0..@maxY + 1).each { |y|
|
47
|
+
@map << []
|
48
|
+
(0..@maxX + 1).each { |x|
|
49
|
+
@map[y] << ' '
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
@vert.each { |v|
|
54
|
+
(v[1]..v[2]).each {|x| @map[v[0]][x] = 'x' }
|
55
|
+
}
|
56
|
+
@hori.each {|h|
|
57
|
+
(h[1]..h[2]).each {|y| @map[y][h[0]] = 'x' }
|
58
|
+
}
|
59
|
+
|
60
|
+
def free(cursor)
|
61
|
+
@map[cursor.y][cursor.x] == ' '
|
62
|
+
end
|
63
|
+
|
64
|
+
def printMap(filename, map, overlay, deepWater, cursor=nil, windowSizeY = 15, windowSizeX = 35)
|
65
|
+
|
66
|
+
file = File.open(filename, 'w') if filename
|
67
|
+
|
68
|
+
if !filename
|
69
|
+
system('cls')
|
70
|
+
puts cursor
|
71
|
+
end
|
72
|
+
|
73
|
+
rangeY = cursor ? ((cursor.y - windowSizeY)..(cursor.y + windowSizeY)) : 0...map.size
|
74
|
+
rangeX = cursor ? ((cursor.x - windowSizeX)..(cursor.x + windowSizeX)) : 0...map[0].size
|
75
|
+
|
76
|
+
rangeY.each { |y|
|
77
|
+
l = map[y]
|
78
|
+
line = ''
|
79
|
+
rangeX.each { |x|
|
80
|
+
if l != nil
|
81
|
+
c = l[x]
|
82
|
+
else
|
83
|
+
c = nil
|
84
|
+
end
|
85
|
+
|
86
|
+
if c == nil
|
87
|
+
c = '?'
|
88
|
+
end
|
89
|
+
|
90
|
+
pos = Point2D.new(x,y)
|
91
|
+
if deepWater && deepWater.include?(pos)
|
92
|
+
line += '~'
|
93
|
+
elsif overlay && overlay.include?(pos)
|
94
|
+
line += '|'
|
95
|
+
else
|
96
|
+
line += c
|
97
|
+
end
|
98
|
+
}
|
99
|
+
if filename
|
100
|
+
file.write(line + "\n")
|
101
|
+
else
|
102
|
+
puts line
|
103
|
+
end
|
104
|
+
}
|
105
|
+
|
106
|
+
if !filename
|
107
|
+
gets
|
108
|
+
else
|
109
|
+
file.close
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# returns true if all available space has been filled
|
116
|
+
#
|
117
|
+
def cursorMove(cursor)
|
118
|
+
|
119
|
+
cursorStart = cursor
|
120
|
+
|
121
|
+
@waterTiles << cursor
|
122
|
+
|
123
|
+
# Traverse down from cursor position
|
124
|
+
while free(cursor.down) && cursor.y < @maxY && !@waterTiles.include?(cursor.down)
|
125
|
+
printMap(nil, @map, @waterTiles, @deepWater, cursor) if false
|
126
|
+
|
127
|
+
cursor = cursor.down
|
128
|
+
@waterTiles << cursor
|
129
|
+
end
|
130
|
+
|
131
|
+
if cursor.y == @maxY
|
132
|
+
return false # we moved out of the field - stop recursion
|
133
|
+
end
|
134
|
+
|
135
|
+
if @waterTiles.include?(cursor.down) && !@deepWater.include?(cursor.down)
|
136
|
+
return false # already been here
|
137
|
+
end
|
138
|
+
|
139
|
+
# Below us is rock
|
140
|
+
left = right = rowStart = cursor
|
141
|
+
|
142
|
+
row = Set.new
|
143
|
+
row << rowStart
|
144
|
+
|
145
|
+
while true
|
146
|
+
|
147
|
+
while free(left.left) && !@waterTiles.include?(left.left) && (!free(left.down) || @deepWater.include?(left.down))
|
148
|
+
left = left.left
|
149
|
+
row << left
|
150
|
+
@waterTiles << left
|
151
|
+
end
|
152
|
+
|
153
|
+
while free(right.right) && !@waterTiles.include?(right.right) && (!free(right.down) || @deepWater.include?(right.down))
|
154
|
+
right = right.right
|
155
|
+
row << right
|
156
|
+
@waterTiles << right
|
157
|
+
end
|
158
|
+
|
159
|
+
printMap(nil, @map, @waterTiles, @deepWater, cursor) if false # && cursor.y > 1300 && cursor.y < 1330
|
160
|
+
|
161
|
+
if !free(right.right) && (!free(right.down) || @deepWater.include?(right.down)) && !free(left.left) && (!free(left.down) || @deepWater.include?(left.down))
|
162
|
+
|
163
|
+
# Move up
|
164
|
+
rowStart = rowStart.up
|
165
|
+
|
166
|
+
@deepWater.merge row
|
167
|
+
row = Set.new
|
168
|
+
row << rowStart
|
169
|
+
|
170
|
+
if rowStart.y < cursorStart.y
|
171
|
+
return true # Return true, if we filled all available space
|
172
|
+
end
|
173
|
+
|
174
|
+
left = right = rowStart
|
175
|
+
|
176
|
+
# Fill again...
|
177
|
+
|
178
|
+
else
|
179
|
+
|
180
|
+
a = !@waterTiles.include?(right.right) && !@waterTiles.include?(left.left)
|
181
|
+
if free(right.down) && !(!free(right.down) || @deepWater.include?(right.down))
|
182
|
+
a &= cursorMove(right.down)
|
183
|
+
end
|
184
|
+
|
185
|
+
if free(left.left) && !(!free(left.down) || @deepWater.include?(left.down))
|
186
|
+
a &= cursorMove(left.down)
|
187
|
+
end
|
188
|
+
|
189
|
+
if !a
|
190
|
+
break
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
return false
|
196
|
+
end
|
197
|
+
|
198
|
+
cursorMove(cursor)
|
199
|
+
|
200
|
+
printMap("day17.out", @map, @waterTiles, @deepWater) if false
|
201
|
+
|
202
|
+
puts "Part 1: #{@waterTiles.size}"
|
203
|
+
puts "Part 2: #{@deepWater.size}"
|