Day 12
Setup
input =
System.fetch_env!("LB_AOC_DIR")
|> Path.join("data/day12.txt")
|> File.read!()
nil
nil
Solve
defmodule Day12 do
@directions [
{0, 1},
{0, -1},
{1, 0},
{-1, 0}
]
def parse(input) do
for {row, i} <- Enum.with_index(String.split(input, "\n")),
row != "",
{item, j} <- Enum.with_index(String.codepoints(row)),
into: %{} do
{{i, j}, item}
end
end
def flood({i, j} = current, board, group) do
for {di, dj} <- @directions,
Map.get(board, current) == Map.get(board, {i + di, j + dj}),
!MapSet.member?(group, {i + di, j + dj}),
reduce: group do
acc ->
group = MapSet.put(acc, {i + di, j + dj})
flood({i + di, j + dj}, board, group)
end
end
defp perimeter(region, board) do
for {i, j} <- region, {di, dj} <- @directions, reduce: 0 do
sum ->
if Map.get(board, {i, j}) == Map.get(board, {i + di, j + dj}), do: sum, else: sum + 1
end
end
def sides(region, board) do
all_sides =
for {i, j} <- region, {di, dj} <- @directions, reduce: MapSet.new() do
s ->
if Map.get(board, {i, j}) == Map.get(board, {i + di, j + dj}) do
s
else
MapSet.put(s, {{i, j}, {di, dj}})
end
end
for {i, j} <- region,
{{^i, ^j}, {di, dj} = direction} <-
MapSet.filter(all_sides, &match?({{^i, ^j}, _direction}, &1)),
reduce: 0 do
sum ->
if MapSet.member?(all_sides, {{i - abs(dj), j - abs(di)}, direction}),
do: sum,
else: sum + 1
end
end
def regions(board) do
for space <- Map.keys(board), reduce: [] do
groups ->
if Enum.any?(groups, &MapSet.member?(&1, space)) do
groups
else
[flood(space, board, MapSet.new([space])) | groups]
end
end
end
@doc ~S"""
iex> Day12.part1("RRRRIICCFF\nRRRRIICCCF\nVVRRRCCFFF\nVVRCCCJFFF\nVVVVCJJCFE\nVVIVCCJJEE\nVVIIICJJEE\nMIIIIIJJEE\nMIIISIJEEE\nMMMISSJEEE\n")
1930
"""
def part1(input) do
board =
parse(input)
regions(board)
|> Enum.reduce(
0,
fn region, sum ->
sum + Enum.count(region) * perimeter(region, board)
end
)
end
@doc ~S"""
iex> Day12.part2("RRRRIICCFF\nRRRRIICCCF\nVVRRRCCFFF\nVVRCCCJFFF\nVVVVCJJCFE\nVVIVCCJJEE\nVVIIICJJEE\nMIIIIIJJEE\nMIIISIJEEE\nMMMISSJEEE\n")
1206
"""
def part2(input) do
board =
parse(input)
regions(board)
|> Enum.reduce(
0,
fn region, sum ->
sum + Enum.count(region) * sides(region, board)
end
)
end
end
{:module, Day12, <<70, 79, 82, 49, 0, 0, 27, ...>>, {:part2, 1}}