diff --git a/day16/part1.lua b/day16/part1.lua new file mode 100755 index 0000000..bfeb227 --- /dev/null +++ b/day16/part1.lua @@ -0,0 +1,84 @@ +#!/usr/bin/env luajit +require("utils") + +local hex = io.open(arg[3]):read("*a") +--local hex = "8A004A801A8002F478" +local hexmap = { + ["0"] = "0000", ["1"] = "0001", ["2"] = "0010", ["3"] = "0011", + ["4"] = "0100", ["5"] = "0101", ["6"] = "0110", ["7"] = "0111", + ["8"] = "1000", ["9"] = "1001", ["A"] = "1010", ["B"] = "1011", + ["C"] = "1100", ["D"] = "1101", ["E"] = "1110", ["F"] = "1111", +} + +local bytes = {} +for char in chars(hex) do + if hexmap[char] then table.insert(bytes, hexmap[char]) end +end + +local bitstring = table.concat(bytes) + +local function literal(bitstring) + local v = 0 + while char(bitstring, 1) == "1" do + v = v * 16 + bin2dec(bitstring:sub(2, 5)) + bitstring = bitstring:sub(6) + end + v = v * 16 + bin2dec(bitstring:sub(2, 5)) + return v, bitstring:sub(6) +end + +local function countoperator(bitstring) + local count = bin2dec(bitstring:sub(1, 11)) + bitstring = bitstring:sub(12) + local p, packets = nil, {} + for i = 1, count do + p, bitstring = packet(bitstring) + table.insert(packets, p) + end + return packets, bitstring +end + +local function lengthoperator(bitstring) + local length = bin2dec(bitstring:sub(1, 15)) + bitstring = bitstring:sub(16) + local target = #bitstring - length + local p, packets = nil, {} + while #bitstring > target do + p, bitstring = packet(bitstring) + table.insert(packets, p) + end + return packets, bitstring +end + +local function operator(bitstring) + if char(bitstring, 1) == "1" then + return countoperator(bitstring:sub(2)) + else + return lengthoperator(bitstring:sub(2)) + end +end + +function packet(bitstring) + local version = bin2dec(bitstring:sub(1, 3)) + local pactype = bin2dec(bitstring:sub(4, 6)) + local content + if pactype == 4 + then content, bitstring = literal(bitstring:sub(7)) + else content, bitstring = operator(bitstring:sub(7)) + end + return { version = version, pactype = pactype, content = content }, bitstring +end + +function sumversions(packet) + if packet.pactype == 4 then + return packet.version + else + local sum = packet.version + for i, p in pairs(packet.content) do + sum = sum + sumversions(p) + end + return sum + end +end + +print(sumversions(packet(bitstring))) diff --git a/day16/part2.lua b/day16/part2.lua new file mode 100755 index 0000000..2f67f92 --- /dev/null +++ b/day16/part2.lua @@ -0,0 +1,119 @@ +#!/usr/bin/env luajit +require("utils") + +local hex = io.open(arg[3]):read("*a") +--local hex = "8A004A801A8002F478" +local hexmap = { + ["0"] = "0000", ["1"] = "0001", ["2"] = "0010", ["3"] = "0011", + ["4"] = "0100", ["5"] = "0101", ["6"] = "0110", ["7"] = "0111", + ["8"] = "1000", ["9"] = "1001", ["A"] = "1010", ["B"] = "1011", + ["C"] = "1100", ["D"] = "1101", ["E"] = "1110", ["F"] = "1111", +} + +local bytes = {} +for char in chars(hex) do + if hexmap[char] then table.insert(bytes, hexmap[char]) end +end + +local bitstring = table.concat(bytes) + +local function literal(bitstring) + local v = 0 + while char(bitstring, 1) == "1" do + v = v * 16 + bin2dec(bitstring:sub(2, 5)) + bitstring = bitstring:sub(6) + end + v = v * 16 + bin2dec(bitstring:sub(2, 5)) + return v, bitstring:sub(6) +end + +local function countoperator(bitstring) + local count = bin2dec(bitstring:sub(1, 11)) + bitstring = bitstring:sub(12) + local p, packets = nil, {} + for i = 1, count do + p, bitstring = packet(bitstring) + table.insert(packets, p) + end + return packets, bitstring +end + +local function lengthoperator(bitstring) + local length = bin2dec(bitstring:sub(1, 15)) + bitstring = bitstring:sub(16) + local target = #bitstring - length + local p, packets = nil, {} + while #bitstring > target do + p, bitstring = packet(bitstring) + table.insert(packets, p) + end + return packets, bitstring +end + +local function operator(bitstring) + if char(bitstring, 1) == "1" then + return countoperator(bitstring:sub(2)) + else + return lengthoperator(bitstring:sub(2)) + end +end + +function packet(bitstring) + local version = bin2dec(bitstring:sub(1, 3)) + local pactype = bin2dec(bitstring:sub(4, 6)) + local content + if pactype == 4 then + content, bitstring = literal(bitstring:sub(7)) + else + content, bitstring = operator(bitstring:sub(7)) + end + return { version = version, pactype = pactype, content = content }, bitstring +end + +local function intop(p, binop) + local acc = evaluate(p.content[1]) + for i = 2, #p.content do + acc = binop(acc, evaluate(p.content[i])) + end + return acc +end + +local function boolop(p, binop) + if binop(evaluate(p.content[1]), evaluate(p.content[2])) + then return 1 + else return 0 + end +end + +local typemap = { + [0] = function(p) + return intop(p, function(a, b) return a + b end) + end, + [1] = function(p) + return intop(p, function(a, b) return a * b end) + end, + [2] = function(p) + return intop(p, math.min) + end, + [3] = function(p) + return intop(p, math.max) + end, + [4] = function(p) + return p.content + end, + [5] = function(p) + return boolop(p, function(a, b) return a > b end) + end, + [6] = function(p) + return boolop(p, function(a, b) return a < b end) + end, + [7] = function(p) + return boolop(p, function(a, b) return a == b end) + end, +} + +function evaluate(packet) + return typemap[packet.pactype](packet) +end + +print(evaluate(packet(bitstring))) diff --git a/utils.lua b/utils.lua index 9734e6f..1f06235 100644 --- a/utils.lua +++ b/utils.lua @@ -74,3 +74,13 @@ function chars(s) end end end + +function bin2dec(str) + local v = 0 + for c in chars(str) do + v = v * 2 + if c == "1" then v = v + 1 end + end + return v +end +