Powered by AppSignal & Oban Pro

Advent of Code 2024 Day 6 Part 2

2024_day6_part2.livemd

Advent of Code 2024 Day 6 Part 2

Mix.install([
  {:kino_aoc, "~> 0.1"}
])

Get Inputs

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2024", "6", System.fetch_env!("LB_SESSION"))

My answer

sample_input =
  """
  ....#.....
  .........#
  ..........
  ..#.......
  .......#..
  ..........
  .#..^.....
  ........#.
  #.........
  ......#...
  """
  |> String.trim()

Kino.Text.new(sample_input, terminal: true)
turn = fn input ->
  input
  |> String.replace("^", "<")
  |> String.split("\n")
  |> Enum.map(&String.codepoints(&1))
  |> Enum.zip()
  |> Enum.map(fn col -> col |> Tuple.to_list() |> Enum.join() end)
  |> Enum.reverse()
  |> Enum.join("\n")
end
round = fn input ->
  Enum.reduce_while(1..1000, {input, [], :up}, fn _, {acc_input, tuened_points, direction} ->
    turned_input = turn.(acc_input)
    direction =
      case direction do
        :up -> :right
        :right -> :down
        :down -> :left
        :left -> :up
      end

    case Regex.scan(~r/#[^\n#]*</, turned_input) do
      [[route]] ->
        [[{point, _}]] = Regex.scan(~r/#[^\n#]*</, turned_input, return: :index)
        turned_point = {direction, point}
        turned_input =
          String.replace(
            turned_input,
            route,
            "#^" <> String.duplicate("X", String.length(route) - 2)
          )

        if Enum.member?(tuened_points, turned_point) do
          {
            :halt,
            { 
              turned_input,
              direction,
              true
            }
          }
        else
          {
            :cont,
            { 
              turned_input,
              [turned_point | tuened_points],
              direction
            }
          }
        end

      _ ->
        route =
          Regex.scan(~r/\.[^\n]*</, turned_input)
          |> hd()
          |> hd()

        {
          :halt,
          {
            String.replace(
              turned_input,
              route,
              String.duplicate("X", String.length(route))
            ),
            direction,
            false
          }
        }
    end
  end)
end
{rounded, _, looped} =
  """
  ..#...
  .....#
  ..^...
  .#....
  ....#.
  """
  |> String.trim()
  |> round.()

IO.inspect(looped, label: "looped")

Kino.Text.new(rounded, terminal: true)
{rounded, direction, looped} = round.(sample_input)

IO.inspect(looped, label: "looped")

rounded =
  case direction do
    :up ->
      rounded
    :right ->
      rounded
      |> turn.()
      |> turn.()
      |> turn.()
    :down ->
      rounded
      |> turn.()
      |> turn.()
    :left ->
      turn.(rounded)
  end

Kino.Text.new(rounded, terminal: true)
replaced =
  Regex.scan(~r/X/, rounded, return: :index)
  |> hd()
  |> then(fn [{index, _}] ->
    String.slice(sample_input, 0..(index - 1)) <>
      "#" <> String.slice(sample_input, (index + 1)..-1//1)
  end)

Kino.Text.new(replaced, terminal: true)
{rounded_replaced, direction, looped} = round.(replaced)

IO.inspect(looped, label: "looped")

Kino.Text.new(rounded_replaced, terminal: true)
Regex.scan(~r/X/, rounded, return: :index)
|> Enum.reduce(0, fn [{index, _}], loop_count ->
  if String.at(sample_input, index) == "^" do
    loop_count
  else
    replaced =
      String.slice(sample_input, 0..(index - 1)) <>
        "#" <> String.slice(sample_input, (index + 1)..-1//1)

    {_, _, looped} = round.(replaced)

    loop_count + if looped, do: 1, else: 0
  end
end)
{rounded, direction, _} = round.(puzzle_input)

rounded =
  case direction do
    :up ->
      rounded
    :right ->
      rounded
      |> turn.()
      |> turn.()
      |> turn.()
    :down ->
      rounded
      |> turn.()
      |> turn.()
    :left ->
      turn.(rounded)
  end
Regex.scan(~r/X/, rounded, return: :index)
|> Enum.reduce(0, fn [{index, _}], loop_count ->
  if String.at(puzzle_input, index) == "^" do
    loop_count
  else
    replaced =
      String.slice(puzzle_input, 0..(index - 1)) <>
        "#" <> String.slice(puzzle_input, (index + 1)..-1//1)

    {_, _, looped} = round.(replaced)

    loop_count + if looped, do: 1, else: 0
  end
end)