Skip to content

Commit

Permalink
Solve 2023/22
Browse files Browse the repository at this point in the history
  • Loading branch information
code-shoily committed Dec 30, 2023
1 parent 72d36b2 commit d852ea4
Show file tree
Hide file tree
Showing 7 changed files with 1,607 additions and 4 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ Note that you can call those commands independently and also set up pre-commit h

Note: All files mentioned above are autogenerated and are created by running `mix update_stats` task.

## :trophy: 287/450
## :trophy: 289/450

| Day | [2015](/lib/2015) | [2016](/lib/2016) | [2017](/lib/2017) | [2018](/lib/2018) | [2019](/lib/2019) | [2020](/lib/2020) | [2021](/lib/2021) | [2022](/lib/2022) | [2023](/lib/2023) |
|:---:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| :star2: | 48 | 22 | 34 | 15 | 15 | 44 | 24 | 45 | 40 |
| :star2: | 48 | 22 | 34 | 15 | 15 | 44 | 24 | 45 | 42 |
| 1 | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: |
| 2 | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: |
| 3 | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: |
Expand All @@ -87,7 +87,7 @@ Note: All files mentioned above are autogenerated and are created by running `mi
| 19 | :1st_place_medal: | | | | | :1st_place_medal: | | :1st_place_medal: | |
| 20 | :1st_place_medal: | | | | | :2nd_place_medal: | | :1st_place_medal: | |
| 21 | :1st_place_medal: | | | | | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | |
| 22 | | | | | | :1st_place_medal: | | :2nd_place_medal: | |
| 22 | | | | | | :1st_place_medal: | | :2nd_place_medal: | :1st_place_medal: |
| 23 | :1st_place_medal: | | :2nd_place_medal: | | | :2nd_place_medal: | | :1st_place_medal: | :1st_place_medal: |
| 24 | :1st_place_medal: | | | | | :2nd_place_medal: | | :1st_place_medal: | :1st_place_medal: |
| 25 | :1st_place_medal: | | | | | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: | :1st_place_medal: |
Expand Down
1 change: 1 addition & 0 deletions difficulties.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ optimize them and update this page with refined and more accurate data.
| 2023/5 | [If You Give A Seed A Fertilizer](https://adventofcode.com/2023/day/5) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: :snowflake: | [day_05.ex](/lib/2023/day_05.ex) | [day_05_test.exs](/test/2023/day_05_test.exs) | [range](/tags.md#range), [gb-tree](/tags.md#gb-tree) |
| 2023/10 | [Pipe Maze](https://adventofcode.com/2023/day/10) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: :snowflake: | [day_10.ex](/lib/2023/day_10.ex) | [day_10_test.exs](/test/2023/day_10_test.exs) | [graph](/tags.md#graph), [graph-traversal](/tags.md#graph-traversal), [needs-improvement](/tags.md#needs-improvement), [not-fast-enough](/tags.md#not-fast-enough) |
| 2023/12 | [Hot Springs](https://adventofcode.com/2023/day/12) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: :snowflake: | [day_12.ex](/lib/2023/day_12.ex) | [day_12_test.exs](/test/2023/day_12_test.exs) | [memoization](/tags.md#memoization), [vector](/tags.md#vector) |
| 2023/22 | [Sand Slabs](https://adventofcode.com/2023/day/22) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: :snowflake: | [day_22.ex](/lib/2023/day_22.ex) | [day_22_test.exs](/test/2023/day_22_test.exs) | [stack](/tags.md#stack), [range](/tags.md#range), [not-fast-enough](/tags.md#not-fast-enough) |
| 2023/23 | [A Long Walk](https://adventofcode.com/2023/day/23) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: :snowflake: | [day_23.ex](/lib/2023/day_23.ex) | [day_23_test.exs](/test/2023/day_23_test.exs) | [graph](/tags.md#graph), [longest-path](/tags.md#longest-path), [slow](/tags.md#slow), [refactor](/tags.md#refactor) |
| 2023/25 | [Snowverload](https://adventofcode.com/2023/day/25) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: :snowflake: | [day_25.ex](/lib/2023/day_25.ex) | [day_25_test.exs](/test/2023/day_25_test.exs) | [graph](/tags.md#graph), [min-cut](/tags.md#min-cut), [probabilistic](/tags.md#probabilistic), [refactor](/tags.md#refactor), [not-fast-enough](/tags.md#not-fast-enough) |

Expand Down
3 changes: 2 additions & 1 deletion lib/2023/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[2015](/lib/2015) | [2016](/lib/2016) | [2017](/lib/2017) | [2018](/lib/2018) | [2019](/lib/2019) | [2020](/lib/2020) | [2021](/lib/2021) | [2022](/lib/2022) | 2023


## :trophy: 40/50
## :trophy: 42/50

| Day | Problem Page | Status | Difficulty | Solution Page | Test Page | Tags |
| :---: | :------: | :---: | :---: | :---: | :---: | :---: |
Expand All @@ -27,6 +27,7 @@
| 15 | [Lens Library](https://adventofcode.com/2023/day/15) | :1st_place_medal: | :snowflake: :snowflake: | [day_15.ex](/lib/2023/day_15.ex) | [day_15_test.exs](/test/2023/day_15_test.exs) | [hash](/tags.md#hash), [ordered-map](/tags.md#ordered-map) |
| 16 | [The Floor Will Be Lava](https://adventofcode.com/2023/day/16) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: | [day_16.ex](/lib/2023/day_16.ex) | [day_16_test.exs](/test/2023/day_16_test.exs) | [grid](/tags.md#grid), [grid-walk](/tags.md#grid-walk), [memoization](/tags.md#memoization) |
| 18 | [Lavaduct Lagoon](https://adventofcode.com/2023/day/18) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: | [day_18.ex](/lib/2023/day_18.ex) | [day_18_test.exs](/test/2023/day_18_test.exs) | [geometry](/tags.md#geometry) |
| 22 | [Sand Slabs](https://adventofcode.com/2023/day/22) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: :snowflake: | [day_22.ex](/lib/2023/day_22.ex) | [day_22_test.exs](/test/2023/day_22_test.exs) | [stack](/tags.md#stack), [range](/tags.md#range), [not-fast-enough](/tags.md#not-fast-enough) |
| 23 | [A Long Walk](https://adventofcode.com/2023/day/23) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: :snowflake: | [day_23.ex](/lib/2023/day_23.ex) | [day_23_test.exs](/test/2023/day_23_test.exs) | [graph](/tags.md#graph), [longest-path](/tags.md#longest-path), [slow](/tags.md#slow), [refactor](/tags.md#refactor) |
| 24 | [Never Tell Me The Odds](https://adventofcode.com/2023/day/24) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: :snowflake: :snowflake: | [day_24.ex](/lib/2023/day_24.ex) | [day_24_test.exs](/test/2023/day_24_test.exs) | [geometry2d](/tags.md#geometry2d), [refactor](/tags.md#refactor) |
| 25 | [Snowverload](https://adventofcode.com/2023/day/25) | :1st_place_medal: | :snowflake: :snowflake: :snowflake: :snowflake: :snowflake: | [day_25.ex](/lib/2023/day_25.ex) | [day_25_test.exs](/test/2023/day_25_test.exs) | [graph](/tags.md#graph), [min-cut](/tags.md#min-cut), [probabilistic](/tags.md#probabilistic), [refactor](/tags.md#refactor), [not-fast-enough](/tags.md#not-fast-enough) |
Expand Down
143 changes: 143 additions & 0 deletions lib/2023/day_22.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
defmodule AdventOfCode.Y2023.Day22 do
@moduledoc """
--- Day 22: Sand Slabs ---
Problem Link: https://adventofcode.com/2023/day/22
Difficulty: xl
Tags: stack range not-fast-enough
"""
alias AdventOfCode.Helpers.{InputReader, Transformers}

def input, do: InputReader.read_from_file(2023, 22)

def run(input \\ input()) do
input
|> parse()
|> supports()
|> then(&{length(free(&1)), disintegrate(&1)})
end

def parse(data \\ input()) do
for {line, i} <- Enum.with_index(Transformers.lines(data)) do
line
|> String.split([",", "~"], trim: true)
|> Enum.map(&String.to_integer/1)
|> Enum.chunk_every(3)
|> Enum.zip_with(fn [a, b] -> Range.new(min(a, b), max(a, b)) end)
|> List.to_tuple()
|> then(fn {x, y, z} -> {to_alpha(i), x, y, z} end)
end
end

defp supports(data), do: data |> drop() |> support()
defp to_alpha(i), do: to_alpha(i, [])
defp to_alpha(i, acc) when i < 26, do: to_string([rem(i, 26) + 65 | acc])
defp to_alpha(i, acc), do: to_alpha(div(i, 26) - 1, [rem(i, 26) + 65 | acc])

defp drop(bricks),
do:
bricks
|> Enum.sort_by(fn {_, _, _, z1.._} -> z1 end)
|> drop([])

defp drop([], settled), do: settled

defp drop([{_, _, _, 1.._} = brick | bricks], settled),
do: drop(bricks, [brick | settled])

defp drop([{id, ax, ay, az} | bricks], settled) do
{_, _, _, _..bz2} =
Enum.filter(settled, fn {_, bx, by, _} ->
not (Range.disjoint?(ax, bx) or
Range.disjoint?(ay, by))
end)
|> Enum.max_by(
fn {_, _, _, _..bz2} -> bz2 end,
fn -> {nil, nil, nil, 0..0} end
)

az1 = bz2 + 1
az2 = bz2 + Range.size(az)
brick = {id, ax, ay, az1..az2}

drop(bricks, [brick | settled])
end

defp support(bricks), do: support(bricks, bricks, %{})
defp support([], _, supports), do: supports

defp support([{_, ax, ay, az1.._} = current | rest], bricks, supports) do
others =
Enum.filter(bricks, fn {_, bx, by, _..bz2} ->
bz2 == az1 - 1 and
not (Range.disjoint?(ax, bx) or
Range.disjoint?(ay, by))
end)

supports =
Map.update(
supports,
current,
%{is_above: others, is_below: []},
fn %{is_above: above} = existing ->
%{existing | is_above: others ++ above}
end
)

supports =
Enum.reduce(others, supports, fn other, supports ->
Map.update(
supports,
other,
%{is_above: [], is_below: [current]},
fn %{is_below: below} = existing ->
%{existing | is_below: [current | below]}
end
)
end)

support(rest, bricks, supports)
end

defp free(supports) do
supports
|> Enum.filter(fn {_, %{is_above: is_above}} -> length(is_above) == 1 end)
|> Enum.flat_map(fn {_, %{is_above: is_above}} -> is_above end)
|> MapSet.new()
|> then(fn required ->
supports
|> Map.keys()
|> MapSet.new()
|> MapSet.difference(required)
|> Enum.to_list()
end)
end

defp chain(brick, supports), do: chain([brick], supports, MapSet.new())
defp chain([], _, acc), do: acc

defp chain([brick | rest], supports, acc) do
destroyed =
supports[brick].is_below
|> Enum.filter(fn above_brick ->
below_bricks = supports[above_brick].is_above

length(below_bricks) == 1 or
Enum.all?(below_bricks, fn below -> MapSet.member?(acc, below) end)
end)

destroyed
|> MapSet.new()
|> MapSet.union(acc)
|> then(fn acc -> chain(rest ++ destroyed, supports, acc) end)
end

defp disintegrate(supports) do
for brick <- Map.keys(supports), reduce: 0 do
acc ->
brick
|> chain(supports)
|> MapSet.size()
|> Kernel.+(acc)
end
end
end
Loading

0 comments on commit d852ea4

Please sign in to comment.