diff --git a/2021/README.md b/2021/README.md index 440a86a..ffac725 100644 --- a/2021/README.md +++ b/2021/README.md @@ -15,7 +15,7 @@ | S | M | T | W | T | F | S | | :-: | :-: | :-: | :-: | :-: | :-: | :-: | | | | | [1] | [2] | [3] | [4] | -| [5] | [6] | [7] | [8] | 9 | 10 | 11 | +| [5] | [6] | [7] | [8] | [9] | 10 | 11 | | 12 | 13 | 14 | 15 | 16 | 17 | 18 | | 19 | 20 | 21 | 22 | 23 | 24 | 25 | @@ -29,3 +29,4 @@ [6]: ./lib/2021/6.ex [7]: ./lib/2021/7.ex [8]: ./lib/2021/8.ex +[9]: ./lib/2021/9.ex diff --git a/2021/lib/2021/9.ex b/2021/lib/2021/9.ex new file mode 100644 index 0000000..bed7b87 --- /dev/null +++ b/2021/lib/2021/9.ex @@ -0,0 +1,89 @@ +import AOC + +aoc 2021, 9 do + def input_map(), + do: + input_string() + |> String.split("\n") + |> Enum.with_index() + |> Enum.flat_map(fn {line, i} -> + line + |> String.split("", trim: true) + |> Enum.map(&String.to_integer/1) + |> Enum.with_index() + |> Enum.map(fn {cell, j} -> {{i, j}, cell} end) + end) + |> Map.new() + + def n({i, j}), do: {i - 1, j} + def e({i, j}), do: {i, j + 1} + def s({i, j}), do: {i + 1, j} + def w({i, j}), do: {i, j - 1} + + def at(map, pos), do: Map.get(map, pos, :infinity) + + def directions(), do: [&n/1, &e/1, &s/1, &w/1] + + def neighbors(map, origin) do + for d <- directions(), pos = d.(origin) do + {pos, at(map, pos)} + end + end + + def gt({_, a}, b), do: a > b + + def basin_from(map, pos, seen \\ MapSet.new()) do + curr = at(map, pos) + + if min(curr, 9) == 9 do + MapSet.new() + else + seen = MapSet.put(seen, pos) + + inclines = + neighbors(map, pos) + |> Enum.filter(>(&1, curr)) + |> Enum.map(&elem(&1, 0)) + + for inc <- inclines, reduce: seen do + seen -> + if MapSet.member?(seen, inc) do + seen + else + MapSet.union(seen, basin_from(map, inc, seen)) + end + end + end + end + + def p1 do + map = input_map() + + for i <- 0..99, j <- 0..99 do + pos = {i, j} + curr = at(map, pos) + + neighbors = + directions() + |> Enum.map(fn d -> at(map, d.(pos)) end) + + if Enum.all?(neighbors, &(curr < &1)) do + curr + 1 + else + 0 + end + end + |> Enum.sum() + end + + def p2 do + map = input_map() + + for i <- 0..99, j <- 0..99, pos = {i, j} do + basin_from(map, pos) |> MapSet.size() + end + |> Enum.sort(:desc) + |> Enum.take(3) + |> Enum.product() + end +end