Day 14
This commit is contained in:
@@ -4,12 +4,11 @@ defmodule Aoc2023 do
|
|||||||
import Aoc2023.Common
|
import Aoc2023.Common
|
||||||
|
|
||||||
def main(input) do
|
def main(input) do
|
||||||
{took, _} = :timer.tc fn ->
|
{t_parse, parsed} = :timer.tc fn -> parse(input) end
|
||||||
parsed = parse(input)
|
{t_p1, _} = :timer.tc fn -> IO.puts("Part 1: #{part1(parsed)}") end
|
||||||
IO.puts("Part 1: #{part1(parsed)}")
|
|
||||||
IO.puts("Part 2: #{part2(parsed)}")
|
{t_p2, _} = :timer.tc fn -> IO.puts("Part 2: #{part2(parsed)}") end
|
||||||
end
|
IO.puts("Took #{(t_parse + t_p1 + t_p2) / 1_000}ms (parse: #{t_parse / 1_000}ms, part1: #{t_p1 / 1_000}ms, part2: #{t_p2 / 1_000}ms)")
|
||||||
IO.puts("Took #{took / 1_000}ms")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
77
lib/day14.ex
Normal file
77
lib/day14.ex
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
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
|
||||||
@@ -15,6 +15,7 @@ defmodule Mix.Tasks.Aoc do
|
|||||||
defp module(11), do: Aoc2023.Day11
|
defp module(11), do: Aoc2023.Day11
|
||||||
defp module(12), do: Aoc2023.Day12
|
defp module(12), do: Aoc2023.Day12
|
||||||
defp module(13), do: Aoc2023.Day13
|
defp module(13), do: Aoc2023.Day13
|
||||||
|
defp module(14), do: Aoc2023.Day14
|
||||||
# [MODULE INSERTION POINT]
|
# [MODULE INSERTION POINT]
|
||||||
|
|
||||||
defp base_dir(), do: System.get_env("AOC_BASE")
|
defp base_dir(), do: System.get_env("AOC_BASE")
|
||||||
@@ -107,6 +108,10 @@ defmodule Mix.Tasks.Aoc do
|
|||||||
create_file("#{tests_dir(day)}#{last + 1}", IO.read(:stdio, :eof))
|
create_file("#{tests_dir(day)}#{last + 1}", IO.read(:stdio, :eof))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp run(day, ["test", "expected", test, part, value]) do
|
||||||
|
create_file("#{tests_dir(day)}#{test}.#{part}", value)
|
||||||
|
end
|
||||||
|
|
||||||
defp run(day, ["test", "expected", test, part]) do
|
defp run(day, ["test", "expected", test, part]) do
|
||||||
create_file("#{tests_dir(day)}#{test}.#{part}", IO.read(:stdio, :eof))
|
create_file("#{tests_dir(day)}#{test}.#{part}", IO.read(:stdio, :eof))
|
||||||
end
|
end
|
||||||
@@ -162,6 +167,19 @@ defmodule Mix.Tasks.Aoc do
|
|||||||
run_file(day, "#{base_dir()}/inputs/day#{day}")
|
run_file(day, "#{base_dir()}/inputs/day#{day}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp run(day, ["run", "submit", part]) do
|
||||||
|
run(day, ["fetch"])
|
||||||
|
mod = module(day)
|
||||||
|
parsed = mod.parse(read("#{base_dir()}/inputs/day#{day}"))
|
||||||
|
val = case part do
|
||||||
|
"1" -> mod.part1(parsed)
|
||||||
|
"2" -> mod.part2(parsed)
|
||||||
|
end
|
||||||
|
HTTPoison.start()
|
||||||
|
resp = HTTPoison.post!("https://adventofcode.com/2023/day/#{day}/answer", {:form, [level: part, answer: stringify(val)]}, "user-agent": "aoc-ex by ben@soroos.net", cookie: "session=#{System.get_env("AOC_SESSION")}")
|
||||||
|
resp |> dbg
|
||||||
|
end
|
||||||
|
|
||||||
defp run(day, ["run", "-"]) do
|
defp run(day, ["run", "-"]) do
|
||||||
run_file(day)
|
run_file(day)
|
||||||
end
|
end
|
||||||
@@ -209,4 +227,4 @@ defmodule Mix.Tasks.Aoc do
|
|||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
10
tests/day14/1
Normal file
10
tests/day14/1
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
O....#....
|
||||||
|
O.OO#....#
|
||||||
|
.....##...
|
||||||
|
OO.#O....O
|
||||||
|
.O.....O#.
|
||||||
|
O.#..O.#.#
|
||||||
|
..O..#O..O
|
||||||
|
.......O..
|
||||||
|
#....###..
|
||||||
|
#OO..#....
|
||||||
1
tests/day14/1.1
Normal file
1
tests/day14/1.1
Normal file
@@ -0,0 +1 @@
|
|||||||
|
136
|
||||||
1
tests/day14/1.2
Normal file
1
tests/day14/1.2
Normal file
@@ -0,0 +1 @@
|
|||||||
|
64
|
||||||
Reference in New Issue
Block a user