Advent of Code 2019 - Lua
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
4.8 KiB

5 years ago
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, state, input_func, output_func)
if not state.pos then
state.pos = 1
end
local pos = state.pos
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
local val = input_func()
if not val then
state.pos = pos
return true
end
mem[get_arg(mem, pos, 1)] = val
pos = pos + 2
elseif opcode == 4 then
output_func(get_param(mem, pos, 1))
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
state.pos = pos
return false
else
print(string.format("Error: Invalid opcode %d at %d", opcode, pos - 1))
os.exit(false)
end
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()
function get_signal(phase)
signal = 0
for i = 1, 5 do
memory = {table.unpack(program)}
output = {}
interpret(memory, {}, input_array({phase[i], signal}), output_array(output))
signal = output[1]
end
return signal
end
function get_signal_p2(phase)
machines = {}
for i = 1, 5 do
if i == 1 then
input = {}
else
input = machines[i - 1].output
end
table.insert(input, phase[i] + 5)
machines[i] = {mem={table.unpack(program)}, input=input, output={}}
end
machines[5].output = machines[1].input
table.insert(machines[1].input, 0)
while true do
done = true
for i = 1, 5 do
if interpret(machines[i].mem, machines[i], input_array(machines[i].input), output_array(machines[i].output)) then
done = false
end
end
if done then
break
end
end
return machines[5].output[1]
end
biggest = 0
biggest_p2 = 0
for i = 0, (5 ^ 5) - 1 do
phase = {
i // (5 ^ 4) % 5,
i // (5 ^ 3) % 5,
i // (5 ^ 2) % 5,
i // (5 ^ 1) % 5,
i // (5 ^ 0) % 5
}
count = {}
for _, x in ipairs(phase) do
if not count[x] then
count[x] = 0
end
count[x] = count[x] + 1
end
double = false
for _, x in pairs(count) do
if x > 1 then
double = true
end
end
if not double then
signal = get_signal(phase)
if signal > biggest then
biggest = signal
end
signal = get_signal_p2(phase)
if signal > biggest_p2 then
biggest_p2 = signal
end
end
end
print("Part 1:", biggest)
print("Part 2:", biggest_p2)