AdventOfCode-2018/day16.cr

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 }