parent
73ca0bca60
commit
8d30b0713c
@ -1,55 +1,55 @@
|
||||
require "set"
|
||||
|
||||
class Program
|
||||
attr_reader :accumulator
|
||||
execute = ->(r, op, arg) {
|
||||
delta = case op
|
||||
when :acc
|
||||
{ acc: arg, pc: 1 }
|
||||
when :jmp
|
||||
{ pc: arg }
|
||||
when :nop
|
||||
{ pc: 1 }
|
||||
else
|
||||
fail
|
||||
end
|
||||
|
||||
def initialize(instructions)
|
||||
@instructions = instructions
|
||||
@accumulator = 0
|
||||
@pc = 0
|
||||
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
|
||||
}
|
||||
|
||||
def run
|
||||
seen = Set.new
|
||||
|
||||
loop do
|
||||
break if @pc == @instructions.size
|
||||
|
||||
fail if seen.include?(@pc)
|
||||
seen << @pc
|
||||
|
||||
op, arg = @instructions.fetch(@pc)
|
||||
case op
|
||||
when :acc
|
||||
@accumulator += arg
|
||||
@pc += 1
|
||||
when :jmp
|
||||
@pc += arg
|
||||
when :nop
|
||||
@pc += 1
|
||||
else
|
||||
fail
|
||||
end
|
||||
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
|
||||
|
||||
instructions = ARGF.read.scan(/(\w+) ([-+]\d+)/).map {|op,arg| [op.to_sym, arg.to_i] }
|
||||
uncorrupt = { nop: :jmp, jmp: :nop }
|
||||
(0...instructions.size).select {|i|
|
||||
op, _ = instructions.fetch(i)
|
||||
uncorrupt.has_key?(op)
|
||||
}.map {|i|
|
||||
attempt = instructions.clone
|
||||
instruction = attempt.fetch(i)
|
||||
attempt[i] = [uncorrupt.fetch(instruction[0]), instruction[1]]
|
||||
attempt
|
||||
}.each do |i|
|
||||
program = Program.new(i)
|
||||
begin
|
||||
program.run
|
||||
rescue
|
||||
next
|
||||
end
|
||||
puts "accumulator: #{program.accumulator}"
|
||||
end
|
||||
p registers[:acc]
|
||||
|
Loading…
Reference in new issue