277 lines
5.6 KiB
Text
277 lines
5.6 KiB
Text
|
# AOC 2022 - Day 8
|
|||
|
|
|||
|
```elixir
|
|||
|
Mix.install(
|
|||
|
[
|
|||
|
{:req, "~> 0.3.3"},
|
|||
|
{:nx, "~> 0.4.1"},
|
|||
|
{:exla, "~> 0.4.1"}
|
|||
|
],
|
|||
|
config: [nx: [default_backend: EXLA.Backend]]
|
|||
|
)
|
|||
|
```
|
|||
|
|
|||
|
## Puzzle description
|
|||
|
|
|||
|
[Day 8: Treetop Tree House](https://adventofcode.com/2022/day/8).
|
|||
|
|
|||
|
## Input
|
|||
|
|
|||
|
```elixir
|
|||
|
defmodule Load do
|
|||
|
def input do
|
|||
|
aoc_session = System.fetch_env!("LB_AOC_SESSION")
|
|||
|
input_url = "https://adventofcode.com/2022/day/8/input"
|
|||
|
Req.get!(input_url, headers: [cookie: "session=#{aoc_session}"]).body
|
|||
|
end
|
|||
|
end
|
|||
|
```
|
|||
|
|
|||
|
## Solution
|
|||
|
|
|||
|
```elixir
|
|||
|
defmodule Util do
|
|||
|
def process(input) do
|
|||
|
input
|
|||
|
|> String.split("\n", trim: true)
|
|||
|
|> Enum.map(fn row ->
|
|||
|
row
|
|||
|
|> String.split("", trim: true)
|
|||
|
|> Enum.map(&String.to_integer/1)
|
|||
|
end)
|
|||
|
end
|
|||
|
|
|||
|
def process2(input) do
|
|||
|
input
|
|||
|
|> String.split()
|
|||
|
|> Enum.with_index()
|
|||
|
|> Enum.flat_map(&parse_line/1)
|
|||
|
|> Map.new(fn {v, k} -> {k, v} end)
|
|||
|
end
|
|||
|
|
|||
|
defp parse_line({string, row}) do
|
|||
|
string
|
|||
|
|> String.graphemes()
|
|||
|
|> Enum.with_index()
|
|||
|
|> Enum.map(fn {char, column} ->
|
|||
|
{String.to_integer(char), {row + 1, column + 1}}
|
|||
|
end)
|
|||
|
end
|
|||
|
|
|||
|
def count_visible(line) do
|
|||
|
line
|
|||
|
|> Enum.with_index()
|
|||
|
|> Enum.map_reduce(0, fn {h, n}, max ->
|
|||
|
cond do
|
|||
|
n == 0 ->
|
|||
|
{true, h}
|
|||
|
|
|||
|
h <= max ->
|
|||
|
{false, max}
|
|||
|
|
|||
|
true ->
|
|||
|
{true, h}
|
|||
|
end
|
|||
|
end)
|
|||
|
|> elem(0)
|
|||
|
end
|
|||
|
|
|||
|
def transpose(v) do
|
|||
|
v
|
|||
|
|> List.zip()
|
|||
|
|> Enum.map(&Tuple.to_list/1)
|
|||
|
end
|
|||
|
|
|||
|
def score(trees, row, column, rows, columns) do
|
|||
|
left_score(trees, row, column, rows, columns) *
|
|||
|
right_score(trees, row, column, rows, columns) *
|
|||
|
up_score(trees, row, column, rows, columns) *
|
|||
|
down_score(trees, row, column, rows, columns)
|
|||
|
end
|
|||
|
|
|||
|
defp left_score(trees, row, column, _rows, _columns) do
|
|||
|
list =
|
|||
|
for c <- (column - 1)..1 do
|
|||
|
trees[{row, c}]
|
|||
|
end
|
|||
|
|> Enum.with_index()
|
|||
|
|
|||
|
len = length(list)
|
|||
|
|
|||
|
list
|
|||
|
|> Enum.reduce_while(1, fn {height, position}, score ->
|
|||
|
if trees[{row, column}] > height and position + 1 != len,
|
|||
|
do: {:cont, score + 1},
|
|||
|
else: {:halt, score}
|
|||
|
end)
|
|||
|
end
|
|||
|
|
|||
|
defp right_score(trees, row, column, _rows, columns) do
|
|||
|
list =
|
|||
|
for c <- (column + 1)..columns do
|
|||
|
trees[{row, c}]
|
|||
|
end
|
|||
|
|> Enum.with_index()
|
|||
|
|
|||
|
len = length(list)
|
|||
|
|
|||
|
list
|
|||
|
|> Enum.reduce_while(1, fn {height, position}, score ->
|
|||
|
if trees[{row, column}] > height and position + 1 != len,
|
|||
|
do: {:cont, score + 1},
|
|||
|
else: {:halt, score}
|
|||
|
end)
|
|||
|
end
|
|||
|
|
|||
|
defp up_score(trees, row, column, _rows, _columns) do
|
|||
|
list =
|
|||
|
for r <- (row - 1)..1 do
|
|||
|
trees[{r, column}]
|
|||
|
end
|
|||
|
|> Enum.with_index()
|
|||
|
|
|||
|
len = length(list)
|
|||
|
|
|||
|
list
|
|||
|
|> Enum.reduce_while(1, fn {height, position}, score ->
|
|||
|
if trees[{row, column}] > height and position + 1 != len,
|
|||
|
do: {:cont, score + 1},
|
|||
|
else: {:halt, score}
|
|||
|
end)
|
|||
|
end
|
|||
|
|
|||
|
defp down_score(trees, row, column, rows, _columns) do
|
|||
|
list =
|
|||
|
for r <- (row + 1)..rows do
|
|||
|
trees[{r, column}]
|
|||
|
end
|
|||
|
|> Enum.with_index()
|
|||
|
|
|||
|
len = length(list)
|
|||
|
|
|||
|
list
|
|||
|
|> Enum.reduce_while(1, fn {height, position}, score ->
|
|||
|
if trees[{row, column}] > height and position + 1 != len,
|
|||
|
do: {:cont, score + 1},
|
|||
|
else: {:halt, score}
|
|||
|
end)
|
|||
|
end
|
|||
|
end
|
|||
|
```
|
|||
|
|
|||
|
```elixir
|
|||
|
defmodule Part1 do
|
|||
|
def run(input) do
|
|||
|
trees =
|
|||
|
input
|
|||
|
|> Util.process()
|
|||
|
|
|||
|
{trees, horizontal} =
|
|||
|
trees
|
|||
|
|> Enum.map_reduce([], fn line, acc ->
|
|||
|
visible =
|
|||
|
[
|
|||
|
Util.count_visible(line),
|
|||
|
line |> Enum.reverse() |> Util.count_visible() |> Enum.reverse()
|
|||
|
]
|
|||
|
|> Enum.zip()
|
|||
|
|> Enum.map(&(elem(&1, 0) or elem(&1, 1)))
|
|||
|
|
|||
|
{line, [visible | acc]}
|
|||
|
end)
|
|||
|
|> then(fn {trees, horizontal} ->
|
|||
|
{trees, Enum.reverse(horizontal)}
|
|||
|
end)
|
|||
|
|
|||
|
{_, vertical} =
|
|||
|
trees
|
|||
|
|> Util.transpose()
|
|||
|
|> Enum.map_reduce([], fn col, acc ->
|
|||
|
visible =
|
|||
|
[
|
|||
|
Util.count_visible(col),
|
|||
|
col |> Enum.reverse() |> Util.count_visible() |> Enum.reverse()
|
|||
|
]
|
|||
|
|> Enum.zip()
|
|||
|
|> Enum.map(&(elem(&1, 0) or elem(&1, 1)))
|
|||
|
|
|||
|
{col, [visible | acc]}
|
|||
|
end)
|
|||
|
|> then(fn {trees, vertical} ->
|
|||
|
{trees, Enum.reverse(vertical) |> Util.transpose()}
|
|||
|
end)
|
|||
|
|
|||
|
horizontal
|
|||
|
|> Enum.zip(vertical)
|
|||
|
|> Enum.map(fn {h, v} ->
|
|||
|
h
|
|||
|
|> Enum.zip(v)
|
|||
|
|> Enum.map(&(elem(&1, 0) or elem(&1, 1)))
|
|||
|
end)
|
|||
|
|> Enum.map(fn line ->
|
|||
|
Enum.count(line, & &1)
|
|||
|
end)
|
|||
|
|> Enum.sum()
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
defmodule Part2 do
|
|||
|
def run(input) do
|
|||
|
trees = Util.process2(input)
|
|||
|
|
|||
|
{rows, columns} =
|
|||
|
trees
|
|||
|
|> Map.keys()
|
|||
|
|> Enum.max()
|
|||
|
|
|||
|
for i <- 2..(rows - 1), j <- 2..(columns - 1) do
|
|||
|
{i, j, Util.score(trees, i, j, rows, columns)}
|
|||
|
end
|
|||
|
|> Enum.max_by(fn {_, _, x} -> x end)
|
|||
|
|> elem(2)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
ExUnit.start(autorun: false)
|
|||
|
|
|||
|
defmodule Test do
|
|||
|
use ExUnit.Case, async: true
|
|||
|
@example_input ~s(30373
|
|||
|
25512
|
|||
|
65332
|
|||
|
33549
|
|||
|
35390)
|
|||
|
@input Load.input()
|
|||
|
|
|||
|
test "it loads the input" do
|
|||
|
assert String.length(@input) > 0
|
|||
|
end
|
|||
|
|
|||
|
test "part 1 example" do
|
|||
|
assert Part1.run(@example_input) === 21
|
|||
|
end
|
|||
|
|
|||
|
test "part 1" do
|
|||
|
assert Part1.run(@input) === 1816
|
|||
|
end
|
|||
|
|
|||
|
test "part 2 example" do
|
|||
|
assert Part2.run(@example_input) === 8
|
|||
|
end
|
|||
|
|
|||
|
test "part 2" do
|
|||
|
assert Part2.run(@input) === 0
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
ExUnit.run()
|
|||
|
|
|||
|
# [
|
|||
|
# [1, 1, 1, 1, 1],
|
|||
|
# [1, 1, 1, 0, 1],
|
|||
|
# [1, 1, 0, 1, 1],
|
|||
|
# [1, 0, 1, 0, 1],
|
|||
|
# [1, 1, 1, 1, 1]
|
|||
|
# ]
|
|||
|
```
|