81 lines
2.1 KiB
Ruby
81 lines
2.1 KiB
Ruby
|
#!/usr/bin/env ruby
|
||
|
|
||
|
input = (ARGV.first.nil? ? DATA : ARGF)
|
||
|
.readlines(chomp: true)
|
||
|
split = input.index("")
|
||
|
|
||
|
registers = input[...split]
|
||
|
.map { _1.split(": ").last.to_i }
|
||
|
.zip(%i[A B C]).map(&:reverse)
|
||
|
.to_h
|
||
|
program = input[split+1].split(" ").last.split(",").map(&:to_i)
|
||
|
|
||
|
def execute(registers, program)
|
||
|
stdout, ic = Array.new, 0
|
||
|
|
||
|
combo = ->(operand) { operand < 4 ? operand : registers.values[operand - 4] }
|
||
|
|
||
|
while ic < program.size
|
||
|
opcode, operand = program[ic], program[ic + 1]
|
||
|
ic += 2
|
||
|
|
||
|
case opcode
|
||
|
when 0 then registers[:A] = registers[:A] / 2 ** combo.(operand)
|
||
|
when 1 then registers[:B] = registers[:B] ^ operand
|
||
|
when 2 then registers[:B] = combo.(operand) % 8
|
||
|
when 3 then registers[:A] == 0 || ic = operand
|
||
|
when 4 then registers[:B] = registers[:B] ^ registers[:C]
|
||
|
when 5 then stdout << combo.(operand) % 8
|
||
|
when 6 then registers[:B] = registers[:A] / 2 ** combo.(operand)
|
||
|
when 7 then registers[:C] = registers[:A] / 2 ** combo.(operand)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
stdout
|
||
|
end
|
||
|
|
||
|
part_1 = execute(registers.dup, program).join(",")
|
||
|
p part_1
|
||
|
|
||
|
def reverse_engineer(program, slot, candidate)
|
||
|
return candidate if slot < 0
|
||
|
|
||
|
candidate <<= 3 unless slot == program.size - 1
|
||
|
|
||
|
(0..7)
|
||
|
.map { [candidate + _1, execute({A: candidate + _1, B: 0, C: 0}, program)] }
|
||
|
.select { _1.last == program[slot..] }
|
||
|
.flat_map { reverse_engineer(program, slot - 1, _1.first) }
|
||
|
end
|
||
|
|
||
|
p reverse_engineer(program, program.size - 1, 0).sort.first
|
||
|
|
||
|
# part_2 = 0
|
||
|
# (program.size - 1).downto(0) do |slot|
|
||
|
# candidates = []
|
||
|
# (0..8).each do |i|
|
||
|
# candidate = part_2 + i
|
||
|
# _, _, output = execute({A: candidate, B: 0, C: 0}, program)
|
||
|
# new_program = output.split(",").map(&:to_i)
|
||
|
#
|
||
|
# if new_program == program[slot..]
|
||
|
# candidates << candidate
|
||
|
# unless [301,2566855701950, 20534845615581, 20534845615573, 20534845615583].include?(candidate)
|
||
|
# part_2 = candidate
|
||
|
# end
|
||
|
# end
|
||
|
# end
|
||
|
# p candidates
|
||
|
# if slot == 0
|
||
|
# p candidates.first
|
||
|
# end
|
||
|
# part_2 <<= 3
|
||
|
# end
|
||
|
|
||
|
__END__
|
||
|
Register A: 117440
|
||
|
Register B: 0
|
||
|
Register C: 0
|
||
|
|
||
|
Program: 0,3,5,4,3,0
|