summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Jesus <adbjesus@gmail.com>2024-12-12 21:49:50 +0000
committerAlexandre Jesus <adbjesus@gmail.com>2024-12-12 21:49:50 +0000
commit65851ff53bead21b288a093620824578f501f637 (patch)
tree782a424e52af602e2eee30dad687c13edcd30cae
parent60a8ca5849b0d4cb50d77b34a3b8ab2259ccf7a9 (diff)
downloadaoc2024-65851ff53bead21b288a093620824578f501f637.tar.gz
aoc2024-65851ff53bead21b288a093620824578f501f637.zip
Day 12
-rw-r--r--src/day12.exs132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/day12.exs b/src/day12.exs
new file mode 100644
index 0000000..522bb39
--- /dev/null
+++ b/src/day12.exs
@@ -0,0 +1,132 @@
+defmodule Day12 do
+ def part1(data) do
+ grid = data
+ |> String.split("\n", trim: true)
+ |> Enum.map(&String.codepoints/1)
+
+ grid = for {l, i} <- Enum.with_index(grid),
+ {c, j} <- Enum.with_index(l) do
+ {{i, j}, c}
+ end
+ |> Map.new()
+
+ for pos <- Map.keys(grid), reduce: {MapSet.new(), 0} do
+ {vis, res} -> solve1(vis, grid, pos)
+ |> then(fn {vis, a, p} -> {vis, res + a*p} end)
+ end
+ |> elem(1)
+ end
+
+ defp solve1(vis, grid, pos) do
+ if MapSet.member?(vis, pos) do
+ {vis, 0, 0}
+ else
+ for npos <- dirs(pos), reduce: {MapSet.put(vis, pos), 1, 0} do
+ {vis, a, p} ->
+ case Map.fetch(grid, npos) do
+ :error ->
+ {vis, a, p+1}
+ {_, v} ->
+ if v == Map.fetch!(grid, pos) do
+ {vis, na, np} = solve1(vis, grid, npos)
+ {vis, a+na, p+np}
+ else
+ {vis, a, p+1}
+ end
+ end
+ end
+ end
+ end
+
+ defp dirs({i, j}) do
+ [{i+1, j}, {i-1, j}, {i, j+1}, {i, j-1}]
+ end
+
+ def part2(data) do
+ grid = data
+ |> String.split("\n", trim: true)
+ |> Enum.map(&String.codepoints/1)
+
+ grid = for {l, i} <- Enum.with_index(grid),
+ {c, j} <- Enum.with_index(l) do
+ {{i, j}, c}
+ end
+ |> Map.new()
+
+ for pos <- Map.keys(grid), reduce: {MapSet.new(), 0} do
+ {vis, res} -> solve2(vis, grid, pos)
+ |> then(fn {vis, a, walls} -> {vis, res + a*perim(walls)} end)
+ end
+ |> elem(1)
+ end
+
+ defp solve2(vis, grid, pos) do
+ if MapSet.member?(vis, pos) do
+ {vis, 0, []}
+ else
+ for {npos, dir} <- dirs2(pos), reduce: {MapSet.put(vis, pos), 1, []} do
+ {vis, a, walls} ->
+ case Map.fetch(grid, npos) do
+ :error ->
+ {vis, a, [{dir, npos} | walls]}
+ {_, v} ->
+ if v == Map.fetch!(grid, pos) do
+ {vis, na, nwalls} = solve2(vis, grid, npos)
+ {vis, a+na, walls ++ nwalls}
+ else
+ {vis, a, [{dir, npos} | walls]}
+ end
+ end
+ end
+ end
+ end
+
+ defp dirs2({i, j}) do
+ [{{i+1, j}, :down},
+ {{i-1, j}, :up},
+ {{i, j+1}, :right},
+ {{i, j-1}, :left}]
+ end
+
+ defp dist({a, b}, {c, d}), do: abs(a-c) + abs(b-d)
+ defp dist(_, nil), do: nil
+ defp dist(nil, _), do: nil
+
+ defp perim([]), do: 0
+
+ defp perim(walls) do
+ gwalls = walls
+ |> Enum.group_by(&elem(&1,0), &elem(&1,1))
+
+ for {dir, walls} <- gwalls do
+ swalls =
+ cond do
+ dir == :up or dir == :down ->
+ Enum.sort(walls)
+ true ->
+ Enum.sort_by(walls, fn {i, j} -> {j, i} end)
+ end
+
+ for w <- swalls, reduce: {nil, 0} do
+ {prev, acc} ->
+ if dist(w, prev) == 1 do
+ {w, acc}
+ else
+ {w, acc+1}
+ end
+ end
+ |> elem(1)
+ end
+ |> Enum.sum()
+ end
+end
+
+data = IO.read(:stdio, :eof)
+
+{time1 , ans1} = :timer.tc(fn -> Day12.part1(data) end)
+IO.puts("Time : #{time1 / 1000000}")
+IO.puts("Answer: #{ans1}")
+
+{time2 , ans2} = :timer.tc(fn -> Day12.part2(data) end)
+IO.puts("Time : #{time2 / 1000000}")
+IO.puts("Answer: #{ans2}")