Advent of Code 2024 Day 12 Part 1
Mix.install([
{:kino_aoc, "~> 0.1"}
])
Get Inputs
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2024", "12", System.fetch_env!("LB_SESSION"))
My answer
small_sample_input =
"""
AAAA
BBCD
BBCC
EEEC
"""
|> String.trim()
parse_map = fn input ->
input
|> String.split("\n")
|> Enum.with_index()
|> Enum.flat_map(fn {row, row_index} ->
row
|> String.codepoints()
|> Enum.with_index()
|> Enum.map(fn {plant, col_index} ->
{{row_index, col_index}, plant}
end)
end)
|> Enum.into(%{})
end
map = parse_map.(small_sample_input)
defmodule Regions do
@next_points [
{-1, 0},
{1, 0},
{0, -1},
{0, 1}
]
@initial_region %{
price: 0,
fences: 0,
points: []
}
def get(map) do
map
|> Enum.reduce(%{}, fn {point, plant}, acc_regions ->
region = connect_point(point, plant, map, acc_regions)
Map.put(acc_regions, plant, region)
end)
end
defp connect_point(point, plant, map, acc_regions) do
{cur_r, cur_c} = point
{num_fences, new_points} =
@next_points
|> Enum.reduce({0, []}, fn {mov_r, move_c}, {acc_fences, acc_points} ->
next_point = {cur_r + mov_r, cur_c + move_c}
case Map.get(map, next_point) do
^plant ->
{acc_fences, [next_point | acc_points]}
_ ->
{acc_fences + 1, acc_points}
end
end)
new_points = [point | new_points]
case Map.get(acc_regions, plant) do
nil ->
[
%{
price: 1,
fences: num_fences,
points: new_points
}
]
sub_regions ->
connected_regions =
sub_regions
|> Enum.filter(fn %{points: points} ->
Enum.any?(new_points, fn point ->
Enum.member?(points, point)
end)
end)
not_connected_regions = sub_regions -- connected_regions
merged_region =
connected_regions
|> merge_sub_regions()
|> then(fn %{price: price, fences: fences, points: points} ->
%{
price: price + 1,
fences: fences + num_fences,
points: Enum.uniq(new_points ++ points)
}
end)
[merged_region | not_connected_regions]
end
end
defp merge_sub_regions(connected_regions) do
connected_regions
|> Enum.reduce(@initial_region, fn sub_region, acc_sub_region ->
%{
price: acc_sub_region.price + sub_region.price,
fences: acc_sub_region.fences + sub_region.fences,
points: acc_sub_region.points ++ sub_region.points
}
end)
end
end
regions = Regions.get(map)
sum_price = fn regions ->
regions
|> Enum.map(fn {_, sub_regions} ->
sub_regions
|> Enum.map(fn %{price: price, fences: fences} ->
price * fences
end)
|> Enum.sum()
end)
|> Enum.sum()
end
sum_price.(regions)
"""
RRRRIICCFF
RRRRIICCCF
VVRRRCCFFF
VVRCCCJFFF
VVVVCJJCFE
VVIVCCJJEE
VVIIICJJEE
MIIIIIJJEE
MIIISIJEEE
MMMISSJEEE
"""
|> String.trim()
|> parse_map.()
|> Regions.get()
|> IO.inspect()
|> sum_price.()
puzzle_input
|> parse_map.()
|> Regions.get()
|> sum_price.()