-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathday_14.ex
72 lines (60 loc) · 1.94 KB
/
day_14.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
defmodule AdventOfCode.Y2022.Day14 do
@moduledoc """
--- Day 14: Regolith Reservoir ---
Problem Link: https://adventofcode.com/2022/day/14
Difficulty: l
Tags: live-book visualized slow flood-fill unfold
"""
alias AdventOfCode.Helpers.{InputReader, Transformers}
@source {500, 0}
def input, do: InputReader.read_from_file(2022, 14)
def run(input \\ input()) do
input = parse(input)
run_1 = Task.async(fn -> Enum.count(endless_sands(input)) end)
run_2 = Task.async(fn -> Enum.count(floored_sands(input)) end)
{Task.await(run_1, :infinity), Task.await(run_2, :infinity)}
end
def parse(path) do
path
|> Transformers.lines()
|> Enum.flat_map(fn line ->
line
|> String.split(" -> ")
|> Enum.map(fn coords ->
coords
|> Transformers.words(",")
|> Enum.map(&String.to_integer/1)
end)
|> then(fn [_ | tail] = coords -> Enum.zip([coords, tail]) end)
|> Enum.flat_map(fn
{[a, x], [a, y]} -> Enum.map(x..y, &{a, &1})
{[x, b], [y, b]} -> Enum.map(x..y, &{&1, b})
end)
end)
|> MapSet.new()
end
defp endless_sands(input) do
floor = Enum.max_by(input, &elem(&1, 1)) |> elem(1)
Stream.unfold(input, &fall(&1, floor, @source))
end
defp floored_sands(input) do
floor = Enum.max_by(input, &elem(&1, 1)) |> elem(1) |> Kernel.+(2)
state = (-floor - 1)..(floor + 1) |> Stream.map(&{500 + &1, floor}) |> Enum.into(input)
Stream.unfold(state, &fall(&1, floor, @source))
end
defp fall(state, floor, {x, y} = sand) do
case MapSet.member?(state, @source) do
false ->
down = {x, y + 1}
left = {x - 1, y + 1}
right = {x + 1, y + 1}
case Enum.find([down, left, right], &(!MapSet.member?(state, &1))) do
nil -> {state, MapSet.put(state, sand)}
{_, y} when y > floor -> nil
air -> fall(state, floor, air)
end
true ->
nil
end
end
end