Day Seventeen
Mix.install([
{:kino, "~> 0.7.0"}
])
Section
input = Kino.Input.textarea("Input")
defmodule DaySeventeen do
@rocks [
[{2, 0}, {3, 0}, {4, 0}, {5, 0}],
[{3, -2}, {2, -1}, {3, -1}, {4, -1}, {3, 0}],
[{4, -2}, {4, -1}, {2, 0}, {3, 0}, {4, 0}],
[{2, -3}, {2, -2}, {2, -1}, {2, 0}],
[{2, -1}, {3, -1}, {2, 0}, {3, 0}]
]
def solve1(input) do
all_jets =
input
|> String.to_charlist()
@rocks
|> Stream.cycle()
|> Stream.take(1_000_000_000_000)
|> Stream.with_index()
|> Enum.reduce({all_jets, MapSet.new(), all_jets}, fn {rock, i}, {jets, occupied, all_jets} ->
# if MapSet.size(occupied) > 0, do: draw(occupied)
if jets == [] || i == 17444 + 1016 do
IO.inspect(height(occupied), label: "height")
IO.inspect(i, label: "rocks")
end
highest_y = highest_y(occupied)
rock = Enum.map(rock, fn {x, y} -> {x, highest_y + y - 4} end)
place(rock, jets, occupied, all_jets, 0)
end)
|> then(fn {_, occupied, _} ->
ys = Enum.map(occupied, &elem(&1, 1))
Enum.max(ys) - Enum.min(ys) + 1
end)
end
defp solve2(input) do
iters = 1_000_000_000_000
floor(iters / (7049 - 7014)) * (10678 - 10625)
end
defp height(occupied) do
ys = Enum.map(occupied, &elem(&1, 1))
Enum.max(ys) - Enum.min(ys) + 1
end
defp highest_y(occupied) do
if MapSet.size(occupied) == 0 do
4
else
occupied |> Enum.min_by(&elem(&1, 1)) |> elem(1)
end
end
defp place(rock, [], occupied, all_jets, c) do
place(rock, all_jets, occupied, all_jets, c)
end
defp place(rock, [jet | jets], occupied, all_jets, c) do
case rock
|> push(jet, occupied)
|> drop(occupied) do
{:halt, rock} ->
{
jets,
Enum.reduce(rock, occupied, fn pt, acc -> MapSet.put(acc, pt) end),
all_jets
}
{:cont, rock} ->
place(rock, jets, occupied, all_jets, c + 1)
end
end
defp push(rock, dir, occupied) do
new_rock = Enum.map(rock, fn {x, y} -> {x + if(dir == ?>, do: 1, else: -1), y} end)
cond do
Enum.any?(new_rock, fn {x, _y} -> x < 0 || x > 6 end) ->
rock
Enum.any?(new_rock, fn pt -> MapSet.member?(occupied, pt) end) ->
rock
true ->
new_rock
end
end
defp drop(rock, occupied) do
new_rock = Enum.map(rock, fn {x, y} -> {x, y + 1} end)
cond do
Enum.any?(new_rock, fn {_x, y} -> y > 3 end) ->
{:halt, rock}
Enum.any?(new_rock, fn pt -> MapSet.member?(occupied, pt) end) ->
{:halt, rock}
true ->
{:cont, new_rock}
end
end
defp draw(occupied) do
min_y = Enum.map(occupied, &elem(&1, 1)) |> Enum.min()
Enum.each(min_y..3, fn y ->
Enum.each(0..7, fn x ->
if MapSet.member?(occupied, {x, y}) do
IO.write("#")
else
IO.write(".")
end
end)
IO.puts("")
end)
IO.puts("")
IO.puts("")
end
end
DaySeventeen.solve1(Kino.Input.read(input))
# Math for part 2
48 rocks: 78
83 rocks: 131
78 + div(1_000_000_000_000-48, 83-48)*(131-78)
height: 2736
rocks: 1739
height: 5486
rocks: 3484
rocks_to_repeat: 1745
diff: 2750
27486 + div(1_000_000_000_000-17444, 1745)*(2750) + 1590
# 1575931231646
# 1575931232076