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.
264 lines
6.5 KiB
264 lines
6.5 KiB
5 years ago
|
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)
|
||
|
|
||
|
map = {}
|
||
|
line = {}
|
||
|
interpret({mem={table.unpack(program)}, output=function(val)
|
||
|
local val = string.char(val)
|
||
|
if val == "\n" then
|
||
|
table.insert(map, line)
|
||
|
line = {}
|
||
|
else
|
||
|
table.insert(line, val)
|
||
|
end
|
||
|
end})
|
||
|
|
||
|
part1 = 0
|
||
|
for y = 2, #map - 1 do
|
||
|
for x = 2, #map[y] - 1 do
|
||
|
if map[y][x] == "#" and map[y-1][x] == "#" and map[y][x+1] == "#" and map[y+1][x] == "#" and map[y][x-1] == "#" then
|
||
|
part1 = part1 + (y-1) * (x-1)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
print("Part 1:", part1)
|
||
|
|
||
|
pos = nil
|
||
|
for y = 1, #map do
|
||
|
for x = 1, #map[y] do
|
||
|
if map[y][x] == "^" then
|
||
|
pos = {y=y, x=x}
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
if pos then
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function get_nextpos(pos, direction)
|
||
|
if direction == "^" then
|
||
|
next_pos = {y=pos.y - 1, x=pos.x}
|
||
|
elseif direction == ">" then
|
||
|
next_pos = {y=pos.y, x=pos.x + 1}
|
||
|
elseif direction == "v" then
|
||
|
next_pos = {y=pos.y + 1, x=pos.x}
|
||
|
elseif direction == "<" then
|
||
|
next_pos = {y=pos.y, x=pos.x - 1}
|
||
|
end
|
||
|
return next_pos
|
||
|
end
|
||
|
|
||
|
path = {}
|
||
|
distance = 0
|
||
|
direction = "^"
|
||
|
while true do
|
||
|
next_pos = get_nextpos(pos, direction)
|
||
|
|
||
|
if map[next_pos.y] and map[next_pos.y][next_pos.x] == "#" then
|
||
|
distance = distance + 1
|
||
|
pos = next_pos
|
||
|
else
|
||
|
if distance ~= 0 then
|
||
|
table.insert(path, distance)
|
||
|
distance = 0
|
||
|
end
|
||
|
|
||
|
if direction == "^" then
|
||
|
dir_l = "<"
|
||
|
dir_r = ">"
|
||
|
elseif direction == ">" then
|
||
|
dir_l = "^"
|
||
|
dir_r = "v"
|
||
|
elseif direction == "v" then
|
||
|
dir_l = ">"
|
||
|
dir_r = "<"
|
||
|
elseif direction == "<" then
|
||
|
dir_l = "v"
|
||
|
dir_r = "^"
|
||
|
end
|
||
|
|
||
|
pos_l = get_nextpos(pos, dir_l)
|
||
|
pos_r = get_nextpos(pos, dir_r)
|
||
|
|
||
|
if map[pos_l.y] and map[pos_l.y][pos_l.x] == "#" then
|
||
|
table.insert(path, "L")
|
||
|
direction = dir_l
|
||
|
elseif map[pos_r.y] and map[pos_r.y][pos_r.x] == "#" then
|
||
|
table.insert(path, "R")
|
||
|
direction = dir_r
|
||
|
else
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
print(table.concat(path, ","))
|
||
|
print("Compress the path manually you lazy fuck")
|
||
|
|
||
|
function sleep(s)
|
||
|
local ntime = os.clock() + s
|
||
|
repeat until os.clock() >= ntime
|
||
|
end
|
||
|
|
||
|
-- Flushing doesn't work as expected... oh well
|
||
|
io.stdout:flush()
|
||
|
io.stdout:setvbuf("full", 0x10000)
|
||
|
|
||
|
program_p2 = {table.unpack(program)}
|
||
|
program_p2[1] = 2
|
||
|
last_output = 0
|
||
|
interpret({mem=program_p2, output=function(val)
|
||
|
if val >= 0x80 then
|
||
|
io.stdout:write(val)
|
||
|
io.stdout:write("\n")
|
||
|
else
|
||
|
if last_output == 10 and val == 10 then
|
||
|
io.stdout:flush()
|
||
|
sleep(0.1)
|
||
|
end
|
||
|
last_output = val
|
||
|
io.stdout:write(string.char(val))
|
||
|
end
|
||
|
end, input=function()
|
||
|
io.stdout:flush()
|
||
|
return string.byte(io.stdin:read(1))
|
||
|
end})
|