Powered by AppSignal & Oban Pro

Day 8

2022/day08.livemd

Day 8

Mix.install([:kino, :arrays])

Input

input = Kino.Input.textarea("")

Pre-work

defmodule Trees do
  def new(input), do: input |> String.split() |> Enum.into(Arrays.new(), &parse_trees_row/1)

  def count_visible_from(trees, i, j, y_range, x_range) do
    Enum.reduce_while(y_range, {0, true}, fn ii, {cnt, _} ->
      {cnt, visible} =
        Enum.reduce_while(x_range, {cnt, true}, fn jj, {cnt, _} ->
          if trees[ii][jj] < trees[i][j] do
            {:cont, {cnt + 1, true}}
          else
            {:halt, {cnt + 1, false}}
          end
        end)

      {if(visible, do: :cont, else: :halt), {cnt, visible}}
    end)
  end

  defp parse_trees_row(str) do
    str |> String.split("", trim: true) |> Enum.into(Arrays.new(), &amp;String.to_integer/1)
  end
end

trees = input |> Kino.Input.read() |> Trees.new()
height = Arrays.size(trees)
width = Arrays.size(trees[0])

{max_score, visibles} =
  Enum.reduce(0..(height - 1), {0, 0}, fn i, {max_score, visibles} ->
    Enum.reduce(0..(width - 1), {max_score, visibles}, fn j, {max_score, visibles} ->
      {l, l_v} = Trees.count_visible_from(trees, i, j, i..i, (j - 1)..0//-1)
      {r, r_v} = Trees.count_visible_from(trees, i, j, i..i, (j + 1)..(width - 1)//1)
      {u, u_v} = Trees.count_visible_from(trees, i, j, (i - 1)..0//-1, j..j)
      {d, d_v} = Trees.count_visible_from(trees, i, j, (i + 1)..(height - 1)//1, j..j)
      {max(max_score, l * r * u * d), visibles + if(l_v or r_v or u_v or d_v, do: 1, else: 0)}
    end)
  end)

Part 1

visibles

Part 2

max_score