Powered by AppSignal & Oban Pro

Day17

2021/day17.livemd

Day17

Untitled

data =
  "input"
  |> IO.getn(1_000_000)
  |> String.trim()
  |> String.trim_leading("target area: ")
  |> String.split(", ")
  |> then(fn ["x=" <> x_range, "y=" <> y_range] ->
    {x_range, []} = Code.eval_string(x_range)
    {y_range, []} = Code.eval_string(y_range)
    {x_range, y_range}
  end)
defmodule D17 do
  def calc({xmin..xmax = xr, ymin..ymax = yr}) do
    dxmin = 1..xmin |> Enum.find(&amp;(Enum.sum(1..&amp;1) >= xmin))

    Enum.reduce(dxmin..xmax, [], fn dx, acc ->
      Enum.reduce(ymin..-ymin, acc, fn dy, acc ->
        {dx_h0, x, dy_h0} =
          if dy > 0 do
            dx_h1 = dx - dy * 2
            {max(dx_h1 - 1, 0), Enum.sum(max(dx_h1, 1)..dx), -dy - 1}
          else
            {dx, 0, dy}
          end

        Stream.iterate({{x, 0}, {dx_h0, dy_h0}}, fn {{x, y}, {dx, dy}} ->
          {{x + dx, y + dy}, {(dx > 0 &amp;&amp; dx - 1) || ((dx < 0 &amp;&amp; dx + 1) || dx), dy - 1}}
        end)
        |> Stream.drop_while(fn {{x, y}, {dx, _dy}} ->
          (x < xmin and dx > 0) or y > ymax
        end)
        |> Stream.take_while(fn {{x, y}, _} ->
          x in xr and y in yr
        end)
        |> Enum.any?()
        |> if(do: [dy | acc], else: acc)
      end)
    end)
  end

  def solve1(data) do
    data
    |> Enum.max()
    |> then(fn h -> Enum.sum(1..h) end)
  end

  def solve2(data) do
    length(data)
  end
end
data
|> D17.calc()
|> D17.solve1()
data
|> D17.calc()
|> D17.solve2()