From c294af6f1de621199c9d069d92679ef7a9f8aaa0 Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Mon, 18 Dec 2017 13:23:56 +0100 Subject: [PATCH] Implement day 18 in Lua. --- 2017/README.md | 1 + 2017/day-18/input.txt | 41 ++++++++++ 2017/day-18/solution.lua | 160 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 2017/day-18/input.txt create mode 100755 2017/day-18/solution.lua diff --git a/2017/README.md b/2017/README.md index dc0209c..fe20231 100644 --- a/2017/README.md +++ b/2017/README.md @@ -19,6 +19,7 @@ The current plan, in no particular order: - [ ] Java - [x] Kotlin - [Day 10](./day-10/solution.kt) - [x] Lex - [Day 09](./day-09/solution.l) +- [x] Lua - [Day 18](./day-18/solution.lua) - [x] Matlab - [Day 06](./day-06) - [x] Node.js - [Day 12](./day-12/solution.js) - [ ] Objective C diff --git a/2017/day-18/input.txt b/2017/day-18/input.txt new file mode 100644 index 0000000..8b74206 --- /dev/null +++ b/2017/day-18/input.txt @@ -0,0 +1,41 @@ +set i 31 +set a 1 +mul p 17 +jgz p p +mul a 2 +add i -1 +jgz i -2 +add a -1 +set i 127 +set p 735 +mul p 8505 +mod p a +mul p 129749 +add p 12345 +mod p a +set b p +mod b 10000 +snd b +add i -1 +jgz i -9 +jgz a 3 +rcv b +jgz b -1 +set f 0 +set i 126 +rcv a +rcv b +set p a +mul p -1 +add p b +jgz p 4 +snd a +set a b +jgz 1 3 +snd b +set f 1 +add i -1 +jgz i -11 +snd a +jgz f -16 +jgz a -19 diff --git a/2017/day-18/solution.lua b/2017/day-18/solution.lua new file mode 100755 index 0000000..8ee8b90 --- /dev/null +++ b/2017/day-18/solution.lua @@ -0,0 +1,160 @@ +#!/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[0] and waiting[1] 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])