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
input = DATA.read.gsub(
/[#O\.@]/, %w[ # ## O [] . .. @ @. ].each_slice(2).to_h
).split("\n\n")
map = {}
input.shift.split("\n").each.with_index do |row, y|
row.chars.each.with_index do |pos, x|
map[[y,x]] = pos unless pos == ?.
end
end
robot = map.find { _2 == ?@ }.first
bounds = [
(0..map.keys.map(&:first).max),
(0..map.keys.map(&:last).max),
]
map_s = ->() {
bounds[0].map { |y|
bounds[1].map { |x|
map.fetch([y,x], ?.)
}.join
}.join("\n")
}
Nope = Class.new(Exception)
def push(map, pos, move)
delta = DELTAS.fetch(move)
pospos = pos.zip(delta).map { _1 + _2 }
case map.fetch(pospos, nil)
when ?#
raise Nope
when ?[, ?]
case move
when ?<, ?>
push(map, pospos, move)
when ?^, ?v
a = pospos
dx = {?[ => 1, ?] => -1}.fetch(map.fetch(pospos))
b = a.zip([0, dx]).map { _1 + _2 }
push_two(map, a, b, move).reverse.uniq.each do |pos, pospos|
map[pospos] = map.fetch(pos)
map.delete(pos)
end
else
fail
end
when nil
else
fail
end
map[pospos] = map.fetch(pos)
map.delete(pos)
pospos
end
def push_two(map, a, b, move)
delta = DELTAS.fetch(move)
aa = a.zip(delta).map { _1 + _2 }
bb = b.zip(delta).map { _1 + _2 }
[[a, aa], [b, bb]].flat_map {|pos, pospos|
case map.fetch(pospos, nil)
when ?#
raise Nope
when ?[, ?]
a_ = pospos
dx = {?[ => 1, ?] => -1}.fetch(map.fetch(pospos))
b_ = a_.zip([0, dx]).map { _1 + _2 }
[[pos, pospos]] + push_two(map, a_, b_, move)
when nil
[[pos, pospos]]
else
fail
end
}
end
DELTAS = %w[ ^ v < > ].zip([[-1,0], [1,0], [0,-1], [0, 1]]).to_h
movements = input.shift.gsub("\n", "").chars
movements.each do |move|
begin
robot = push(map, robot, move)
rescue Nope
end
end
# pp map.select { _2 == ?O }.sum {|(y,x),_| 100 * y + x }
pp map.select { _2 == ?[ }.sum {|(y,x),_| 100 * y + x }
__END__