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

Day 13

2021/day-13.livemd

Day 13

Setup

Mix.install([{:kino, "~> 0.4.1"}])
example_input =
  Kino.Input.textarea("example input:")
  |> Kino.render()

real_input = Kino.Input.textarea("real input:")
defmodule Transparency do
  def fold(grid, {max_x, max_y}, {"x", line}) do
    grid =
      for x <- (line + 1)..max_x, y <- 0..max_y, value = grid[{x, y}], reduce: grid do
        grid ->
          Map.delete(grid, {x, y}) |> Map.put({x - (x - line) * 2, y}, value)
      end

    {grid, {div(max_x, 2), max_y}}
  end

  def fold(grid, {max_x, max_y}, {"y", line}) do
    grid =
      for x <- 0..max_x, y <- (line + 1)..max_y, value = grid[{x, y}], reduce: grid do
        grid ->
          Map.delete(grid, {x, y}) |> Map.put({x, y - (y - line) * 2}, value)
      end

    {grid, {max_x, div(max_y, 2)}}
  end

  def parse(input) do
    {
      parse_grid(input, %{}),
      parse_instructions(input, [])
    }
  end

  def parse_grid(input), do: parse_grid(input, %{})
  def parse_grid([], grid), do: grid
  def parse_grid(["fold " <> _ | rest], grid), do: parse_grid(rest, grid)

  def parse_grid([coord | rest], grid) do
    [col, row] =
      coord
      |> String.split(",")
      |> Enum.map(&amp;String.to_integer/1)

    parse_grid(rest, Map.put(grid, {col, row}, true))
  end

  def parse_instructions(input), do: parse_instructions(input, [])
  def parse_instructions([], instructions), do: Enum.reverse(instructions)

  def parse_instructions(["fold along " <> instruction | rest], instructions) do
    [axis, value] = String.split(instruction, "=")
    parse_instructions(rest, [{axis, String.to_integer(value)} | instructions])
  end

  def parse_instructions([_ | rest], instructions), do: parse_instructions(rest, instructions)
end
{grid, instructions} =
  real_input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Transparency.parse()

max_x =
  Map.keys(grid)
  |> Enum.map(&amp;elem(&amp;1, 0))
  |> Enum.max()

max_y =
  Map.keys(grid)
  |> Enum.map(&amp;elem(&amp;1, 1))
  |> Enum.max()

Part 1

{grid, {max_x, max_y}} =
  instructions
  |> Enum.take(1)
  |> Enum.reduce({grid, {max_x, max_y}}, fn instruction, {grid, {max_x, max_y}} ->
    Transparency.fold(grid, {max_x, max_y}, instruction)
  end)

grid
|> Map.keys()
|> Enum.count()

Part 2

{grid, {max_x, max_y}} =
  instructions
  |> Enum.reduce({grid, {max_x, max_y}}, fn instruction, {grid, {max_x, max_y}} ->
    Transparency.fold(grid, {max_x, max_y}, instruction)
  end)

for y <- 0..max_y, into: [] do
  for x <- 0..max_x, reduce: "" do
    acc -> acc <> if grid[{x, y}], do: ".", else: " "
  end <> "\n"
end
|> IO.puts()