[2020][ruby][8.x] refactor
diff --git a/2020/ruby/day_08.rb b/2020/ruby/day_08.rb
index 494ac94..a52e3df 100644
--- a/2020/ruby/day_08.rb
+++ b/2020/ruby/day_08.rb
@@ -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]