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

AoC 2023 - Day 08

2023/lang-elixir/08.livemd

AoC 2023 - Day 08

Mix.install([
  {:kino, "~> 0.11.3"}
])

Section

input_e1 =
  "day08-e1.txt"
  |> Kino.FS.file_path()
  |> File.read!()
  |> String.trim()

input_e2 =
  "day08-e2.txt"
  |> Kino.FS.file_path()
  |> File.read!()
  |> String.trim()

input_e3 =
  "day08-e3.txt"
  |> Kino.FS.file_path()
  |> File.read!()
  |> String.trim()

input =
  "day08.txt"
  |> Kino.FS.file_path()
  |> File.read!()
  |> String.trim()

[input_e1, input_e2, input_e3, input]
defmodule SolutionA do
  def part_1(input) do
    [directions, nodes] = parse(input)
    traverse(nodes, directions)
  end

  def traverse(nodes, directions, steps \\ [], next \\ "AAA", counter \\ 0)

  def traverse(_nodes, _directions, _steps, "ZZZ", counter), do: counter

  def traverse(nodes, directions, [], next, counter) do
    traverse(nodes, directions, directions, next, counter)
  end

  def traverse(nodes, directions, ["L" | steps], next, counter) do
    [next_node, _] = nodes[next]
    traverse(nodes, directions, steps, next_node, counter + 1)
  end

  def traverse(nodes, directions, ["R" | steps], next, counter) do
    [_, next_node] = nodes[next]
    traverse(nodes, directions, steps, next_node, counter + 1)
  end

  def parse(input) do
    [direction, nodes] = String.split(input, "\n\n")
    direction = String.graphemes(direction)
    nodes = nodes |> String.split("\n") |> Enum.map(&build/1) |> Map.new()

    [direction, nodes]
  end

  def build(
        <>
      ),
      do: {key, [l, r]}
end
defmodule SolutionB do
  def part_2(input) do
    [directions, nodes] = SolutionA.parse(input)

    nodes
    |> Map.keys()
    |> Enum.filter(&amp;String.ends_with?(&amp;1, "A"))
    |> Enum.map(&amp;traverse(nodes, directions, [], &amp;1))
    |> Enum.reduce(1, &amp;div(&amp;1 * &amp;2, Integer.gcd(&amp;1, &amp;2)))
  end

  def traverse(nodes, directions, steps, next, counter \\ 0)

  def traverse(_nodes, _directions, _steps, <<_::binary-size(2), next::binary-size(1)>>, counter)
      when next == "Z",
      do: counter

  def traverse(nodes, directions, [], next, counter) do
    traverse(nodes, directions, directions, next, counter)
  end

  def traverse(nodes, directions, [step | steps], next, counter) do
    next_node = next_node(nodes[next], step)
    traverse(nodes, directions, steps, next_node, counter + 1)
  end

  def next_node([node, _], "L"), do: node
  def next_node([_, node], "R"), do: node
end
SolutionA.part_1(input)
SolutionB.part_2(input)