function get_arg(mem, pos, arg) local param_mode = mem[pos] // (10 ^ (arg + 1)) % 10 if #mem < pos + arg then print(string.format("Error: Opcode too short at end of memory: %d", pos)) os.exit(false) end local arg = mem[pos + arg] if param_mode == 0 then arg = arg + 1 if #mem < arg then print(string.format("Error: Memory offset out of bounds: %d", arg)) os.exit(false) end end return arg end function get_param(mem, pos, arg) local param_mode = mem[pos] // (10 ^ (arg + 1)) % 10 local arg = get_arg(mem, pos, arg) if param_mode == 0 then return mem[arg] end return arg end function interpret(mem) local pos = 1 while true do if #mem < pos then print(string.format("Instruction pointer ran off of memory")) os.exit(false) end local opcode = mem[pos] % 100 if opcode == 1 then mem[get_arg(mem, pos, 3)] = get_param(mem, pos, 1) + get_param(mem, pos, 2) pos = pos + 4 elseif opcode == 2 then mem[get_arg(mem, pos, 3)] = get_param(mem, pos, 1) * get_param(mem, pos, 2) pos = pos + 4 elseif opcode == 3 then io.stdout:write("> ") mem[get_arg(mem, pos, 1)] = io.stdin:read("n") pos = pos + 2 elseif opcode == 4 then io.stdout:write(get_param(mem, pos, 1)) io.stdout:write("\n") pos = pos + 2 elseif opcode == 5 then if get_param(mem, pos, 1) ~= 0 then pos = get_param(mem, pos, 2) + 1 else pos = pos + 3 end elseif opcode == 6 then if get_param(mem, pos, 1) == 0 then pos = get_param(mem, pos, 2) + 1 else pos = pos + 3 end elseif opcode == 7 then mem[get_arg(mem, pos, 3)] = get_param(mem, pos, 1) < get_param(mem, pos, 2) and 1 or 0 pos = pos + 4 elseif opcode == 8 then mem[get_arg(mem, pos, 3)] = get_param(mem, pos, 1) == get_param(mem, pos, 2) and 1 or 0 pos = pos + 4 elseif opcode == 99 then return else print(string.format("Error: Invalid opcode %d at %d", opcode, pos - 1)) os.exit(false) end end end file = io.open(arg[1]) memory = {} for num in string.gmatch(file:read(), "(-?%d+),?") do table.insert(memory, tonumber(num)) end file:close() interpret(memory)