Day 8
Section
test_input = """
30373
25512
65332
33549
35390
"""
defmodule Day8 do
def run(input) do
rows = input |> String.split()
size = Enum.count(rows)
rows
|> Enum.with_index()
|> Enum.flat_map(fn {str, row} ->
trees = str |> String.graphemes()
trees
|> Enum.with_index()
|> Enum.map(fn {tree_height, col} ->
{{col, row}, {String.to_integer(tree_height), is_edge(size, row, col)}}
end)
end)
|> Map.new()
|> count_visibility(size)
end
def run2(input) do
rows = input |> String.split()
num_y = Enum.count(rows)
num_x = List.first(rows) |> String.graphemes() |> Enum.count()
rows
|> Enum.with_index()
|> Enum.flat_map(fn {str, y} ->
trees = str |> String.graphemes()
trees
|> Enum.with_index()
|> Enum.map(fn {tree_height, x} ->
{{x, y}, String.to_integer(tree_height)}
end)
end)
|> Map.new()
|> find_scenic(num_x, num_y)
end
def find_scenic(m, max_rows, max_cols) do
Enum.reduce(m, 0, fn {{x, y}, _} = tree, acc ->
# get tree coords left, right, up, down
left =
for l <- (x - 1)..0 do
{l, y}
end
right =
for l <- (x + 1)..max_cols do
{l, y}
end
up =
for l <- (y - 1)..0 do
{x, l}
end
down =
for l <- (y + 1)..max_rows do
{x, l}
end
# count in each direction
left = process_vis(m, left, tree)
right = process_vis(m, right, tree)
up = process_vis(m, up, tree)
down = process_vis(m, down, tree)
result = left * right * up * down
if(result > acc) do
result
else
acc
end
end)
end
def process_vis(map, list_of_coords, {{x, y}, h}) do
list_of_coords
|> Enum.reduce_while(0, fn {px, py}, count ->
if({x, y} == {px, py}) do
{:halt, count}
else
tree_height = Map.get(map, {px, py})
case(tree_height) do
# generated a coord not in our map
nil -> {:cont, count}
x when x < h -> {:cont, count + 1}
_ -> {:halt, count + 1}
end
end
end)
end
def count_visibility(m, max) do
m
|> Enum.reduce(0, fn {{x, y}, {height, already_visible}}, acc ->
if already_visible do
acc + 1
else
up_coords =
for up <- 0..(x - 1) do
{up, y}
end
down_coords =
for down <- (x + 1)..max do
{down, y}
end
left_coords =
for l <- 0..(y - 1) do
{x, l}
end
right_coords =
for r <- (y + 1)..max do
{x, r}
end
u =
Map.take(m, up_coords)
|> Enum.all?(fn {_, {h, _}} -> h < height end)
d =
Map.take(m, down_coords)
|> Enum.all?(fn {_, {h, _}} -> h < height end)
left =
Map.take(m, left_coords)
|> Enum.all?(fn {_, {h, _}} -> h < height end)
right =
Map.take(m, right_coords)
|> Enum.all?(fn {_, {h, _}} -> h < height end)
if u or d or left or right do
acc + 1
else
acc
end
end
end)
end
def is_edge(_, row, _) when row == 0, do: true
def is_edge(_, _, col) when col == 0, do: true
def is_edge(max, _, col) when col == max - 1, do: true
def is_edge(max, row, _) when row == max - 1, do: true
def is_edge(_, _, _), do: false
end
path = "Projects/aoc/2022/day8.txt"
input = File.read!(path)
Day8.run(input) |> IO.inspect()
Day8.run2(input)