Powered by AppSignal & Oban Pro

Day 08

2023/day08.livemd

Day 08

Mix.install([:kino_aoc])

Section

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2023", "8", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
# puzzle_input =
"""
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)
"""
defmodule Day08 do
  def find_path(instructions, pos, map) do
    Enum.reduce_while(instructions, pos, fn
      {_, idx}, <<_, _, ?Z>> -> {:halt, idx}
      {step, _}, pos -> {:cont, elem(Map.fetch!(map, pos), step)}
    end)
  end
end

[instructions | rest] =
  String.split(puzzle_input, "\n", trim: true)

instructions =
  Stream.cycle(for <<c <- instructions>>, do: if(c == ?L, do: 0, else: 1))
  |> Stream.with_index()

map =
  Map.new(rest, fn
    <<src::binary-3>> <> " = (" <> <<left::binary-3>> <> ", " <> <<right::binary-3>> <> ")" ->
      {src, {left, right}}
  end)

Part 1

Day08.find_path(instructions, "AAA", map)

Part 2

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

Task.async_stream(starts, &Day08.find_path(instructions, &1, map), ordered: false)
|> Enum.reduce(1, fn {:ok, a}, b ->
  div(a * b, Integer.gcd(a, b))
end)