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

Day 08

2023/elixir/day08.livemd

Day 08

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

Part 1

content =
  Kino.FS.file_path("input08.txt")
  |> File.read!()
test = """
LR

11A = (11B, XXX)
11B = (XXX, 11Z)
11Z = (11B, XXX)
22A = (22B, XXX)
22B = (22C, 22C)
22C = (22Z, 22Z)
22Z = (22B, 22B)
XXX = (XXX, XXX)
"""
input = content
[instructions | graph] = String.split(input, "\n", trim: true)
instructions = instructions |> String.codepoints()
network =
  graph
  |> Enum.map(fn line ->
    [node, left, right] = String.split(line, [" ", ",", "=", "(", ")"], trim: true)
    {node, {left, right}}
  end)
  |> Map.new()
defmodule Route do
  def steps(network, instructions) do
    sequence = instructions |> Enum.with_index(&{&2, &1}) |> Map.new()
    steps(network, "AAA", 0, {sequence, 0})
  end

  def steps(_network, "ZZZ", total, _sequence) do
    total
  end

  def steps(network, node, total, sequence) do
    {l, r} = Map.fetch!(network, node)
    {step, sequence} = next_step(sequence)

    next =
      case step do
        "L" -> l
        "R" -> r
      end

    steps(network, next, total + 1, sequence)
  end

  def next_step({instructions, current}) do
    step = Map.fetch!(instructions, current)
    next = current + 1
    next = if next >= map_size(instructions), do: 0, else: next

    {step, {instructions, next}}
  end
end
Route.steps(network, instructions)

Part 2

defmodule MultiRoute do
  def steps(network, instructions) do
    network =
      for {n, {l, r}} <- network, into: %{} do
        {String.reverse(n), {String.reverse(l), String.reverse(r)}}
      end

    nodes = network |> Map.keys() |> Enum.filter(&amp;match?("A" <> _rest, &amp;1))
    sequence = instructions |> Enum.with_index(&amp;{&amp;2, &amp;1}) |> Map.new()

    nodes
    |> Enum.map(fn node ->
      steps(network, node, 0, {sequence, 0})
    end)
  end

  def steps(_network, "Z" <> _, total, _sequence) do
    total
  end

  def steps(network, node, total, sequence) do
    {l, r} = Map.fetch!(network, node)
    {step, sequence} = next_step(sequence)

    next =
      case step do
        "L" -> l
        "R" -> r
      end

    steps(network, next, total + 1, sequence)
  end

  def next_step({instructions, current}) do
    step = Map.fetch!(instructions, current)
    next = current + 1
    next = if next >= map_size(instructions), do: 0, else: next

    {step, {instructions, next}}
  end
end
MultiRoute.steps(network, instructions)
|> Enum.reduce(fn acc, next ->
  trunc(acc * next / Integer.gcd(acc, next))
end)