diff --git a/day15/part1.lua b/day15/part1.lua new file mode 100755 index 0000000..c743a56 --- /dev/null +++ b/day15/part1.lua @@ -0,0 +1,47 @@ +#!/usr/bin/env luajit +require("utils") +require("pqueue") + +local grid = {} +for line in io.lines(arg[3]) do + local row = {} + for char in chars(line) do + table.insert(row, tonumber(char)) + end + table.insert(grid, row) +end + +function printgrid() + for r, row in pairs(grid) do + for c, cell in pairs(row) do + io.write(string.format("%3d", cell)) + end + io.write('\n') + end +end + +local pq = pqueue(function(a, b) + return a[3] < b[3] +end) + +local distances = {} + +local H = math.huge +local n = { 1, 1, 0 } +while n ~= nil and (distances[#grid] == nil or distances[#grid][#grid[1]] == nil) do + local r, c, d = unpack(n) + if 0 < r or r <= #grid or 0 < c or c <= #grid[r] then + local row = distances[r] or {} + if d < (row[c] or H) then + row[c] = d + distances[r] = row + pq:add({ r-1, c, d + ((grid[r-1] or {})[c] or H) }) + pq:add({ r, c-1, d + ((grid[r] or {})[c-1] or H) }) + pq:add({ r+1, c, d + ((grid[r+1] or {})[c] or H) }) + pq:add({ r, c+1, d + ((grid[r] or {})[c+1] or H) }) + end + end + n = pq:pop() +end + +print(distances[#grid] and distances[#grid][#grid[1]]) diff --git a/day15/part2.lua b/day15/part2.lua new file mode 100755 index 0000000..ccec019 --- /dev/null +++ b/day15/part2.lua @@ -0,0 +1,60 @@ +#!/usr/bin/env luajit +require("utils") +require("pqueue") + +local grid = {} +for line in io.lines(arg[3]) do + local row = {} + for char in chars(line) do + table.insert(row, tonumber(char)) + end + table.insert(grid, row) +end + +function printgrid() + for r, row in pairs(grid) do + for c, cell in pairs(row) do + io.write(string.format("%3d", cell)) + end + io.write('\n') + end +end + +local h, w = #grid, #grid[1] +for r0 = 0, 4 do + for c0 = 0, 4 do + for r = 1, h do + for c = 1, w do + local row = grid[r0*h + r] or {} + row[c0*w + c] = (grid[r][c] + r0 + c0 - 1) % 9 + 1 + grid[r0*h + r] = row + end + end + end +end + +local pq = pqueue(function(a, b) + return a[3] < b[3] +end) + +local distances = {} + +local H = math.huge +local n = { 1, 1, 0 } +while n ~= nil and (distances[#grid] == nil or distances[#grid][#grid[1]] == nil) do + local r, c, d = unpack(n) + if 0 < r or r <= #grid or 0 < c or c <= #grid[r] then + local row = distances[r] or {} + if d < (row[c] or H) then + row[c] = d + distances[r] = row + pq:add({ r-1, c, d + ((grid[r-1] or {})[c] or H) }) + pq:add({ r, c-1, d + ((grid[r] or {})[c-1] or H) }) + pq:add({ r+1, c, d + ((grid[r+1] or {})[c] or H) }) + pq:add({ r, c+1, d + ((grid[r] or {})[c+1] or H) }) + end + end + n = pq:pop() +end + +print(distances[#grid] and distances[#grid][#grid[1]]) diff --git a/pqueue.lua b/pqueue.lua new file mode 100644 index 0000000..674a7eb --- /dev/null +++ b/pqueue.lua @@ -0,0 +1,49 @@ +local function add(self, item) + table.insert(self.items, item) + local i, p = #self.items + local p = math.floor(i / 2) + while i > 1 and self.smaller(self.items[i], self.items[p]) do + self.items[p], self.items[i] = self.items[i], self.items[p] + i, p = p, math.floor(p / 2) + end +end + +local function pop(self) + local item = self.items[1] + self.items[1] = self.items[#self.items] + table.remove(self.items) + local i = 1 + while i * 2 <= #self.items do + if i * 2 + 1 <= #self.items then + if self.smaller(self.items[i*2], self.items[i]) + or self.smaller(self.items[i*2+1], self.items[i]) then + if self.smaller(self.items[i*2], self.items[i*2+1]) then + self.items[i], self.items[i*2], i + = self.items[i * 2], self.items[i], i * 2 + else + self.items[i], self.items[i*2+1], i + = self.items[i*2+1], self.items[i], i * 2 + 1 + end + else + break + end + else + if self.smaller(self.items[i*2], self.items[i]) then + self.items[i], self.items[i * 2] + = self.items[i * 2], self.items[i] + end + i = i * 2 + end + end + return item +end + +function pqueue(smaller) + return { + items = {}, + smaller = smaller + or function(a, b) return a < b end, + add = add, + pop = pop, + } +end diff --git a/utils.lua b/utils.lua index 1836650..9734e6f 100644 --- a/utils.lua +++ b/utils.lua @@ -24,11 +24,20 @@ function foreach(t, f) end end -function printtable(t) +function printtable(t, nonewline) for k, v in pairs(t) do - io.write(k..":"..v.." ") + io.write(k..":") + if type(v) == "table" then + io.write("(") + printtable(v, true) + io.write(") ") + else + io.write(v.." ") + end + end + if not nonewline then + io.write("\n") end - io.write("\n") end function count(t, pred)