|
|
@ -3,11 +3,25 @@ |
|
|
-export([solve/1]). |
|
|
-export([solve/1]). |
|
|
|
|
|
|
|
|
solve(Input) -> |
|
|
solve(Input) -> |
|
|
{part1(Input), none}. |
|
|
|
|
|
|
|
|
{part1(Input), part2(Input)}. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
part1(Input) -> simulate(parse_map(Input), 0). |
|
|
part1(Input) -> simulate(parse_map(Input), 0). |
|
|
|
|
|
|
|
|
|
|
|
part2(Input) -> |
|
|
|
|
|
simulate(parse_map2(Input), 0). |
|
|
|
|
|
|
|
|
|
|
|
parse_map2(Input) -> |
|
|
|
|
|
LineSegments = parse_instructions(Input), |
|
|
|
|
|
FloorDepth = y_max(LineSegments, 0) + 2, |
|
|
|
|
|
FlooredLineSegments = [{{500 - FloorDepth, FloorDepth}, {500 + FloorDepth, FloorDepth}} | LineSegments], |
|
|
|
|
|
ChoppedSegments = chop_segments(FlooredLineSegments, []), |
|
|
|
|
|
SegmentMap = maps:groups_from_list(fun({X, _, _}) -> X end, fun({_X, YStart, YEnd}) -> {YStart, YEnd} end, ChoppedSegments), |
|
|
|
|
|
maps:map(fun (_Key, Segments) -> lists:foldl(fun rset_append/2, rset_new(), Segments) end, SegmentMap). |
|
|
|
|
|
|
|
|
|
|
|
y_max([], Max) -> Max; |
|
|
|
|
|
y_max([{{_, Y1},{_,Y2}}|Rest], Max) -> y_max(Rest, max(max(Y1, Y2), Max)). |
|
|
|
|
|
|
|
|
parse_map(Input) -> |
|
|
parse_map(Input) -> |
|
|
LineSegments = parse_instructions(Input), |
|
|
LineSegments = parse_instructions(Input), |
|
|
ChoppedSegments = chop_segments(LineSegments, []), |
|
|
ChoppedSegments = chop_segments(LineSegments, []), |
|
|
@ -45,6 +59,7 @@ chop_segments([{{X1, Y}, {X2, Y}} | Rest], Acc) -> chop_segments(Rest, [{X, Y, Y |
|
|
|
|
|
|
|
|
simulate(State, SandCount) -> |
|
|
simulate(State, SandCount) -> |
|
|
case attempt_place(State, {500, 0}) of |
|
|
case attempt_place(State, {500, 0}) of |
|
|
|
|
|
{500, 0} -> SandCount + 1; |
|
|
{X, Y} -> simulate(State#{X := rset_append({Y, Y}, maps:get(X, State))}, SandCount+1); |
|
|
{X, Y} -> simulate(State#{X := rset_append({Y, Y}, maps:get(X, State))}, SandCount+1); |
|
|
falling -> SandCount |
|
|
falling -> SandCount |
|
|
end. |
|
|
end. |
|
|
@ -83,15 +98,7 @@ rset_append({_, End} = Entry, [{HeadStart, _} | _] = Set) when End < HeadStart - |
|
|
rset_append({Start, _} = Entry, [{_, HeadEnd} = Head | Rest]) when Start > HeadEnd + 1 -> [ Head | rset_append(Entry, Rest)]; |
|
|
rset_append({Start, _} = Entry, [{_, HeadEnd} = Head | Rest]) when Start > HeadEnd + 1 -> [ Head | rset_append(Entry, Rest)]; |
|
|
rset_append({Start, End}, [{HeadStart, HeadEnd} | Rest]) -> rset_append({min(Start, HeadStart), max(End, HeadEnd)}, Rest). |
|
|
rset_append({Start, End}, [{HeadStart, HeadEnd} | Rest]) -> rset_append({min(Start, HeadStart), max(End, HeadEnd)}, Rest). |
|
|
|
|
|
|
|
|
rset_contains(Item, []) -> false; |
|
|
|
|
|
rset_contains(Item, [{Start, _}|Rest]) when Item < Start -> false; |
|
|
|
|
|
|
|
|
rset_contains(_Item, []) -> false; |
|
|
|
|
|
rset_contains(Item, [{Start, _}|_Rest]) when Item < Start -> false; |
|
|
rset_contains(Item, [{_, End}|Rest]) when Item > End -> rset_contains(Item, Rest); |
|
|
rset_contains(Item, [{_, End}|Rest]) when Item > End -> rset_contains(Item, Rest); |
|
|
rset_contains(_Item, _Rest) -> true. |
|
|
rset_contains(_Item, _Rest) -> true. |
|
|
|
|
|
|
|
|
rset_remove1(_Point, []) -> []; |
|
|
|
|
|
rset_remove1(Point, [{Start, _End} | _Rest] = Set) when Point < Start -> Set; |
|
|
|
|
|
rset_remove1(Point, [{_Start, End} = Head | Rest]) when Point > End -> [Head | rset_remove1(Point, Rest)]; |
|
|
|
|
|
rset_remove1(Point, [{Point, Point} | Rest]) -> Rest; |
|
|
|
|
|
rset_remove1(Point, [{Point, End} | Rest]) -> [{Point+1, End} | Rest]; |
|
|
|
|
|
rset_remove1(Point, [{Start, Point} | Rest]) -> [{Start, Point-1} | Rest]; |
|
|
|
|
|
rset_remove1(Point, [{Start, End} | Rest]) -> [{Start, Point-1}, {Point+1, End} | Rest]. |
|
|
|