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
require "set"
execute = ->(r, op, arg) {
delta = case op
when :acc
{ acc: arg, pc: 1 }
when :jmp
{ pc: arg }
when :nop
{ pc: 1 }
else
fail
end
r.merge(delta) {|_, old, new| old + new }
}
# part 1
seen = Set.new
detect_loop = ->(r, op, arg) {
throw :halt if seen.include?(r[:pc])
seen << r[:pc]
execute[r, op, arg]
}
instructions = ARGF.read.scan(/(\w+) ([-+]\d+)/).map {|op,arg| [op.to_sym, arg.to_i] }
registers = Hash.new(0)
swaps = { nop: :jmp, jmp: :nop }
candidates = instructions.filter_map.with_index {|(op, arg), i|
swap = swaps[op]
if swap.nil?
nil
else
[i, [swap, arg]]
end
}.map {|i, swap|
candidate = instructions.clone
candidate[i] = swap
candidate
}
candidates.each do |candidate|
seen = Set.new
registers = Hash.new(0)
catch(:halt) do
while instruction = candidate[registers[:pc]]
registers = detect_loop[registers, *instruction]
end
end
break if registers[:pc] == candidate.size
end
p registers[:acc]