solve 2024 day 12
This commit is contained in:
parent
1e677cbbc9
commit
154e278fb3
3 changed files with 116 additions and 3 deletions
|
@ -3,7 +3,7 @@
|
|||
| S | M | T | W | T | F | S |
|
||||
| :-: | :-: | :-: | :-: | :-: | :-: | :-: |
|
||||
| [1] | [2] | [3] | [4] | [5] | [6] | [7] |
|
||||
| [8] | [9] | [10]| [11]| 12 | 13 | 14 |
|
||||
| [8] | [9] | [10]| [11]| [12]| 13 | 14 |
|
||||
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
|
||||
| 22 | 23 | 24 | 25 | | | |
|
||||
|
||||
|
@ -18,3 +18,4 @@
|
|||
[9]: ./lib/2024/9.ex
|
||||
[10]: ./lib/2024/10.ex
|
||||
[11]: ./lib/2024/11.ex
|
||||
[12]: ./lib/2024/12.ex
|
||||
|
|
112
2024/lib/2024/12.ex
Normal file
112
2024/lib/2024/12.ex
Normal file
|
@ -0,0 +1,112 @@
|
|||
import AOC
|
||||
import AOC.Prelude
|
||||
|
||||
aoc 2024, 12 do
|
||||
def p1(input) do
|
||||
input
|
||||
|> map_grid()
|
||||
|> group_plots()
|
||||
|> Enum.map(&size_plot/1)
|
||||
|> Enum.map(fn {area, perimeter, _} -> area * perimeter end)
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
def p2(input) do
|
||||
input
|
||||
|> map_grid()
|
||||
|> group_plots()
|
||||
|> Enum.map(&size_plot/1)
|
||||
|> Enum.map(fn {area, _, sides} -> area * sides end)
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
## group plots
|
||||
|
||||
defp group_plots(map, plots \\ [])
|
||||
defp group_plots(map, plots) when map_size(map) == 0, do: plots
|
||||
|
||||
defp group_plots(map, plots) do
|
||||
{pos, plant} = Enum.at(map, 0)
|
||||
|
||||
plot = walk_plot(map, pos, plant)
|
||||
|
||||
{_, map} = Map.split(map, MapSet.to_list(plot))
|
||||
|
||||
group_plots(map, [plot | plots])
|
||||
end
|
||||
|
||||
defp size_plot(plot) do
|
||||
area = MapSet.size(plot)
|
||||
|
||||
perimeter =
|
||||
for pos <- plot, reduce: 0 do
|
||||
sum ->
|
||||
sum +
|
||||
([&n/1, &s/1, &e/1, &w/1]
|
||||
|> Enum.map(& &1.(pos))
|
||||
|> Enum.count(&(not MapSet.member?(plot, &1))))
|
||||
end
|
||||
|
||||
{area, perimeter, count_sides(plot)}
|
||||
end
|
||||
|
||||
## traversal
|
||||
|
||||
defp walk_plot(map, pos, plant, plot \\ MapSet.new()) do
|
||||
plot = MapSet.put(plot, pos)
|
||||
|
||||
[&n/1, &s/1, &e/1, &w/1]
|
||||
|> Enum.map(& &1.(pos))
|
||||
|> Enum.reject(&MapSet.member?(plot, &1))
|
||||
|> Enum.filter(&(Map.get(map, &1) == plant))
|
||||
|> Enum.reduce(plot, fn pos, plot ->
|
||||
walk_plot(map, pos, plant, plot)
|
||||
end)
|
||||
end
|
||||
|
||||
def n({x, y}), do: {x, y + 1}
|
||||
def s({x, y}), do: {x, y - 1}
|
||||
def e({x, y}), do: {x + 1, y}
|
||||
def w({x, y}), do: {x - 1, y}
|
||||
|
||||
defp count_sides(plot) do
|
||||
# find exterior faces
|
||||
exterior_faces =
|
||||
for pos <- plot, dir <- ~w[n e s w]a, exterior?(plot, pos, dir) do
|
||||
{pos, dir}
|
||||
end
|
||||
|
||||
exterior_faces
|
||||
# group exterior faces
|
||||
|> Enum.group_by(
|
||||
fn
|
||||
{{_, y}, dir} when dir in ~w[n s]a -> {dir, y}
|
||||
{{x, _}, dir} when dir in ~w[e w]a -> {dir, x}
|
||||
end,
|
||||
fn
|
||||
{{x, _}, dir} when dir in ~w[n s]a -> x
|
||||
{{_, y}, dir} when dir in ~w[e w]a -> y
|
||||
end
|
||||
)
|
||||
|> Map.values()
|
||||
# count groups of exterior faces, splitting non-monotonic sections
|
||||
|> Enum.map(fn group ->
|
||||
{faces, _} =
|
||||
group
|
||||
|> Enum.sort()
|
||||
|> Enum.reduce({0, nil}, fn
|
||||
n, {sides, nil} -> {sides + 1, n}
|
||||
n, {sides, last} when last + 1 == n -> {sides, n}
|
||||
n, {sides, _last} -> {sides + 1, n}
|
||||
end)
|
||||
|
||||
faces
|
||||
end)
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
defp exterior?(plot, pos, dir) do
|
||||
neighboring_pos = apply(__MODULE__, dir, [pos])
|
||||
not MapSet.member?(plot, neighboring_pos)
|
||||
end
|
||||
end
|
|
@ -15,8 +15,8 @@
|
|||
| [2021] | **43/50** 🌟 | Elixir |
|
||||
| [2022] | **14/50** 🌟 | Elixir, Haskell |
|
||||
| [2023] | **19/50** 🌟 | Elixir, Haskell |
|
||||
| [2024] | **22/50** 🌟 | Elixir |
|
||||
| **Total** | **178** 🌟| |
|
||||
| [2024] | **24/50** 🌟 | Elixir |
|
||||
| **Total** | **180** 🌟| |
|
||||
|
||||
[2015]: ./2015
|
||||
[2017]: ./2017
|
||||
|
|
Loading…
Reference in a new issue