diff --git a/day16.cr b/day16.cr new file mode 100644 index 0000000..2a1a719 --- /dev/null +++ b/day16.cr @@ -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 }