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.
244 lines
6.6 KiB
244 lines
6.6 KiB
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)
|
|
|