Day 18. Going to come back to day 17... maybe
parent
70c7c79757
commit
697feb3c14
@ -0,0 +1,149 @@
|
||||
defmodule Day18 do
|
||||
def run do
|
||||
map_list =
|
||||
File.read!("data.txt")
|
||||
|> String.trim()
|
||||
|> String.split("\n")
|
||||
|> Enum.map(fn line -> String.split(line, ",") |> Enum.map(&String.to_integer/1) end)
|
||||
|
||||
height = 71
|
||||
width = 71
|
||||
|
||||
map_list1 = Enum.take(map_list, 1024)
|
||||
|
||||
map1 =
|
||||
Enum.reduce(0..(height - 1), %{}, fn row, acc ->
|
||||
Enum.reduce(0..(width - 1), acc, fn col, acc2 ->
|
||||
char = if Enum.member?(map_list1, [col, row]), do: :wall, else: :empty
|
||||
Map.put(acc2, {col, row}, char)
|
||||
end)
|
||||
end)
|
||||
|
||||
start = {0, 0}
|
||||
dest = {width - 1, height - 1}
|
||||
|
||||
# create a map of visited nodes an a queue
|
||||
visited = %{start => 100_000_000}
|
||||
q = :queue.from_list([{start, 0, [{0, 0}]}])
|
||||
|
||||
{_path, shortest} = walk(map1, q, dest, visited, [], 100_000_000_000, width, height)
|
||||
dbg(shortest)
|
||||
|
||||
part2 =
|
||||
Enum.reduce(1024..length(map_list), nil, fn idx, acc ->
|
||||
dbg(idx)
|
||||
|
||||
if !is_nil(acc) do
|
||||
# exit early, we already found the coord
|
||||
acc
|
||||
else
|
||||
# take the first N coords
|
||||
map_list = Enum.take(map_list, idx)
|
||||
|
||||
# generate a new map with that many blocks fallen
|
||||
map =
|
||||
Enum.reduce(0..(height - 1), %{}, fn row, acc ->
|
||||
Enum.reduce(0..(width - 1), acc, fn col, acc2 ->
|
||||
char = if Enum.member?(map_list, [col, row]), do: :wall, else: :empty
|
||||
Map.put(acc2, {col, row}, char)
|
||||
end)
|
||||
end)
|
||||
|
||||
start = {0, 0}
|
||||
dest = {width - 1, height - 1}
|
||||
|
||||
# create a map of visited nodes an a queue
|
||||
visited = %{start => 100_000_000}
|
||||
q = :queue.from_list([{start, 0, [{0, 0}]}])
|
||||
|
||||
res = walk(map, q, dest, visited, [], 100_000_000_000, width, height)
|
||||
dbg(res)
|
||||
|
||||
if is_nil(res) do
|
||||
List.last(map_list)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
dbg(part2)
|
||||
end
|
||||
|
||||
defp walk(map, q, {dx, dy} = dest, visited, paths, shortest_path, width, height) do
|
||||
# dequeue the node with the lowest distnce
|
||||
# no priority queue, so just find the lowest one and delete it from the queue
|
||||
ql = :queue.to_list(q)
|
||||
|
||||
if length(ql) == 0 do
|
||||
nil
|
||||
else
|
||||
lowest = Enum.min_by(ql, fn {_, dist, _} -> dist end)
|
||||
{{x, y}, dist, path} = lowest
|
||||
new_q = :queue.delete(lowest, q)
|
||||
|
||||
# if we reached the destination
|
||||
if x == dx and y == dy do
|
||||
{path, dist}
|
||||
else
|
||||
dirs = [{1, 0}, {0, 1}, {-1, 0}, {0, -1}]
|
||||
|
||||
# find neighbors to enqueue
|
||||
neighbors =
|
||||
dirs
|
||||
|> Enum.map(fn {dx, dy} -> {x + dx, y + dy} end)
|
||||
|> Enum.map(fn key -> {key, Map.get(map, key, :empty)} end)
|
||||
|> Enum.filter(fn {{x, y}, el} ->
|
||||
el != :wall and x >= 0 and y >= 0 and x < width and y < height
|
||||
end)
|
||||
|> Enum.reject(fn {{nx, ny}, _el} -> Map.has_key?(visited, {nx, ny}) end)
|
||||
|> Enum.reject(fn {{nx, ny}, _el} ->
|
||||
Enum.any?(:queue.to_list(q), fn {pos, _, _} -> pos == {nx, ny} end)
|
||||
end)
|
||||
|> Enum.map(fn {key, _el} -> key end)
|
||||
|
||||
new_q2 =
|
||||
Enum.reduce(neighbors, new_q, fn {nx, ny}, acc ->
|
||||
:queue.in({{nx, ny}, dist + 1, [{x, y} | path]}, acc)
|
||||
end)
|
||||
|
||||
new_visited = Map.put(visited, {x, y}, dist)
|
||||
walk(map, new_q2, dest, new_visited, paths, shortest_path, width, height)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp render(map, location \\ nil, visited \\ %{}) do
|
||||
width = Map.keys(map) |> Enum.map(&elem(&1, 1)) |> Enum.max()
|
||||
height = Map.keys(map) |> Enum.map(&elem(&1, 0)) |> Enum.max()
|
||||
|
||||
Enum.each(0..height, fn row ->
|
||||
Enum.each(0..width, fn col ->
|
||||
el = if Map.get(map, {col, row}, :wall) == :wall, do: "#", else: "."
|
||||
|
||||
visited? = Map.has_key?(visited, {col, row})
|
||||
|
||||
formatted =
|
||||
if location == {col, row} do
|
||||
IO.ANSI.format([:red_background, "@"])
|
||||
else
|
||||
if visited? do
|
||||
IO.ANSI.format([:blue_background, el])
|
||||
else
|
||||
el
|
||||
end
|
||||
end
|
||||
|
||||
IO.write(formatted)
|
||||
end)
|
||||
|
||||
IO.write("\n")
|
||||
end)
|
||||
|
||||
IO.write("\n")
|
||||
|
||||
map
|
||||
end
|
||||
end
|
||||
|
||||
Day18.run()
|
Loading…
Reference in New Issue