function get_param(state, arg) local param_mode = state.mem[state.pos] // (10 ^ (arg + 1)) % 10 if #state.mem < state.pos + arg then print(string.format("Error: Opcode too short at end of memory: %d", state.pos)) os.exit(false) end local arg = state.mem[state.pos + arg] if param_mode == 0 then arg = arg + 1 elseif param_mode == 2 then arg = arg + state.relbase end return arg end function read_mem(state, arg) local param_mode = state.mem[state.pos] // (10 ^ (arg + 1)) % 10 local arg = get_param(state, arg) if param_mode == 1 then return arg end arg = state.mem[arg] if not arg then return 0 end return arg end function write_mem(state, arg, val) local param_mode = state.mem[state.pos] // (10 ^ (arg + 1)) % 10 local arg = get_param(state, arg) if param_mode == 1 then print(string.format("Error: Invalid inmediate write: %d", arg)) end state.mem[arg] = val end function interpret(state) if not state.mem then state.mem = state end if not state.pos then state.pos = 1 state.relbase = 1 end if not state.input then state.input = input_stdin end if not state.output then state.output = output_stdout end while true do if #state.mem < state.pos then print(string.format("Instruction pointer ran off of memory")) os.exit(false) end local opcode = state.mem[state.pos] % 100 local instr_size = 1 if opcode == 1 then write_mem(state, 3, read_mem(state, 1) + read_mem(state, 2)) instr_size = 4 elseif opcode == 2 then write_mem(state, 3, read_mem(state, 1) * read_mem(state, 2)) instr_size = 4 elseif opcode == 3 then local val = state.input() if not val then return true end write_mem(state, 1, val) instr_size = 2 elseif opcode == 4 then state.output(read_mem(state, 1)) instr_size = 2 elseif opcode == 5 then instr_size = 3 if read_mem(state, 1) ~= 0 then state.pos = read_mem(state, 2) + 1 instr_size = 0 end elseif opcode == 6 then instr_size = 3 if read_mem(state, 1) == 0 then state.pos = read_mem(state, 2) + 1 instr_size = 0 end elseif opcode == 7 then write_mem(state, 3, read_mem(state, 1) < read_mem(state, 2) and 1 or 0) instr_size = 4 elseif opcode == 8 then write_mem(state, 3, read_mem(state, 1) == read_mem(state, 2) and 1 or 0) instr_size = 4 elseif opcode == 9 then state.relbase = state.relbase + read_mem(state, 1) instr_size = 2 elseif opcode == 99 then return false else print(string.format("Error: Invalid opcode %d at %d", opcode, state.pos - 1)) os.exit(false) end state.pos = state.pos + instr_size end end function input_stdin() io.stdout:write("> ") return io.stdin:read("n") end function output_stdout(val) io.stdout:write(val) io.stdout:write("\n") end function input_array(array) function inner() return table.remove(array, 1) end return inner end function output_array(array) function inner(val) table.insert(array, val) end return inner end file = io.open(arg[1]) program = {} for num in string.gmatch(file:read(), "(-?%d+),?") do table.insert(program, tonumber(num)) end file:close() --interpret(program) --file = {} --for line in io.lines(arg[1]) do --fline = {} --for char in line:gmatch(".") do --if char == "." then --table.insert(fline, 0) --else --table.insert(fline, 1) --end --end --table.insert(file, fline) --end result_p1 = 0 angles_low = {} angles_high = {} for y = 0, 49 do --for y = 0, 34 do current = 0 for x = 0, 49 do --for x = 0, 34 do output = {} interpret({mem={table.unpack(program)}, input=input_array({x, y}), output=output_array(output)}) --output = {file[y + 1][x + 1]} result_p1 = result_p1 + output[1] if current ~= output[1] then current = output[1] if current == 1 then table.insert(angles_low, math.atan(y + 0.5, x + 0.5)) else table.insert(angles_high, math.atan(y + 0.5, x + 0.5)) end end end end print("Part 1:", result_p1) p1 = {x=1, y=1} p2 = {x=1, y=1} while (p2.x - p1.x) < 99 or (p1.y - p2.y) < 99 do if (p2.x - p1.x) < 99 then p2.x = p1.x + 99 while true do output = {} interpret({mem={table.unpack(program)}, input=input_array({p2.x, p2.y}), output=output_array(output)}) if output[1] == 1 then break end p2.y = p2.y + 1 end end if (p1.y - p2.y) < 99 then p1.y = p2.y + 99 while true do output = {} interpret({mem={table.unpack(program)}, input=input_array({p1.x, p1.y}), output=output_array(output)}) if output[1] == 1 then break end p1.x = p1.x + 1 end end end print("Part 2:", p1.x * 10000 + p2.y) -- I tried to do this using the law of cosines and it works for the example, but not for the "real" thing... function mean(table) local sum = 0 for _, x in ipairs(table) do sum = sum + x end return sum / #table end angle_low = mean(angles_low) angle_high = mean(angles_high) angle_rect = -math.pi * 1 / 4 print(angle_low, angle_high, angle_rect) angle_alpha = angle_low - angle_high angle_beta = math.pi - (angle_low - angle_rect) angle_gamma = angle_high - angle_rect print(angle_alpha, angle_beta, angle_gamma, (angle_alpha + angle_beta + angle_gamma) / math.pi) length_a = math.sqrt((99 ^ 2) + (99 ^ 2)) --length_a = math.sqrt((9 ^ 2) + (9 ^ 2)) length_b = length_a * math.sin(angle_beta) / math.sin(angle_alpha) length_c = length_a * math.sin(angle_gamma) / math.sin(angle_alpha) pos_low = {x=math.cos(angle_low) * length_c, y=math.sin(angle_low) * length_c} pos_high = {x=math.cos(angle_high) * length_b, y=math.sin(angle_high) * length_b} print(pos_low.x, pos_low.y, pos_high.x, pos_high.y) print(angle_rect + math.pi, math.atan(pos_low.y - pos_high.y, pos_low.x - pos_high.x)) pos_x = math.ceil(pos_low.x - 0.5) pos_y = math.ceil(pos_high.y - 0.5) print("Part 2:", pos_x * 10000 + pos_y)