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

Advent 2021 - Day 5

day5.livemd

Advent 2021 - Day 5

Setup

Mix.install([
  {:kino, github: "livebook-dev/kino"}
])
input = Kino.Input.textarea("Please paste your input file:")
lines =
  input
  |> Kino.Input.read()
  |> String.trim()
  |> String.split("\n")
  |> Enum.map(fn line ->
    line
    |> String.split(" -> ")
    |> Enum.map(fn point ->
      point
      |> String.split(",")
      |> Enum.map(&String.to_integer(&1))
      |> then(&List.to_tuple(&1))
    end)
    |> then(&List.to_tuple(&1))
  end)

Utils

defmodule Utils do
  def is_horizontal({{x0, _}, {x1, _}}) do
    x0 == x1
  end

  def is_vertical({{_, y0}, {_, y1}}) do
    y0 == y1
  end

  def direction_vector({{x0, y0}, {x1, y1}}) do
    x =
      cond do
        x0 == x1 -> 0
        x0 > x1 -> -1
        x0 < x1 -> 1
      end

    y =
      cond do
        y0 == y1 -> 0
        y0 > y1 -> -1
        y0 < y1 -> 1
      end

    {x, y}
  end

  def draw_point(board, point) do
    Map.get_and_update(board, point, fn val ->
      next_val = if val == nil, do: 1, else: val + 1
      {val, next_val}
    end)
    |> elem(1)
  end

  def draw_line(board, _direction_vector, {p0, p1}) when p0 == p1 do
    draw_point(board, p0)
  end

  def draw_line(board, direction_vector = {dx, dy}, {p0 = {p0x, p0y}, p1}) do
    board = draw_point(board, p0)
    next_p0 = {p0x + dx, p0y + dy}
    draw_line(board, direction_vector, {next_p0, p1})
  end

  def draw_line(board, line) do
    vector = direction_vector(line)
    draw_line(board, vector, line)
  end
end

Part 1

# filter out non-horizontal and non-vertical lines
straight_lines =
  lines
  |> Enum.filter(&amp;(Utils.is_horizontal(&amp;1) || Utils.is_vertical(&amp;1)))

overlapping_points = Enum.reduce(straight_lines, %{}, &amp;Utils.draw_line(&amp;2, &amp;1))

overlapping_points
|> Map.values()
|> Enum.filter(&amp;(&amp;1 > 1))
|> Enum.count()

Part 2

overlapping_points = Enum.reduce(lines, %{}, &amp;Utils.draw_line(&amp;2, &amp;1))

overlapping_points
|> Map.values()
|> Enum.filter(&amp;(&amp;1 > 1))
|> Enum.count()