Powered by AppSignal & Oban Pro

Advent of Code - Day 9

day_9.livemd

Advent of Code - Day 9

Mix.install(
  [
    {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"}
  ],
  force: true
)

Section

{:ok, puzzle_input} = KinoAOC.download_puzzle("2022", "9", System.fetch_env!("LB_SESSION"))
input = """
R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2
"""
defmodule Rope do
  def move_head(input) do
    input
    |> String.split("\n", trim: true)
    |> Stream.map(fn l -> String.split(l, " ") end)
    |> Stream.map(fn [move, count] -> {move, String.to_integer(count)} end)
    |> Stream.flat_map(fn {dir, count} -> Stream.map(0..(count - 1), fn _ -> dir end) end)
    |> Stream.scan({0, 0}, &make_head_move/2)
  end

  def move_tail(head_positions) do
    Stream.scan(head_positions, {0, 0}, &make_tail_move/2)
  end

  defp make_head_move("R", {x, y}), do: {x + 1, y}
  defp make_head_move("L", {x, y}), do: {x - 1, y}
  defp make_head_move("U", {x, y}), do: {x, y + 1}
  defp make_head_move("D", {x, y}), do: {x, y - 1}

  defp make_tail_move({hx, hy}, {tx, ty}) when abs(hx - tx) > 1 or abs(hy - ty) > 1,
    do: {tx + get_cross_direction(hx, tx), ty + get_cross_direction(hy, ty)}

  defp make_tail_move(_head, tail), do: tail

  defp get_cross_direction(x, x), do: 0
  defp get_cross_direction(head, tail) when head > tail, do: 1
  defp get_cross_direction(_head, _tail), do: -1
end

Part 1

puzzle_input
|> Rope.move_head()
|> Rope.move_tail()
|> Enum.uniq()
|> Enum.count()

Part 2

puzzle_input
|> Rope.move_head()
|> Rope.move_tail()
|> Rope.move_tail()
|> Rope.move_tail()
|> Rope.move_tail()
|> Rope.move_tail()
|> Rope.move_tail()
|> Rope.move_tail()
|> Rope.move_tail()
|> Rope.move_tail()
|> Enum.uniq()
|> Enum.count()