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
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)
|