mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Only need to check whether the current program is blocked, since the other will have switched if it was going to block.
161 lines
3.3 KiB
Lua
Executable File
161 lines
3.3 KiB
Lua
Executable File
#!/usr/bin/env lua
|
|
|
|
function split(input, match)
|
|
-- Stolen from stack overflow.
|
|
-- Why doesn't lua have string split?
|
|
local i = 1; t = {}
|
|
|
|
for str in string.gmatch(input, match) do
|
|
t[i] = str
|
|
i = i + 1
|
|
end
|
|
|
|
return t
|
|
end
|
|
|
|
instructions = {}
|
|
icount = 0
|
|
|
|
while true do
|
|
line = io.read()
|
|
|
|
if line == nil then break end
|
|
|
|
instructions[icount] = split(line, "%S+")
|
|
icount = icount + 1
|
|
end
|
|
|
|
registers = {}
|
|
|
|
function argval(input)
|
|
if tonumber(input) ~= nil then
|
|
return tonumber(input)
|
|
elseif registers[input] ~= nil then
|
|
return registers[input]
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
iptr = 0
|
|
|
|
while true do
|
|
instr = instructions[iptr]
|
|
|
|
if instr[1] == "set" then
|
|
registers[instr[2]] = argval(instr[3])
|
|
elseif instr[1] == "snd" then
|
|
last_played = argval(instr[2])
|
|
elseif instr[1] == "add" then
|
|
registers[instr[2]] = argval(instr[2]) + argval(instr[3])
|
|
elseif instr[1] == "mul" then
|
|
registers[instr[2]] = argval(instr[2]) * argval(instr[3])
|
|
elseif instr[1] == "mod" then
|
|
registers[instr[2]] = argval(instr[2]) % argval(instr[3])
|
|
elseif instr[1] == "rcv" then
|
|
print("Last played", last_played)
|
|
break
|
|
elseif instr[1] == "jgz" then
|
|
if argval(instr[2]) > 0 then
|
|
iptr = iptr + argval(instr[3]) - 1 -- correct for the subsequent add
|
|
end
|
|
else
|
|
print("Illegal instruction", instr[1])
|
|
break
|
|
end
|
|
|
|
iptr = iptr + 1
|
|
end
|
|
|
|
registers = {}
|
|
registers[0] = {}
|
|
registers[1] = {}
|
|
|
|
function argval(input, pid)
|
|
if tonumber(input) ~= nil then
|
|
return tonumber(input)
|
|
elseif registers[pid][input] ~= nil then
|
|
return registers[pid][input]
|
|
else
|
|
return pid
|
|
end
|
|
end
|
|
|
|
-- Double instruction pointer
|
|
iptr = {}
|
|
iptr[0] = 0
|
|
iptr[1] = 0
|
|
-- Double receive buffer
|
|
rbuf = {}
|
|
rbuf[0] = {}
|
|
rbuf[1] = {}
|
|
-- Pointer in the receive buffer
|
|
rptr = {}
|
|
rptr[0] = 0
|
|
rptr[1] = 0
|
|
-- Number of entries in each buffer
|
|
rctr = {}
|
|
rctr[0] = 0
|
|
rctr[1] = 0
|
|
-- Whether one thread is waiting
|
|
waiting = {}
|
|
waiting[0] = false
|
|
waiting[1] = false
|
|
|
|
sends = 0
|
|
|
|
pid = 0
|
|
|
|
function nextpid(pid)
|
|
if pid == 0 then
|
|
return 1
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
while true do
|
|
instr = instructions[iptr[pid]]
|
|
|
|
if waiting[pid] then
|
|
print("Deadlocked!")
|
|
break
|
|
end
|
|
|
|
if instr[1] == "set" then
|
|
registers[pid][instr[2]] = argval(instr[3], pid)
|
|
elseif instr[1] == "snd" then
|
|
rbuf[nextpid(pid)][rctr[nextpid(pid)]] = argval(instr[2], pid)
|
|
rctr[nextpid(pid)] = rctr[nextpid(pid)] + 1
|
|
elseif instr[1] == "add" then
|
|
registers[pid][instr[2]] = argval(instr[2], pid) + argval(instr[3], pid)
|
|
elseif instr[1] == "mul" then
|
|
registers[pid][instr[2]] = argval(instr[2], pid) * argval(instr[3], pid)
|
|
elseif instr[1] == "mod" then
|
|
registers[pid][instr[2]] = argval(instr[2], pid) % argval(instr[3], pid)
|
|
elseif instr[1] == "rcv" then
|
|
if rbuf[pid][rptr[pid]] ~= nil then
|
|
-- Have value, read and continue
|
|
registers[pid][instr[2]] = rbuf[pid][rptr[pid]]
|
|
rptr[pid] = rptr[pid] + 1
|
|
waiting[nextpid(pid)] = false
|
|
else
|
|
-- Need to wait for value, continue with execution of the other
|
|
waiting[pid] = true
|
|
pid = nextpid(pid)
|
|
iptr[pid] = iptr[pid] - 1 -- Correct for subsequent increase
|
|
end
|
|
elseif instr[1] == "jgz" then
|
|
if argval(instr[2], pid) > 0 then
|
|
iptr[pid] = iptr[pid] + argval(instr[3], pid) - 1 -- correct for the subsequent add
|
|
end
|
|
else
|
|
print("Illegal instruction", instr[1])
|
|
break
|
|
end
|
|
|
|
iptr[pid] = iptr[pid] + 1
|
|
end
|
|
|
|
print("Final sends from 1:", rctr[0])
|