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

Day 8

Day8.livemd

Day 8

Mix.install([
  {:kino_aoc, "~> 0.1.5"},
  {:math, "~> 0.7.0"}
])

Untitled

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2023", "8", System.fetch_env!("LB_AOC_SESSION"))
[leftrights, network] = String.split(puzzle_input, "\n\n")

network =
  network
  |> String.split("\n")
  |> Map.new(fn l ->
    [node, left, right] =
      [0..2, 7..9, 12..14]
      |> Enum.map(&String.slice(l, &1))

    {node, {left, right}}
  end)

leftrights =
  leftrights
  |> String.to_charlist()
  |> Enum.map(fn
    ?L -> 0
    ?R -> 1
  end)

Part 1

distance_to_zzz =
  leftrights
  |> Stream.cycle()
  |> Stream.scan("AAA", fn lr, node -> network[node] |> elem(lr) end)
  |> Stream.take_while(&(&1 != "ZZZ"))
  |> Enum.count()
  |> (&(&1 + 1)).()
rem(distance_to_zzz, Enum.count(leftrights))

Part 2

defmodule Network do
  def step(network, node, lr) do
    network[node] |> elem(lr)
  end

  def follow_path(network, start_node, turns) do
    [start_node | turns |> Enum.scan(start_node, fn lr, node -> step(network, node, lr) end)]
  end

  def end_of_path(network, start_node, turns) do
    turns
    |> Enum.reduce(start_node, fn lr, node -> step(network, node, lr) end)
  end
end

nexts =
  network
  |> Map.keys()
  |> Map.new(&{&1, Network.end_of_path(network, &1, leftrights)})

starts =
  Map.keys(nexts)
  |> Enum.filter(&String.ends_with?(&1, "A"))

loop_counts =
  Enum.map(starts, fn node ->
    Stream.iterate(node, &nexts[&1])
    |> Enum.find_index(&String.ends_with?(&1, "Z"))
  end)
  |> IO.inspect(charlists: :as_list)

# This _really_ shouldn't work for the general case but the problem is conveniently structured
Enum.product(loop_counts) * Enum.count(leftrights)