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

Day Nine

day9.livemd

Day Nine

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

Section

input = Kino.Input.textarea("Input")
defmodule DayNine do
  def solve1(input) do
    input
    |> String.split("\n", trim: true)
    |> eval()
    |> MapSet.size()
  end

  def solve2(input) do
    input
    |> String.split("\n", trim: true)
    |> eval2()
    |> MapSet.size()
  end

  defp eval(lines) do
    eval(lines, {0, 0}, {0, 0}, MapSet.new())
  end

  defp eval([], _h, _t, visited) do
    visited
  end

  defp eval([line | rest], h, t, visited) do
    [dir, count] = String.split(line, " ")

    {h, t, visited} =
      Enum.reduce(1..String.to_integer(count), {h, t, visited}, fn _, {h, t, visited} ->
        step(dir, h, t, visited)
      end)

    eval(rest, h, t, visited)
  end

  defp step(dir, h, t, visited) do
    new_h = move_head(h, dir)
    new_t = move_tail(new_h, t)
    {new_h, new_t, MapSet.put(visited, new_t)}
  end

  defp eval2(lines) do
    eval2(lines, {0, 0}, Enum.map(1..9, fn _ -> {0, 0} end), MapSet.new())
  end

  defp eval2([], _h, _t, visited) do
    visited
  end

  defp eval2([line | rest], h, t, visited) do
    [dir, count] = String.split(line, " ")

    {h, t, visited} =
      Enum.reduce(1..String.to_integer(count), {h, t, visited}, fn _, {h, t, visited} ->
        step2(dir, h, t, visited)
      end)

    eval2(rest, h, t, visited)
  end

  defp step2(dir, h, t, visited) do
    new_h = move_head(h, dir)

    {last_new_t, new_t} =
      Enum.reduce(t, {new_h, []}, fn t, {h, acc} ->
        new_t = move_tail(h, t)
        {new_t, [new_t | acc]}
      end)

    {new_h, Enum.reverse(new_t), MapSet.put(visited, last_new_t)}
  end

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

  defp move_tail({hx, hy}, {tx, ty}) do
    cond do
      abs(hx - tx) <= 1 &amp;&amp; abs(hy - ty) <= 1 -> {tx, ty}
      hx == tx &amp;&amp; hy > ty -> {tx, ty + 1}
      hx == tx &amp;&amp; hy < ty -> {tx, ty - 1}
      hy == ty &amp;&amp; hx > tx -> {tx + 1, ty}
      hy == ty &amp;&amp; hx < tx -> {tx - 1, ty}
      hx > tx &amp;&amp; hy > ty -> {tx + 1, ty + 1}
      hx > tx &amp;&amp; hy < ty -> {tx + 1, ty - 1}
      hx < tx &amp;&amp; hy > ty -> {tx - 1, ty + 1}
      hx < tx &amp;&amp; hy < ty -> {tx - 1, ty - 1}
    end
  end
end

DayNine.solve2(Kino.Input.read(input))