Sponsored by AppSignal
Would you like to see your link here? Contact us
Notesclub

Day 13

advent_of_code/2021/day-13.livemd

Day 13

Setup

Mix.install([
  {:kino, "~> 0.5.0"},
  {:vega_lite, "~> 0.1.1"}
])
input = Kino.Input.textarea("Input:")
{dots, folds} =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.split_while(&(not String.starts_with?(&1, "fold along ")))

paper =
  Enum.map(dots, fn dot ->
    [x, y] = String.split(dot, ",")
    {String.to_integer(x), String.to_integer(y)}
  end)

folds =
  Enum.map(folds, fn "fold along " <> fold ->
    [dir, fold] = String.split(fold, "=")
    {String.to_atom(dir), String.to_integer(fold)}
  end)

folder = fn
  :x, fold -> fn {x, y} -> {fold - abs(x - fold), y} end
  :y, fold -> fn {x, y} -> {x, fold - abs(y - fold)} end
end

Part 1

folds
|> Enum.take(1)
|> Enum.reduce(paper, fn {dir, fold}, paper ->
  Enum.map(paper, folder.(dir, fold))
end)
|> Enum.uniq()
|> length()

Part 2

folded =
  Enum.reduce(folds, paper, fn {dir, fold}, paper ->
    Enum.map(paper, folder.(dir, fold))
  end)

{width, _} = Enum.max_by(folded, &amp;elem(&amp;1, 0))
{_, height} = Enum.max_by(folded, &amp;elem(&amp;1, 1))

grid = MapSet.new(folded)

for y <- 0..height do
  for x <- 0..width do
    if {x, y} in grid do
      IO.write(" # ")
    else
      IO.write("   ")
    end
  end

  IO.puts("")
end

VegaLite

alias VegaLite, as: Vl
paper_to_values = fn paper ->
  Enum.map(paper, fn {x, y} -> %{x: x, y: -y} end)
end

graph =
  Vl.new(width: 800, height: 150)
  |> Vl.config(view: [stroke: :transparent])
  |> Vl.mark(:square, opacity: 0.4, size: 900)
  |> Vl.data_from_values(paper_to_values.(paper))
  |> Vl.encode_field(:x, "x", type: :quantitative, axis: false)
  |> Vl.encode_field(:y, "y", type: :quantitative, axis: false)
  |> Vl.encode_field(:color, "x",
    type: :quantitative,
    scale: [range: ["#27e3c8", "#b25ae7"]],
    legend: false
  )
  |> Kino.VegaLite.new()
  |> Kino.render()

Enum.reduce(folds, paper, fn {dir, fold}, paper ->
  paper = Enum.map(paper, folder.(dir, fold))

  Process.sleep(500)
  Kino.VegaLite.clear(graph)
  Kino.VegaLite.push_many(graph, paper_to_values.(paper))

  paper
end)

:ok