Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Advent of Code 2023 - Day 10

2023/10.livemd

Advent of Code 2023 - Day 10

Mix.install([
  {:kino, "~> 0.11.0"},
  {:kino_aoc, github: "ljgago/kino_aoc"},
  {:libgraph, "~> 0.16.0"},
  {:topo, "~> 1.0"}
])

Input

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2023", "10", System.fetch_env!("LB_AOC_SESSION"))
tiles =
  puzzle_input
  |> String.split("\n", trim: true)
  |> Enum.map(&String.split(&1, "", trim: true))
grid =
  for {row, y} <- Enum.with_index(tiles),
      {tile, x} <- Enum.with_index(row),
      into: %{},
      do: {{x, y}, tile}
{start, _} = Enum.find(grid, fn {_, tile} -> tile == "S" end)
n = fn {x, y} -> {x, y - 1} end
e = fn {x, y} -> {x + 1, y} end
s = fn {x, y} -> {x, y + 1} end
w = fn {x, y} -> {x - 1, y} end

adjacents = fn
  _p, "." -> []
  _p, "S" -> []
  p, "|" -> [n.(p), s.(p)]
  p, "-" -> [w.(p), e.(p)]
  p, "L" -> [n.(p), e.(p)]
  p, "J" -> [n.(p), w.(p)]
  p, "7" -> [w.(p), s.(p)]
  p, "F" -> [e.(p), s.(p)]
end

graph =
  for {{x, y}, tile} <- grid, reduce: Graph.new() do
    acc ->
      adjacents.({x, y}, tile)
      |> Enum.reduce(acc, fn a, acc -> Graph.add_edge(acc, {x, y}, a) end)
  end
loop =
  graph
  |> Graph.in_neighbors(start)
  |> Enum.reduce(graph, fn n, g ->
    Graph.add_edge(g, start, n)
  end)
  |> Graph.reachable_neighbors([start])

Part 1

length(loop) |> div(2)

Part 2

geoloop = %Geo.Polygon{coordinates: [loop]}

grid
|> Map.keys()
|> Stream.reject(&amp;(&amp;1 in loop))
|> Stream.map(&amp;Topo.contains?(geoloop, &amp;1))
|> Enum.count(&amp; &amp;1)

Run in Livebook