Powered by AppSignal & Oban Pro

Advent of code - Day 8

day_8.livemd

Advent of code - Day 8

Mix.install(
  [
    {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"}
  ],
  force: true
)

Section

{:ok, puzzle_input} = KinoAOC.download_puzzle("2022", "8", System.fetch_env!("LB_SESSION"))
input = """
30373
25512
65332
33549
35390
"""

trees =
  input
  |> String.split("\n", trim: true)
  |> Enum.map(fn row -> String.graphemes(row) |> Enum.map(fn t -> String.to_integer(t) end) end)
defmodule A do
  def a(forest, default, func) do
    height = length(forest)
    width = length(Enum.at(forest, 0))

    0..(height - 1)
    |> Enum.map(fn i ->
      Enum.map(
        0..(width - 1),
        fn j ->
          a(i, j, forest, height, width, default, func)
        end
      )
    end)
  end

  def a(_, 0, _, _, _, default, _), do: default
  def a(0, _, _, _, _, default, _), do: default
  def a(_, j, _, _, width, default, _) when j == width - 1, do: default
  def a(i, _, _, height, _, default, _) when i == height - 1, do: default

  def a(i, j, forest, height, width, _, func) do
    tree = get_tree({i, j}, forest)
    left = for x <- 0..(j - 1), do: {i, x}
    right = for x <- (j + 1)..(width - 1), do: {i, x}

    top = for y <- 0..(i - 1), do: {y, j}
    bottom = for y <- (i + 1)..(height - 1), do: {y, j}

    func.([left, right, top, bottom], tree)
  end

  def get_tree({i, j}, forest), do: forest |> Enum.at(i) |> Enum.at(j)
end
f = fn l, tree ->
  Enum.any?(
    l,
    fn r -> Enum.all?(r, fn t -> A.get_tree(t, trees) < tree end) end
  )
end

f3 = fn l, tree ->
  Enum.reduce(l, 1, fn r, acc ->
    acc *
      (r
       |> Enum.find_index(fn x -> A.get_tree(x, trees) >= tree end)
       |> case do
         nil -> length(r)
         i -> i + 1
       end)
  end)
end

f2 = fn [left, right, top, bottom], tree ->
  f3.([Enum.reverse(left), right, Enum.reverse(top), bottom], tree)
end

A.a(trees, true, f)
defmodule Traverse do
  def t(trees, start_acc, scanner, reducer) do
    height = length(trees)
    width = length(Enum.at(trees, 0))

    [l1, l2] =
      Enum.map(
        [{0..(height - 1), 0..(width - 1)}, {0..(height - 1), (width - 1)..0}],
        fn r -> traverse(r, trees, &amp;hget/3, start_acc, scanner) end
      )

    [l3, l4] =
      Enum.map(
        [{0..(width - 1), 0..(height - 1)}, {0..(width - 1), (height - 1)..0}],
        fn r -> traverse(r, trees, &amp;vget/3, start_acc, scanner) end
      )

    IO.inspect(l2)

    Stream.map(
      0..(height - 1),
      fn i ->
        Stream.map(
          0..(width - 1),
          fn j ->
            Enum.reduce(
              [
                hget(i, j, l1),
                hget(i, width - 1 - j, l2),
                hget(j, i, l3),
                hget(j, height - 1 - i, l4)
              ],
              reducer
            )
          end
        )
      end
    )
  end

  def hget(i, j, trees),
    do:
      trees
      |> Enum.at(i)
      |> Enum.at(j)

  def vget(i, j, trees),
    do:
      trees
      |> Enum.at(j)
      |> Enum.at(i)

  def traverse({is, js}, trees, getter, start_acc, scanner) do
    Enum.map(
      is,
      fn i ->
        Enum.scan(js, start_acc, fn j, {max_height, _} ->
          x = getter.(i, j, trees)

          scanner.(i, x, max_height)
        end)
      end
    )
    |> Enum.map(fn line ->
      Enum.map(line, fn {_, r} -> r end)
    end)
  end

  def part1(trees) do
    t(
      trees,
      {-1, false},
      &amp;is_max_height/3,
      &amp;Kernel.or/2
    )
    |> Stream.flat_map(&amp;Function.identity/1)
    |> Stream.filter(&amp;Function.identity/1)
    |> Enum.count()
  end

  def is_max_height(_i, x, max_height) when x > max_height, do: {x, true}
  def is_max_height(_i, _x, max_height), do: {max_height, false}

  def part2(trees) do
    t(
      trees,
      {-1, 0},
      &amp;visibility/3,
      &amp;Kernel.*/2
    )
    |> Enum.to_list()
    |> Enum.map(&amp;Enum.to_list/1)

    # |> Stream.flat_map(&Function.identity/1)
    # |> Enum.max()
  end

  def visibility(0, x, _max_height), do: {x, 1}
  def visibility(i, x, max_height) when x > max_height, do: {x, i - 1}
  def visibility(_i, _x, max_height), do: {max_height, 1}
end

Traverse.part2(trees)