102 lines
3.2 KiB
Crystal
102 lines
3.2 KiB
Crystal
require "./common.cr"
|
|
|
|
lines = File.read("day16_input").split "\n"
|
|
lines.pop
|
|
count = 0
|
|
end_index = 0
|
|
start_index = 0
|
|
|
|
lines.each_with_index do |line, i|
|
|
if line.size == 0
|
|
count += 1
|
|
else
|
|
count = 0
|
|
end
|
|
|
|
if count == 3
|
|
end_index = i - 3
|
|
start_index = i + 1
|
|
end
|
|
end
|
|
|
|
registers = Array(Int32).new(4, 0)
|
|
OPCODES = {
|
|
"addr" => ->(regs : Array(Int32), a : Int32, b : Int32) { regs[a] + regs[b] },
|
|
"addi" => ->(regs : Array(Int32), a : Int32, b : Int32) { regs[a] + b },
|
|
"mulr" => ->(regs : Array(Int32), a : Int32, b : Int32) { regs[a] * regs[b] },
|
|
"muli" => ->(regs : Array(Int32), a : Int32, b : Int32) { regs[a] * b },
|
|
"banr" => ->(regs : Array(Int32), a : Int32, b : Int32) { regs[a] & regs[b] },
|
|
"bani" => ->(regs : Array(Int32), a : Int32, b : Int32) { regs[a] & b },
|
|
"borr" => ->(regs : Array(Int32), a : Int32, b : Int32) { regs[a] | regs[b] },
|
|
"bori" => ->(regs : Array(Int32), a : Int32, b : Int32) { regs[a] | b },
|
|
"setr" => ->(regs : Array(Int32), a : Int32, b : Int32) { regs[a] },
|
|
"seti" => ->(regs : Array(Int32), a : Int32, b : Int32) { a },
|
|
"gtir" => ->(regs : Array(Int32), a : Int32, b : Int32) { (a > regs[b]) ? 1 : 0 },
|
|
"gtri" => ->(regs : Array(Int32), a : Int32, b : Int32) { (regs[a] > b) ? 1 : 0 },
|
|
"gtrr" => ->(regs : Array(Int32), a : Int32, b : Int32) { (regs[a] > regs[b]) ? 1 : 0 },
|
|
"eqir" => ->(regs : Array(Int32), a : Int32, b : Int32) { (a == regs[b]) ? 1 : 0 },
|
|
"eqri" => ->(regs : Array(Int32), a : Int32, b : Int32) { (regs[a] == b) ? 1 : 0 },
|
|
"eqrr" => ->(regs : Array(Int32), a : Int32, b : Int32) { (regs[a] == regs[b]) ? 1 : 0 },
|
|
}
|
|
|
|
def find_possible(instr, before, after)
|
|
OPCODES.select do |name, code|
|
|
sample = before.dup
|
|
sample[instr[3]] = code.call(sample, instr[1], instr[2])
|
|
sample == after
|
|
end
|
|
end
|
|
|
|
ARRAY_REGEX = /[^:]+:\s*\[([^\]]*)\]/
|
|
|
|
class String
|
|
def extract_array
|
|
self.match(ARRAY_REGEX).not_nil![1].split(", ").map &.to_i32
|
|
end
|
|
end
|
|
|
|
index = 0
|
|
count_more_three = 0
|
|
possibilities = Array(Set(String)).new(16) { Set(String).new }
|
|
while index < end_index
|
|
start_array = lines[index].extract_array
|
|
end_array = lines[index + 2].extract_array
|
|
instruction = lines[index + 1].split(" ").map &.to_i32
|
|
|
|
possible = find_possible(instruction, start_array, end_array)
|
|
count_more_three += 1 if possible.keys.size >= 3
|
|
|
|
opcode = instruction[0]
|
|
old_set = possibilities[opcode]
|
|
if old_set.empty?
|
|
old_set.concat possible.keys
|
|
else
|
|
old_set.each do |it|
|
|
old_set.delete it unless possible.has_key? it
|
|
end
|
|
end
|
|
|
|
index += 4
|
|
end
|
|
puts count_more_three
|
|
|
|
sure_possibilities = {} of Int32 => Proc(Array(Int32), Int32, Int32, Int32)
|
|
while sure_possibilities.keys.size != 16
|
|
possibilities.each_with_index do |set, index|
|
|
next unless set.size == 1
|
|
first = set.first
|
|
sure_possibilities[index] = OPCODES[first]
|
|
possibilities.each &.delete(first)
|
|
end
|
|
end
|
|
|
|
registers = [0, 0, 0, 0]
|
|
index = start_index
|
|
while index < lines.size
|
|
instruction = lines[index].split(" ").map &.to_i32
|
|
registers[instruction[3]] = sure_possibilities[instruction[0]].call(registers, instruction[1], instruction[2])
|
|
index += 1
|
|
end
|
|
puts registers[0]
|
|
# opcodes = {} of Int32 => Proc(Int32, Int32, Int32) # 0 => ->(x : Int32, y : Int32) { x + y }
|