Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require("utils")
- local intcode = getinput()
- local function Process(intcode, inputs)
- local memory = parsecommas(intcode, tonumber)
- memory[0] = table.remove(memory, 1)
- setmetatable(memory, {
- __index = function(t, k)
- rawset(t, k, 0)
- return 0
- end;
- })
- local self = {
- memory = memory;
- ip = 0; -- instruction pointer
- inputs = inputs or {}; -- input queue
- halted = false;
- relativeBase = 0;
- }
- self.thread = coroutine.create(function()
- local operations = {
- [1]={3, true, function(a, b) return a + b end};
- [2]={3, true, function(a, b) return a * b end};
- [3]={1, true, function() if #self.inputs > 0 then return table.remove(self.inputs, 1) end return self.getinput() end};
- [4]={1, false, function(x) coroutine.yield(x) end};
- [5]={2, false, function(a, b) if a ~= 0 then self.ip = b end end};
- [6]={2, false, function(a, b) if a == 0 then self.ip = b end end};
- [7]={3, true, function(a, b) return a < b and 1 or 0 end};
- [8]={3, true, function(a, b) return a == b and 1 or 0 end};
- [9]={1, false, function(x) self.relativeBase = self.relativeBase + x end};
- [99]={0, false, function() self.halted = true end}
- }
- while true do
- local memory = self.memory
- local opcode = memory[self.ip]%100
- local operation = operations[opcode]
- local paramCount = operation[1]
- local writes = operation[2]
- local args = {}
- for i = 1, paramCount do
- local mode = memory[self.ip]//10^(i+1)%10
- local value = mode == 1 and (self.ip + i) or memory[self.ip + i]
- if mode == 2 then value = value + self.relativeBase end
- args[i] = (writes and i == paramCount) and value or memory[value]
- end
- local lastip = self.ip
- local result = operation[3](table.unpack(args))
- if self.halted then break end
- if writes then -- writes to
- memory[args[#args]] = result
- end
- if lastip == self.ip then -- didn't jump
- self.ip = self.ip + paramCount + 1
- end
- end
- return "halted"
- end)
- function self:resume()
- return ({coroutine.resume(self.thread)})[2]
- end
- function self:input(value)
- table.insert(self.inputs, value)
- end
- function self:copy()
- local new = Process(intcode, {table.unpack(self.inputs)})
- new.ip = self.ip
- new.halted = self.halted
- new.relativeBase = self.relativeBase
- new.memory = {}
- for k, v in pairs(self.memory) do
- new.memory[k] = v
- end
- if self.memory[self.ip]%100 == 4 then
- new.ip = new.ip + 2
- end
- return new
- end
- return self
- end
- local visited = {}
- local dir = {{0,1},{0,-1},{1,0},{-1,0}}
- local opposite = {2,1,4,3}
- local paths = {}
- for i = 1, 4 do
- paths[i] = {length = 1, x = dir[i][1], y = dir[i][2], process = Process(intcode, {i}), backwards = opposite[i]}
- end
- local longest = 0
- local part2started = false
- while paths[1] do
- local new = {}
- for _, path in pairs(paths) do
- local x, y = path.x, path.y
- local s = x..","..y
- if not visited[s] then
- visited[s] = true
- local status = path.process:resume()
- if status ~= 0 then
- longest = math.max(longest, path.length)
- for i = 1, 4 do
- if i ~= path.backwards then
- local copy = path.process:copy()
- copy:input(i)
- new[#new+1] = {length = path.length + 1, x = path.x + dir[i][1], y = path.y + dir[i][2], process = copy, backwards = opposite[i]}
- end
- end
- end
- if status == 2 then
- if not part2started then
- print("minumum length: "..path.length)
- part2started = true
- visited = {}
- new = {}
- for i = 1, 4 do
- local copy = path.process:copy()
- copy:input(i)
- new[i] = {length = 1, x = x+dir[i][1], y = y+dir[i][2], process = copy, backwards = opposite[i]}
- end
- break
- end
- end
- end
- end
- paths = new
- end
- print("longest: "..longest)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement