You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
advent-of-code/2020/ruby/day_08.rb

56 lines
1.1 KiB

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]