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

Advent of Code 2021 day 12

2021/priv/day-12.livemd

Advent of Code 2021 day 12

Setup

Mix.install([
  {:kino, "~> 0.4.1"}
])
input = Kino.Input.textarea("Paste your input here:")
edges =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.reduce(%{}, fn line, acc ->
    [left, right] = String.split(line, "-")
    acc = Map.update(acc, left, [right], &[right | &1])

    if left == "start" or right == "end" do
      acc
    else
      Map.update(acc, right, [left], &[left | &1])
    end
  end)

Part 1

defmodule Day12 do
  def walk(edges) do
    walk(edges["start"], ["start"], edges, MapSet.new(), [])
  end

  defp walk(["end" | caves], walked, edges, seen, pathes) do
    valid_path = Enum.reverse(["end" | walked]) |> Enum.join("-")
    walk(caves, walked, edges, seen, [valid_path | pathes])
  end

  defp walk([cave | caves], walked, edges, seen, pathes) do
    pathes =
      cond do
        cave == "start" or cave in seen ->
          pathes

        lowercased?(cave) ->
          walk(edges[cave], [cave | walked], edges, MapSet.put(seen, cave), pathes)

        true ->
          walk(edges[cave], [cave | walked], edges, seen, pathes)
      end

    walk(caves, walked, edges, seen, pathes)
  end

  defp walk([], _walked, _edges, _seen, pathes), do: pathes

  defp lowercased?(cave), do: String.downcase(cave, :ascii) == cave
end

Day12.walk(edges)
|> IO.inspect()
|> Enum.count()

Part 2

defmodule Day12Part2 do
  def twice(edges) do
    walk(edges["start"], ["start"], edges, MapSet.new(), false, [])
  end

  defp walk(["end" | caves], walked, edges, seen, once?, pathes) do
    valid_path = Enum.reverse(["end" | walked]) |> Enum.join("-")
    walk(caves, walked, edges, seen, once?, [valid_path | pathes])
  end

  defp walk([cave | caves], walked, edges, seen, once?, pathes) do
    pathes =
      cond do
        cave == "start" or (cave in seen and once?) ->
          pathes

        cave in seen ->
          walk(edges[cave], [cave | walked], edges, MapSet.put(seen, cave), true, pathes)

        lowercased?(cave) ->
          walk(edges[cave], [cave | walked], edges, MapSet.put(seen, cave), once?, pathes)

        true ->
          walk(edges[cave], [cave | walked], edges, seen, once?, pathes)
      end

    walk(caves, [cave | walked], edges, seen, once?, pathes)
  end

  defp walk([], _walked, _edges, _seen, _once?, pathes), do: pathes

  defp lowercased?(cave), do: String.downcase(cave, :ascii) == cave
end

Day12Part2.twice(edges)
|> IO.inspect()
|> Enum.count()