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

Advent 2021 - Day 13

day13.livemd

Advent 2021 - Day 13

Setup

Mix.install([
  {:kino, github: "livebook-dev/kino"}
])
input = Kino.Input.textarea("Please paste your input file:")
[positions, instructions] =
  input
  |> Kino.Input.read()
  |> String.trim()
  |> String.split("\n\n")
  |> Enum.map(&String.split(&1, "\n"))

instructions =
  instructions
  |> Enum.map(fn instruction ->
    [axis, position] =
      instruction
      |> String.replace("fold along ", "")
      |> String.split("=")

    {String.to_atom(axis), String.to_integer(position)}
  end)

positions =
  positions
  |> Enum.map(fn point ->
    [x, y] =
      point
      |> String.split(",")
      |> Enum.map(fn scalar -> String.to_integer(scalar) end)

    {x, y}
  end)

{positions, instructions}

Utils

defmodule Utils do
  def max_x(positions) do
    positions
    |> Enum.max_by(fn {x, _} -> x end)
    |> then(&elem(&1, 0))
  end

  def max_y(positions) do
    positions
    |> Enum.max_by(fn {_, y} -> y end)
    |> then(&elem(&1, 1))
  end

  def display(positions) do
    mx = max_x(positions)
    my = max_y(positions)

    text =
      Enum.map(0..my, fn y ->
        line =
          Enum.map(0..mx, fn x ->
            if Enum.find(positions, fn position -> position == {x, y} end) do
              "##"
            else
              ".."
            end
          end)

        "#{line}\n"
      end)

    Kino.Markdown.new(~s"""
    ```
    #{text}
    ```
    """)
  end

  def apply_fold(positions, {:y, amount}) do
    positions
    |> Enum.map(fn {x, y} ->
      if y > amount do
        {x, amount - (y - amount)}
      else
        {x, y}
      end
    end)
    |> Enum.uniq()
  end

  def apply_fold(positions, {:x, amount}) do
    positions
    |> Enum.map(fn {x, y} ->
      if x > amount do
        {amount - (x - amount), y}
      else
        {x, y}
      end
    end)
    |> Enum.uniq()
  end
end

Part 1

first_instruction = List.first(instructions)

positions
|> Part1.apply_fold(first_instruction)
|> Enum.count()

Part 2

positions =
  Enum.reduce(instructions, positions, fn instruction, positions ->
    Utils.apply_fold(positions, instruction)
  end)
  |> Utils.display()