Skip to content

Commit

Permalink
Day 18, Part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeladler committed Dec 19, 2024
1 parent a611472 commit 49becb7
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 0 deletions.
104 changes: 104 additions & 0 deletions src/day18/day18.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
-- Author: Michael Adler
local M = {}

local Point2D = require("aoc_helper.point").Point2D
local north, south, east, west = Point2D:new(0, -1), Point2D:new(0, 1), Point2D:new(1, 0), Point2D:new(-1, 0)

local function build_map(points, map_size, iterations)
local map = {}
for y = 0, map_size do
map[y] = {}
for x = 0, map_size do
map[y][x] = "."
end
end
for i = 1, iterations do
local p = points[i]
map[p.y][p.x] = "#"
end
return map
end

local function shortest_path(points, map_size, iterations)
local map = build_map(points, map_size, iterations)
local neighbors = function(current)
local result = {}
for _, dir in ipairs({ north, east, south, west }) do
local candidate = current + dir
local row = map[candidate.y]
if row and row[candidate.x] == "." then
table.insert(result, { node = candidate, weight = 1 })
end
end
return result
end
-- for y = 0, map_size do
-- for x = 0, map_size do
-- io.stdout:write(map[y][x])
-- end
-- print()
-- end

--- Dijkstra's algorithm
local distances = {}
-- local previous = {}
local queue = {}

-- Initialize distances and previous nodes
for y = 0, map_size do
for x = 0, map_size do
local p = Point2D:new(x, y)
local p_hash = p:hash()
distances[p_hash] = math.huge
-- previous[p_hash] = nil
end
end
local start = Point2D:new(0, 0)
distances[start:hash()] = 0

-- Create priority queue
table.insert(queue, { node = start, distance = 0 })

while queue[1] do
-- Extract node with minimum distance from queue
table.sort(queue, function(a, b)
return a.distance < b.distance
end)
local current = table.remove(queue, 1)

-- Update distances and previous nodes for neighbors
for _, nb in ipairs(neighbors(current.node)) do
local neighbor, weight = nb.node, nb.weight
local alt = current.distance + weight
local neighbor_hash = neighbor:hash()
if alt < distances[neighbor_hash] then
distances[neighbor_hash] = alt
-- previous[neighbor_hash] = current
table.insert(queue, { node = neighbor, distance = alt })
end
end
end

local destination = Point2D:new(map_size, map_size)
return distances[destination:hash()]
end
M.shortest_path = shortest_path

local function parse(input)
local points = {}
for line in input:gmatch("[^\r\n]+") do
local x, y = line:match("(%d+),(%d+)")
table.insert(points, Point2D:new(assert(tonumber(x)), assert(tonumber(y))))
end
return points
end
M.parse = parse

--- @param input string
M.solve = function(input)
local points = parse(input)
local part1 = shortest_path(points, 70, 1024)
return part1, 0
end

return M
37 changes: 37 additions & 0 deletions src/day18/day18_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
local day18 = require("day18")

describe("day18", function()
describe("example 1", function()
local input = [[5,4
4,2
4,5
3,0
2,1
6,3
2,4
1,5
0,6
3,3
2,6
5,1
1,2
5,5
2,5
6,5
1,4
0,4
6,4
1,1
6,1
1,0
0,5
1,6
2,0
]]
local points = day18.parse(input)
local part1 = day18.shortest_path(points, 6, 12)
it("part1", function()
assert.are.equal(22, part1)
end)
end)
end)
8 changes: 8 additions & 0 deletions src/day18/main.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env luajit
local day18 = require("day18")
local fname = arg[1] or "input.txt"
local f = assert(io.open(fname, "r"), fname .. " missing")
local input = f:read("*a")
f:close()
local part1, part2 = day18.solve(input)
print(string.format("Part 1: %d\nPart 2: %d", part1, part2))

0 comments on commit 49becb7

Please sign in to comment.