Files
aoc-2023/lib/day14.ex
bluepython508 a7beb06a28 Day 14
2023-12-14 09:38:23 +00:00

78 lines
1.8 KiB
Elixir

defmodule Aoc2023.Day14 do
use Aoc2023
def parse(input) do
input
|> lines
|> Enum.map(&String.to_charlist/1)
end
defp replace_many_at(lst, idxs, val) do
idxs |> Enum.reduce(lst, &List.replace_at(&2, &1, val))
end
defp slide(grid) do
iter = fn recur, grid ->
case grid do
[last | [next | rest]] ->
idxs =
last
|> Enum.with_index()
|> Enum.filter(pipe(elem(0) |> Kernel.==(?O)))
|> Enum.map(pipe(elem(1)))
|> Enum.filter(&(Enum.at(next, &1) == ?.))
[
last |> replace_many_at(idxs, ?.)
| recur.(recur, [next |> replace_many_at(idxs, ?O) | rest])
]
[last] ->
[last]
end
end
loop = fn recur, grid ->
grid_ = iter.(iter, grid)
if grid_ == grid, do: grid, else: recur.(recur, grid_)
end
loop.(loop, grid |> Enum.reverse())
end
defp cycle(grid) do
for _ <- 1..4, reduce: grid do
# reverse |> transpose is rotation clockwise, but slide already reverses
grid -> grid |> slide |> transpose
end
end
defp cycles(grid, n \\ 1_000_000_000, {cache_to_n, cache_from_n} \\ {%{}, %{}}) when n > 0 do
rep_n = Map.get(cache_to_n, grid)
if rep_n do
n_ = rep_n - Integer.mod(n, rep_n - n)
cache_from_n |> Map.get(n_)
else
grid_ = cycle(grid)
cycles(grid_, n - 1, {Map.put(cache_to_n, grid, n), Map.put(cache_from_n, n, grid)})
end
end
def part1(input) do
input
|> slide
|> Enum.with_index(1)
|> Enum.map(fn {row, i} -> Enum.count(row, &(&1 == ?O)) * i end)
|> Enum.sum()
end
def part2(input) do
input
|> cycles()
|> Enum.reverse
|> Enum.with_index(1)
|> Enum.map(fn {row, i} -> Enum.count(row, &(&1 == ?O)) * i end)
|> Enum.sum()
end
end