AOC 2022-08 (Treetop Tree House)

Mix.install([
  {:kino, "~> 0.7.0"}
])

Input

input = Kino.Input.textarea("Input")
input =
  input
  |> Kino.Input.read()
  |> String.split()

grid =
  input
  |> Enum.with_index()
  |> Enum.reduce(%{}, fn {line, row}, acc ->
    line
    |> String.graphemes()
    |> Enum.with_index()
    |> Enum.reduce(acc, fn {height, col}, acc2 ->
      Map.put(acc2, {row, col}, String.to_integer(height))
    end)
  end)

Part 1

Pending refactor...

Part 2

defmodule Grid2 do
  @grid_size 99

  def find_best_tree_in(grid) do
    grid
    |> Enum.map(fn {{row, col}, height} ->
      all_candidates(row, col)
      |> Enum.map(&score(grid, &1, height))
      |> Enum.product()
    end)
    |> Enum.max()
  end

  defp all_candidates(row, col) do
    [
      north_candidates(row, col),
      south_candidates(row, col),
      west_candidates(row, col),
      east_candidates(row, col)
    ]
  end

  defp north_candidates(row, col) do
    Enum.map((row - 1)..0, fn r -> {r, col} end)
  end

  defp south_candidates(row, col) do
    Enum.map((row + 1)..(@grid_size - 1), fn r -> {r, col} end)
  end

  defp west_candidates(row, col) do
    Enum.map((col - 1)..0, fn c -> {row, c} end)
  end

  defp east_candidates(row, col) do
    Enum.map((col + 1)..(@grid_size - 1), fn c -> {row, c} end)
  end

  def score(grid, partial_row_or_col, height) do
    candidates = Enum.map(partial_row_or_col, &height_for_location(grid, &1))

    case Enum.find_index(candidates, fn h -> h >= height end) do
      nil -> Enum.count(candidates)
      other -> other + 1
    end
  end

  defp height_for_location(grid, loc), do: Map.get(grid, loc, 1000)
end

Grid2.find_best_tree_in(grid)