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

Day 8

2023/day08.livemd

Day 8

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

Section

input = Kino.Input.textarea("input")
defmodule Network do
  def traverse(instructions, network, start \\ "AAA", stop \\ "ZZZ") do
    instructions
    |> stream_instructions()
    |> Enum.reduce_while({start, 0}, fn instruction, {x, steps} ->
      if String.starts_with?(x, stop) do
        {:halt, steps}
      else
        {:cont, {elem(network[x], instruction), steps + 1}}
      end
    end)
  end

  defp stream_instructions(instructions) do
    instructions
    |> String.replace("L", "0")
    |> String.replace("R", "1")
    |> String.split("", trim: true)
    |> Enum.map(&String.to_integer/1)
    |> Stream.cycle()
  end

  def parse(network) do
    Map.new(network, fn line ->
      line
      |> String.split([" = (", ", ", ")"], trim: true)
      |> Enum.map(&String.reverse/1)
      |> then(fn [x, l, r] -> {x, {l, r}} end)
    end)
  end
end

{instructions, map} =
  input
  |> Kino.Input.read()
  |> String.split("\n")
  |> then(fn [inst, _ | map] ->
    {inst, Network.parse(map)}
  end)
Network.traverse(instructions, map)
map
|> Map.keys()
|> Enum.filter(&amp;match?("A" <> _, &amp;1))
|> Enum.map(&amp;Network.traverse(instructions, map, &amp;1, "Z"))
|> Enum.reduce(1, &amp;div(&amp;1 * &amp;2, Integer.gcd(&amp;1, &amp;2)))