Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 09

books/aoc/2022/09.livemd

Day 09

Mix.install([
  {:kino, "~> 0.8.0"},
  {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"}
])
:ok

Input

{:ok, result} = KinoAOC.download_puzzle("2022", "9", System.fetch_env!("LB_AOC_SESSION"))
input = result
"R 2\nD 2\nU 2\nD 1\nL 1\nD 2\nR 2\nL 2\nR 1\nD 2\nL 1\nU 2\nR 1\nD 1\nR 1\nL 1\nD 1\nR 2\nU 2\nL 2\nR 2\nU 2\nR 1\nL 1\nD 2\nR 1\nD 1\nR 1\nD 1\nR 1\nL 2\nR 1\nD 1\nL 1\nU 2\nL 1\nD 1\nL 1\nR 1\nU 2\nD 1\nU 2\nL 2\nR 2\nD 1\nL 1\nR 1\nD 1\nL 1\nU 1\nR 2\nD 1\nR 1\nD 2\nL 1\nD 2\nL 1\nD 2\nR 1\nL 1\nD 2\nL 1\nR 1\nD 2\nL 2\nR 2\nL 1\nU 2\nR 1\nU 2\nR 2\nU 1\nD 1\nU 2\nL 1\nD 2\nL 2\nR 2\nL 1\nR 1\nU 2\nD 1\nR 1\nL 2\nU 1\nD 2\nU 1\nL 2\nR 2\nD 1\nU 1\nL 2\nU 2\nL 1\nR 1\nD 1\nR 2\nD 1\nR 1\nD 2\nR 1\nD 1\nR 1\nD 2\nL 2\nU 2\nL 1\nD 1\nL 1\nR 2\nU 1\nD 1\nU 2\nL 2\nD 3\nL 3\nU 3\nR 1\nD 3\nR 1\nD 3\nR 2\nD 2\nU 3\nD 2\nL 3\nR 3\nU 3\nR 1\nU 3\nD 3\nL 1\nD 2\nU 1\nR 2\nL 2\nR 3\nL 2\nD 3\nL 2\nR 1\nD 1\nU 1\nD 2\nR 2\nL 1\nU 1\nR 3\nU 2\nD 3\nL 3\nU 2\nL 3\nR 2\nD 2\nU 2\nR 1\nU 3\nR 2\nD 1\nU 2\nD 3\nU 2\nR 3\nU 2\nL 3\nU 3\nD 2\nR 3\nU 3\nL 3\nU 2\nL 1\nD 3\nL 2\nD 3\nR 3\nL 2\nR 3\nD 1\nU 1\nL 3\nR 3\nD 2\nL 3\nU 2\nR 2\nU 1\nR 3\nD 3\nR 1\nU 2\nL 2\nU 1\nR 1\nU 1\nD 2\nL 2\nR 1\nD 3\nR 1\nD 3\nU 1\nR 2\nU 2\nL 2\nU 2\nL 3\nD 3\nU 2\nL 3\nU 1\nL 2\nD 1\nU 3\nL 2\nR 3\nD 1\nR 3\nL 3\nU 1\nL 3\nR 2\nD 3\nU 3\nL 3\nD 4\nL 1\nU 1\nR 3\nL 1\nD 4\nU 4\nL 4\nD 4\nU 1\nD 3\nR 1\nD 4\nL 1\nU 2\nD 1\nR 3\nL 4\nD 2\nU 2\nR 1\nL 4\nU 4\nR 4\nD 1\nR 3\nD 1\nR 4\nU 4\nD 1\nU 3\nD 4\nL 3\nR 2\nD 4\nL 2\nU 4\nD 3\nU 4\nD 2\nU 2\nL 3\nR 4\nL 4\nU 2\nL 1\nU 4\nD 4\nR 4\nU 4\nR 2\nU 4\nR 1\nU 3\nR 3\nU 4\nR 4\nU 2\nL 1\nU 3\nD 4\nL 1\nR 1\nL 2\nR 2\nD 2\nU 3\nR 3\nL 1\nD 2\nR 4\nD 1\nR 4\nL 2\nU 4\nD 2\nR 4\nU 2\nD 4\nR 1\nU 3\nL 3\nD 2\nR 2\nU 1\nL 4\nR 1\nU 2\nR 4\nD 3\nR 1\nL 2\nU 1\nR 2\nL 2\nU 2\nR 3\nL 2\nD 4\nU 4\nL 1\nU 2\nD 1\nU 2\nD 1\nL 2\nR 4\nL 5\nD 2\nU 5\nL 1\nR 2\nL 3\nU 3\nD 3\nL 1\nD 1\nU 4\nL 4\nU 3\nD 5\nR 1\nL 4\nU 1\nL 2\nR 4\nD 1\nL 4\nD 1\nU 4\nD 1\nL 2\nD 5\nL 5\nD 4\nR 3\nU 2\nL 4\nU 4\nL 4\nR 5\nD 1\nL 2\nR 5\nU 4\nD 5\nL 2\nU 4\nD 1\nL 3\nR 5\nD 4\nL 1\nD 3\nL 3\nU 2\nR 2\nD 4\nL 4\nU 1\nD 2\nL 5\nD 2\nL 2\nU 3\nR 3\nU 3\nD 2\nU 4\nR 3\nL 3\nD 2\nL 2\nR 3\nD 2\nL 3\nR 4\nU 4\nR 4\nD 2\nR 1\nD 1\nL 4\nR 4\nD 3\nR 2\nU 4\nL 2\nD 3\nU 4\nL 3\nR 5\nL 2\nR 1\nD 4\nL 5\nD 2\nU 5\nL 4\nU 2\nR 3\nL 4\nR 1\nU 3\nR 3\nL 2\nU 2\nL 3\nR 5\nL 3\nR 3\nU 3\nL 3\nU 5\nD 4\nU 5\nD 4\nL 4\nD 2\nR 5\nL 3\nU 2\nD 3\nL 4\nR 1\nD 1\nR 5\nL 3\nR 2\nL 3\nU 3\nD 1\nU 5\nR 2\nL 2\nD 5\nR 3\nU 4\nR 3\nL 1\nR 6\nL 4\nD 4\nU 4\nR 4\nU 2\nR 4\nD 1\nU 3\nR 1\nU 5\nD 3\nL 4\nR 5\nL 3\nU 6\nL 5\nD 3\nR 1\nD 2\nU 5\nL 1\nR 5\nU 4\nR 1\nU 1\nR 3\nL 2\nD 5\nU 4\nL 1\nU 2\nR 3\nL 5\nR 2\nD 3\nU 3\nD 6\nR 1\nD 2\nL 3\nR 3\nL 3\nU 4\nR 4\nU 4\nR 6\nU 1\nL 6\nR 6\nL 4\nU 6\nL 2\nD 1\nR 5\nL 5\nU 3\nD 6\nU 5\nL 4\nU 2\nR 1\nL 3\nD 6\nU 5\nR 4\nU 2\nD 3\nR 4\nL 1\nD 4\nU 6\nR 1\nD 6\nU 2\nD 5\nU 4\nL 4\nR 6\nD 2\nR 6\nL 1\nR 3\nD 4\nR 5\nL 6\nU 5\nL 3\nR 6\nU 1\nL 3\nD 7\nU 2\nD 5\nR 5\nD 7\nR 6\nD 6\nR 7\nD 7\nL 3\nR 4\nL 1\nU 6\nR 2\nL 7\nU 7\nD 1\nR 1\nD 1\nU 5\nR 4\nU 2\nD 5\nU 6\nL 2\nR 1\nU 5\nL 1\nU 7\nR 1\nD 2\nL 4\nD 4\nL 5\nU 4\nL 2\nD 5\nR 7\nD 7\nR 5\nL 3\nU 7\nR 7\nD 1\nL 2\nU 3\nL 2\nU 7\nL 2\nU 3\nL 6\nD 6\nL 2\nD 6\nL 6\nU 3\nL 3\nU 7\nD 3\nL 4\nU 5\nD 5\nL 4\nD 7\nU 3\nR 7\nD 5\nR 3\nL 6\nU 2\nL 2\nU 1\nL 1\nU 4\nD 7\nL 7\nD 2\nU 6\nL 2\nU 2\nL 4\nR 3\nL 6\nR 2\nD 7\nL 6\nD 3\nL 6\nR 1\nU 4\nR 6\nL 7\nD 7\nR 4\nU 7\nL 6\nR 3\nD 1\nU 3\nD 2\nU 3\nR 2\nL 7\nU 1\nR 4\nD 4\nU 2\nR 5\nD 5\nR 4\nL 3\nU 1\nR 7\nL 5\nD 4\nL 3\nD 7\nU 2\nD 4\nU 4\nL 1\nD 4\nR 7\nL 6\nU 3\nL 4\nD 5\nU 1\nD 1\nL 6\nR 7\nD 1\nL 4\nD 1\nL 5\nR 8\nD 4\nL 8\nR 4\nD 4\nU 3\nL 5\nR 5\nL 8\nU 4\nR 2\nD 6\nR 5\nL 1\nU 8\nL 1\nD 5\nU 5\nD 4\nL 6\nU 6\nD 8\nR 6\nD 3\nU 7\nR 8\nD 7\nL 2\nU 4\nD 4\nL 2\nR 2\nU 5\nL 4\nR 3\nL 2\nU 5\nD 8\nL 8\nD 3\nU 4\nD 2\nL 2\nU 4\nR 5\nL 6\nU 4\nR 5\nU 4\nL 7\nD 8\nR 8\nD 7\nR 5\nD 6\nU 2\nR 1\nD 3\nL 6\nU 3\nD 5\nU 6\nL 7\nR 1\nL 4\nR 4\nL 4\nR 3\nL 4\nU 3\nD 7\nU 8\nD 4\nR 6\nL 7\nR 2\nL 2\nU 7\nD 2\nR 1\nD 5\nU 1\nD 7\nR 2\nL 8\nR 8\nU 4\nR 9\nL 4\nR 5\nL 2\nD 6\nL 9\nU 2\nR 5\nD 4\nR 9\nU 4\nD 8\nR 9\nU 5\nD 4\nU 4\nL 4\nU 3\nR 5\nL 8\nD 9\nU 2\nL 8\nU 5\nD 4\nL 1\nD 4\nU 3\nD 7\nU 5\nD 5\nR 9\nL 2\nD 5\nL 7\nD 1\nL 2\nR 6\nD 9\nU 1\nL 6\nR 2\nD 2\nR 5\nD 8\nR 2\nD 3\nL 4\nD 5\nR 2\nD 8\nL 3\nD 6\nU 2\nL 4\nD 9\nL 6\nR 5\nL 7\nU 2\nD 8\nU 5\nL 6\nU 1\nL 9\nR 9\nD 1\nR 3\nU 9\nL 2\nU 8\nR 8\nD 8\nR 7\nU 7\nR 6\nL 2\nU 4\nD 2\nL 4\nU 4\nD 2\nR 8\nL 6\nR 9\nD 9\nL 6\nD 4\nL 5\nU 8\nD 2\nR 6\nD 7\nU 3\nR 6\nL 9\nU 6\nL 8\nU 8\nD 6\nU 9\nD 5\nU 8\nL 6\nR 6\nL 6\nR 9\nL 2\nU 4\nL 4\nU 1\nD 4\nR 1\nU 7\nD 5\nR 4\nU 4\nD 5\nL 9\nR 2\nU 5\nL 2\nR 10\nL 5\nR 1\nL 2\nU 3\nD 2\nR 7\nL 2\nR 6\nL 3\nR 6\nU 7\nL 1\nU 6\nR 6\nU 2\nL 3\nR 3\nL 1\nR 9\nL 5\nU 9\nL 9\nD 9\nU 4\nD 2\nR 6\nD 6\nR 8\nD 2\nU 6\nL 5\nR 2\nU 10\nL 3\nD 6\nR 3\nD 6\nU 2\nD 7\nR 1\nU 7\nD 2\nR 8\nL 5\nU 4\nL 5\nR 6\nU 6\nD 1\nL 5\nD 5\nR 5\nD 4\nL 5\nU 3\nR 4\nL 5\nR 2\nL 5\nD 10\nR 4\nL 2\nR 4\nL 7\nU 9\nR 3\nD 6\nR 7\nL 10\nD 7\nU 4\nL 9\nD 6\nL 7\nR 3\nU 7\nR 5\nU 6\nL 1\nU 2\nL 5\nD 6\nR 8\nL 7\nR 7\nD 1\nU 9\nR 1\nL 4\nU 4\nR 1\nL 3\nD 2\nL 8\nD 10\nL 9\nD 8\nR 5\nD 6\nL 7\nD 2\nU 11\nD 2\nU 6\nL 3\nU 8\nD 11\nU 9\nD 9\nR 11\nU 11\nL 8\nU 11\nR 11\nU 2\nD 6\nR 11\nD 7\nL 6\n" <> ...

Part 1

defmodule PartOne do
  def resolve(input) do
    IO.puts("--- Part One ---")
    IO.puts("Result: #{run(input)}")
  end

  def run(input) do
    input
    |> String.split("\n", trim: true)
    |> Enum.map(fn x -> String.split(x, "", trim: true) end)
    |> then(fn x ->
      max_row = Enum.count(x)
      max_col = Enum.at(x, 0) |> Enum.count()

      Enum.with_index(x, fn element, row_index ->
        Enum.with_index(element, fn _tree, col_index ->
          if row_index == 0 or row_index == max_row - 1 or col_index == 0 or
               col_index == max_col - 1 do
            true
          else
            check_visible(x, row_index, col_index)
          end
        end)
      end)
    end)
    |> Enum.reduce(0, fn row, count ->
      count +
        Enum.reduce(row, 0, fn tree, c ->
          if tree do
            c + 1
          else
            c
          end
        end)
    end)
  end

  defp check_visible(x, row_index, col_index) do
    row = Enum.at(x, row_index)
    row_left = row |> Enum.slice(0..(col_index - 1))
    row_right = row |> Enum.slice((col_index + 1)..(Enum.count(x) - 1))
    elem = row |> Enum.at(col_index)
    col = Enum.map(x, fn x -> Enum.at(x, col_index) end)
    col_top = col |> Enum.slice(0..(row_index - 1))
    col_bottom = col |> Enum.slice((row_index + 1)..(Enum.count(col) - 1))

    visible =
      is_visible(row_left, elem) || is_visible(row_right, elem) ||
        is_visible(col_top, elem) || is_visible(col_bottom, elem)

    visible
  end

  defp is_visible(row, elem) do
    Enum.all?(row, fn x -> x < elem end)
  end
end
{:module, PartOne, <<70, 79, 82, 49, 0, 0, 19, ...>>, {:is_visible, 2}}
input
|> PartOne.resolve()
--- Part One ---
Result: 1789
:ok
ExUnit.start(autorun: false)

defmodule PartOneTest do
  use ExUnit.Case, async: true
  import PartOne

  test "part one" do
    input = "30373
25512
65332
33549
35390"
    result = run(input)
    assert result == 21
  end
end

ExUnit.run()
.
Finished in 0.00 seconds (0.00s async, 0.00s sync)
1 test, 0 failures

Randomized with seed 61016
%{excluded: 0, failures: 0, skipped: 0, total: 1}

Part 2

defmodule PartTwo do
  def resolve(input) do
    IO.puts("--- Part One ---")
    IO.puts("Result: #{run(input)}")
  end

  def run(input) do
    input
    |> String.split("\n", trim: true)
    |> Enum.map(fn x ->
      String.split(x, "", trim: true)
      |> Enum.map(fn x -> String.to_integer(x) end)
    end)
    |> then(fn x ->
      max_row = Enum.count(x)
      max_col = Enum.at(x, 0) |> Enum.count()

      Enum.with_index(x, fn element, row_index ->
        Enum.with_index(element, fn _tree, col_index ->
          if row_index == 0 or row_index == max_row - 1 or col_index == 0 or
               col_index == max_col - 1 do
            0
          else
            calc_score(x, row_index, col_index)
          end
        end)
      end)
    end)
    |> Enum.map(fn row -> Enum.max(row) end)
    |> Enum.max()
  end

  defp calc_score(x, row_index, col_index) do
    row = Enum.at(x, row_index)
    row_left = row |> Enum.slice(0..(col_index - 1)) |> Enum.reverse()
    row_right = row |> Enum.slice((col_index + 1)..(Enum.count(x) - 1))
    elem = row |> Enum.at(col_index)
    col = Enum.map(x, fn x -> Enum.at(x, col_index) end)
    col_top = col |> Enum.slice(0..(row_index - 1)) |> Enum.reverse()
    col_bottom = col |> Enum.slice((row_index + 1)..(Enum.count(col) - 1))

    scenic_score =
      [
        count_visible(row_left, elem),
        count_visible(row_right, elem),
        count_visible(col_top, elem),
        count_visible(col_bottom, elem)
      ]
      |> Enum.reduce(1, fn x, acc -> acc * x end)

    scenic_score
  end

  defp count_visible([], _elem) do
    0
  end

  defp count_visible(row, elem) do
    Enum.reduce_while(row, 0, fn x, acc ->
      cond do
        x < elem -> {:cont, acc + 1}
        true -> {:halt, acc + 1}
      end
    end)
  end
end
{:module, PartTwo, <<70, 79, 82, 49, 0, 0, 19, ...>>, {:count_visible, 2}}
input
|> PartTwo.resolve()
--- Part One ---
Result: 314820
:ok
ExUnit.start(autorun: false)

defmodule PartTwoTest do
  use ExUnit.Case, async: true
  import PartTwo

  test "part one" do
    input = "30373
25512
65332
33549
35390"
    result = run(input)
    assert result == 8
  end
end

ExUnit.run()
.
Finished in 0.00 seconds (0.00s async, 0.00s sync)
1 test, 0 failures

Randomized with seed 61016
%{excluded: 0, failures: 0, skipped: 0, total: 1}