parent
6ff1d97c91
commit
edfd7a1ecb
@ -0,0 +1,101 @@ |
||||
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 } |
Loading…
Reference in new issue