#!/usr/bin/env ruby # What can I say? I like the word reify. vars = {} nets = [] class Var def initialize(name) @name = name @value = nil end attr_reader :name, :value def reified? !@value.nil? end def try_reify_numeric! if @name =~ /\A\d+\Z/ @value = @name.to_i end end def reify!(value) @value = value end def reify_negative! @value = 65536 + @value if @value < 0 end def reset! @value = nil end end class Net def initialize(left, op, right, out) @left = left @op = op @right = right @out = out @reified = false end def reified? @reified end def reifiable? return false unless @left.nil? || @left.reified? return false unless @right.reified? return true end def reify! case @op when nil @out.reify!(@right.value) when "NOT" @out.reify!(~@right.value) when "AND" @out.reify!(@left.value & @right.value) when "OR" @out.reify!(@left.value | @right.value) when "LSHIFT" @out.reify!(@left.value << @right.value) when "RSHIFT" @out.reify!(@left.value >> @right.value) end @reified = true end def reset! @reified = false end end File.readlines("day7.input").map(&:strip).each do |line| input, output = line.split(" -> ") input = input.split vars[output] = Var.new(output) if vars[output].nil? output = vars[output] case input.length when 1 vars[input[0]] = Var.new(input[0]) if vars[input[0]].nil? nets << Net.new(nil, nil, vars[input[0]], output) when 2 vars[input[1]] = Var.new(input[1]) if vars[input[1]].nil? nets << Net.new(nil, input[0], vars[input[1]], output) when 3 vars[input[0]] = Var.new(input[0]) if vars[input[0]].nil? vars[input[2]] = Var.new(input[2]) if vars[input[2]].nil? nets << Net.new(vars[input[0]], input[1], vars[input[2]], output) end end # Part 1 vars.values.each(&:try_reify_numeric!) until nets.all?(&:reified?) nets.each do |net| net.reify! if net.reifiable? end end vars.values.each(&:reify_negative!) part1 = vars["a"].value puts "Part 1: #{part1}" # Part 2 vars.values.each(&:reset!) nets.each(&:reset!) vars.values.each(&:try_reify_numeric!) until nets.all?(&:reified?) nets.each do |net| vars["b"].reify!(part1) net.reify! if net.reifiable? end end vars.values.each(&:reify_negative!) part2 = vars["a"].value puts "Part 2: #{part2}"