|
|
|
@ -2,11 +2,22 @@ |
|
|
|
|
|
|
|
-export([solve/1]). |
|
|
|
|
|
|
|
-compile(export_all). |
|
|
|
|
|
|
|
solve(Input) -> |
|
|
|
Grid = parse_grid(Input), |
|
|
|
{map_size(visible_trees(Grid)), none}. |
|
|
|
{map_size(visible_trees(Grid)), scenery(Grid)}. |
|
|
|
|
|
|
|
|
|
|
|
scenery({_, H, W} = Grid) -> |
|
|
|
Visible0 = #{}, |
|
|
|
%Left |
|
|
|
Visible1 = range_fold(0, H-1, fun(Row, Acc) -> element(2, grid_traverse(fun scenery_score/3, {[], Acc}, Grid, {0, Row}, {1, 0})) end, Visible0), |
|
|
|
%Right |
|
|
|
Visible2 = range_fold(0, H-1, fun(Row, Acc) -> element(2, grid_traverse(fun scenery_score/3, {[], Acc}, Grid, {W-1, Row}, {-1, 0})) end, Visible1), |
|
|
|
%Top |
|
|
|
Visible3 = range_fold(0, W-1, fun(Col, Acc) -> element(2, grid_traverse(fun scenery_score/3, {[], Acc}, Grid, {Col, 0}, {0, 1})) end, Visible2), |
|
|
|
%Bottom |
|
|
|
Visible4 = range_fold(0, W-1, fun(Col, Acc) -> element(2, grid_traverse(fun scenery_score/3, {[], Acc}, Grid, {Col, H-1}, {0, -1})) end, Visible3), |
|
|
|
lists:max(maps:values(Visible4)). |
|
|
|
|
|
|
|
visible_trees({_, H, W} = Grid) -> |
|
|
|
%top |
|
|
|
@ -23,6 +34,16 @@ visible_trees({_, H, W} = Grid) -> |
|
|
|
visible_path(Tree, Position, {MaxHeight, Visible}) when Tree > MaxHeight -> {Tree, Visible#{Position => []}}; |
|
|
|
visible_path(_Tree, _Position, State) -> State. |
|
|
|
|
|
|
|
% horrible name, calculate the view distance in one direction |
|
|
|
tree_stack(_Tree, []) -> 0; |
|
|
|
tree_stack(Tree, [Other|_Rest]) when Other >= Tree -> 1; |
|
|
|
tree_stack(Tree, [_Other|Rest]) -> tree_stack(Tree, Rest) + 1. |
|
|
|
|
|
|
|
scenery_score(Tree, Position, {TreeStack, Trees}) -> |
|
|
|
Distance = tree_stack(Tree, TreeStack), |
|
|
|
NewTrees = Trees#{Position => Distance * maps:get(Position, Trees, 1)}, |
|
|
|
{[Tree|TreeStack], NewTrees}. |
|
|
|
|
|
|
|
grid_traverse(Fun, AccIn, Grid, {XPos, YPos}, {XVec, YVec}) -> |
|
|
|
case grid_at(Grid, XPos, YPos) of |
|
|
|
error -> AccIn; |
|
|
|
|