Powered by AppSignal & Oban Pro

Day 12: Passage Pathing

2021/day_12_passage_pathing.livemd

Day 12: Passage Pathing

Mix.install([:kino])

input = Kino.Input.textarea("Please paste your input:")

Setup

inputs =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(&(&1 |> String.split("-")))
  |> Enum.reduce(%{}, fn [a, b], map ->
    map
    |> Map.update(a, [b], &[b | &1])
    |> Map.update(b, [a], &[a | &1])
  end)

Part 1

https://adventofcode.com/2021/day/12

Solve: Part 1

defmodule Day12.Part1 do
  def run(connections) do
    do_run(connections, "start", [], [])
  end

  def do_run(_connections, "end", path, results) do
    path = ["end" | path] |> Enum.reverse()

    [path | results]
  end

  def do_run(connections, current_cave, path, results) do
    {next_caves, connections} =
      case cave_type(current_cave) do
        :big -> {connections |> Map.get(current_cave, []), connections}
        :small -> connections |> Map.pop(current_cave, [])
      end

    case next_caves do
      [] ->
        results

      next_caves ->
        next_caves
        |> Enum.reduce(results, fn next_cave, results ->
          do_run(connections, next_cave, [current_cave | path], results)
        end)
    end
  end

  defp cave_type(name) do
    case Regex.match?(~r/[A-Z]+/, name) do
      true -> :big
      false -> :small
    end
  end
end

inputs
|> Day12.Part1.run()
|> Enum.count()

Part 2

https://adventofcode.com/2021/day/12#part2

Solve: Part 2

defmodule Day12.Part2 do
  def run(connections) do
    do_run(connections, "start", true, [], [])
  end

  def do_run(_connections, "end", _twice_flag, path, results) do
    path = ["end" | path] |> Enum.reverse()

    [path | results]
  end

  def do_run(connections, current_cave, twice_flag, path, results) do
    args =
      connections
      |> Map.get(current_cave, [])
      |> Enum.map(fn next_cave ->
        case {twice_flag, cave_type(current_cave)} do
          {twice_flag, :big} ->
            [{next_cave, connections, twice_flag}]

          {true, :small} ->
            [
              {next_cave, connections, false},
              {next_cave, connections |> Map.delete(current_cave), true}
            ]

          {false, :small} ->
            [{next_cave, connections |> Map.delete(current_cave), false}]

          {twice_flag, :start} ->
            [{next_cave, connections |> Map.delete(current_cave), twice_flag}]
        end
      end)
      |> List.flatten()

    case args do
      [] ->
        results

      args ->
        args
        |> Enum.reduce(results, fn {next_cave, connections, twice_flag}, results ->
          do_run(connections, next_cave, twice_flag, [current_cave | path], results)
        end)
    end
  end

  defp cave_type("start"), do: :start

  defp cave_type(name) do
    case Regex.match?(~r/[A-Z]+/, name) do
      true -> :big
      false -> :small
    end
  end
end

inputs
|> Day12.Part2.run()
|> Enum.uniq()
|> Enum.count()