-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a611472
commit 49becb7
Showing
3 changed files
with
149 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) |