add day 10 (stinky)
This commit is contained in:
parent
01432b8e0f
commit
4b59c0f893
7 changed files with 394 additions and 0 deletions
215
23/elixir/lib/days/day10.ex
Normal file
215
23/elixir/lib/days/day10.ex
Normal file
|
@ -0,0 +1,215 @@
|
|||
defmodule AOC.Day10 do
|
||||
# use AOC.Day, day: 10, input: "example5"
|
||||
use AOC.Day, day: 10
|
||||
|
||||
def parse_input(lines) do
|
||||
pipe_map =
|
||||
lines
|
||||
|> Enum.with_index()
|
||||
|> Enum.flat_map(fn {row, y} ->
|
||||
row
|
||||
|> String.to_charlist()
|
||||
|> Enum.with_index()
|
||||
|> Enum.map(fn {tile, x} -> {{y, x}, tile} end)
|
||||
end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
connection_map =
|
||||
Enum.map(pipe_map, fn {coords, tile} ->
|
||||
connections =
|
||||
case tile do
|
||||
?| -> [:north, :south]
|
||||
?- -> [:east, :west]
|
||||
?L -> [:north, :east]
|
||||
?J -> [:north, :west]
|
||||
?7 -> [:south, :west]
|
||||
?F -> [:south, :east]
|
||||
?. -> []
|
||||
?S -> []
|
||||
end
|
||||
|
||||
{coords, connections}
|
||||
end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
{start_location, start_connections} = find_start_connections(pipe_map)
|
||||
|
||||
{pipe_map, connection_map, start_location, start_connections}
|
||||
end
|
||||
|
||||
def find_start_connections(pipe_map) do
|
||||
{start_y, start_x} =
|
||||
start_location =
|
||||
pipe_map
|
||||
|> Enum.find(&(elem(&1, 1) == ?S))
|
||||
|> elem(0)
|
||||
|
||||
start_connections =
|
||||
[
|
||||
{{start_y - 1, start_x}, ~c"|7F"},
|
||||
{{start_y, start_x + 1}, ~c"-J7"},
|
||||
{{start_y + 1, start_x}, ~c"|LJ"},
|
||||
{{start_y, start_x - 1}, ~c"-LF"}
|
||||
]
|
||||
|> Enum.filter(&Map.has_key?(pipe_map, elem(&1, 0)))
|
||||
|> Enum.filter(fn {coords, allowed_pipes} ->
|
||||
pipe = Map.fetch!(pipe_map, coords)
|
||||
Enum.member?(allowed_pipes, pipe)
|
||||
end)
|
||||
|> Enum.map(&elem(&1, 0))
|
||||
|
||||
{start_location, start_connections}
|
||||
end
|
||||
|
||||
def find_furthest_pipe(connection_map, start_location, start_connections) do
|
||||
:ets.insert(:pipe_distances, {start_location, 0})
|
||||
Enum.each(start_connections, &visit_pipe(connection_map, &1, 1))
|
||||
|
||||
:ets.tab2list(:pipe_distances)
|
||||
|> Enum.map(&elem(&1, 1))
|
||||
|> Enum.max()
|
||||
end
|
||||
|
||||
def visit_pipe(connection_map, {y, x} = location, step_count) do
|
||||
case Map.fetch(connection_map, location) do
|
||||
{:ok, directions} ->
|
||||
location_step_count =
|
||||
case :ets.lookup(:pipe_distances, location) do
|
||||
[{_, location_step_count}] -> location_step_count
|
||||
_ -> :infinity
|
||||
end
|
||||
|
||||
if step_count < location_step_count do
|
||||
:ets.insert(:pipe_distances, {location, step_count})
|
||||
|
||||
Enum.each(directions, fn
|
||||
:north -> visit_pipe(connection_map, {y - 1, x}, step_count + 1)
|
||||
:east -> visit_pipe(connection_map, {y, x + 1}, step_count + 1)
|
||||
:south -> visit_pipe(connection_map, {y + 1, x}, step_count + 1)
|
||||
:west -> visit_pipe(connection_map, {y, x - 1}, step_count + 1)
|
||||
end)
|
||||
end
|
||||
|
||||
:error ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def part1({_, connection_map, start_location, start_connections}) do
|
||||
:ets.new(:pipe_distances, [:set, :protected, :named_table])
|
||||
|
||||
find_furthest_pipe(connection_map, start_location, start_connections)
|
||||
end
|
||||
|
||||
def count_enclosed(pipe_map, connection_map, start_location, start_connections) do
|
||||
next_location = tl(start_connections) |> hd()
|
||||
# next_location = hd(start_connections)
|
||||
|
||||
count_enclosed(pipe_map, connection_map, start_location, start_location, next_location)
|
||||
end
|
||||
|
||||
def count_enclosed(
|
||||
pipe_map,
|
||||
connection_map,
|
||||
start_location,
|
||||
{prev_y, prev_x} = previous_location,
|
||||
{y, x} = current_location
|
||||
) do
|
||||
if current_location != start_location do
|
||||
directions = Map.fetch!(connection_map, current_location)
|
||||
|
||||
# Always take RIGHT hand side
|
||||
|
||||
if Enum.member?(directions, :east) and Enum.member?(directions, :west) do
|
||||
if prev_x < x do
|
||||
# We came from the east
|
||||
flood_fill_ground(pipe_map, start_location, {y + 1, x})
|
||||
else
|
||||
# We came from the west
|
||||
flood_fill_ground(pipe_map, start_location, {y - 1, x})
|
||||
end
|
||||
end
|
||||
|
||||
if Enum.member?(directions, :north) and Enum.member?(directions, :south) do
|
||||
if prev_y < y do
|
||||
# We came from the north
|
||||
flood_fill_ground(pipe_map, start_location, {y, x - 1})
|
||||
else
|
||||
# We came from the south
|
||||
flood_fill_ground(pipe_map, start_location, {y, x + 1})
|
||||
end
|
||||
end
|
||||
|
||||
if Enum.member?(directions, :north) and Enum.member?(directions, :east) and prev_y < y do
|
||||
flood_fill_ground(pipe_map, start_location, {y, x - 1})
|
||||
flood_fill_ground(pipe_map, start_location, {y + 1, x})
|
||||
end
|
||||
|
||||
if Enum.member?(directions, :east) and Enum.member?(directions, :south) and prev_x > x do
|
||||
flood_fill_ground(pipe_map, start_location, {y - 1, x})
|
||||
flood_fill_ground(pipe_map, start_location, {y, x - 1})
|
||||
end
|
||||
|
||||
if Enum.member?(directions, :south) and Enum.member?(directions, :west) and prev_y > y do
|
||||
flood_fill_ground(pipe_map, start_location, {y, x + 1})
|
||||
flood_fill_ground(pipe_map, start_location, {y - 1, x})
|
||||
end
|
||||
|
||||
if Enum.member?(directions, :west) and Enum.member?(directions, :north) and prev_x < x do
|
||||
flood_fill_ground(pipe_map, start_location, {y + 1, x})
|
||||
flood_fill_ground(pipe_map, start_location, {y, x + 1})
|
||||
end
|
||||
|
||||
next_location =
|
||||
Enum.map(directions, fn
|
||||
:north -> {y - 1, x}
|
||||
:east -> {y, x + 1}
|
||||
:south -> {y + 1, x}
|
||||
:west -> {y, x - 1}
|
||||
end)
|
||||
|> Enum.reject(&(&1 == previous_location))
|
||||
|> hd()
|
||||
|
||||
count_enclosed(pipe_map, connection_map, start_location, current_location, next_location)
|
||||
end
|
||||
end
|
||||
|
||||
def flood_fill_ground(pipe_map, start_location, {y, x} = location) do
|
||||
if location != start_location do
|
||||
case Map.fetch(pipe_map, location) do
|
||||
{:ok, _} ->
|
||||
case :ets.lookup(:pipe_distances, location) do
|
||||
[] ->
|
||||
case :ets.lookup(:enclosed_pipes, location) do
|
||||
[] ->
|
||||
:ets.insert(:enclosed_pipes, {location, 1})
|
||||
|
||||
[{y - 1, x}, {y, x + 1}, {y + 1, x}, {y, x - 1}]
|
||||
|> Enum.each(&flood_fill_ground(pipe_map, start_location, &1))
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def part2({pipe_map, connection_map, start_location, start_connections}) do
|
||||
:ets.new(:enclosed_pipes, [:set, :protected, :named_table])
|
||||
|
||||
count_enclosed(pipe_map, connection_map, start_location, start_connections)
|
||||
|
||||
:ets.tab2list(:enclosed_pipes)
|
||||
|> Enum.count()
|
||||
|> IO.inspect()
|
||||
|
||||
"TODO"
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue