120 lines
2.8 KiB
Elixir
120 lines
2.8 KiB
Elixir
|
defmodule Day11 do
|
||
|
@example """
|
||
|
L.LL.LL.LL
|
||
|
LLLLLLL.LL
|
||
|
L.L.L..L..
|
||
|
LLLL.LL.LL
|
||
|
L.LL.LL.LL
|
||
|
L.LLLLL.LL
|
||
|
..L.L.....
|
||
|
LLLLLLLLLL
|
||
|
L.LLLLLL.L
|
||
|
L.LLLLL.LL
|
||
|
"""
|
||
|
|
||
|
def part1(example \\ false) do
|
||
|
parse_input(example)
|
||
|
|> find_final_state(&count_adjacent_occupied/3, 4)
|
||
|
|> count_occupied()
|
||
|
end
|
||
|
|
||
|
def part2(example \\ false) do
|
||
|
parse_input(example)
|
||
|
|> find_final_state(&count_visible_occupied/3, 5)
|
||
|
|> count_occupied()
|
||
|
|
||
|
# |> step(&count_visible_occupied/3, 5)
|
||
|
# |> step(&count_visible_occupied/3, 5)
|
||
|
# |> Enum.each(&IO.puts/1)
|
||
|
end
|
||
|
|
||
|
def parse_input(example) do
|
||
|
if(example, do: @example, else: File.read!("lib/day11/input.txt"))
|
||
|
|> String.trim()
|
||
|
|> String.split()
|
||
|
|> Enum.map(&String.to_charlist/1)
|
||
|
end
|
||
|
|
||
|
def find_final_state(map, count_fn, empty_threshold) do
|
||
|
case step(map, count_fn, empty_threshold) do
|
||
|
^map -> map
|
||
|
next -> find_final_state(next, count_fn, empty_threshold)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def step(map, count_fn, empty_threshold) do
|
||
|
map
|
||
|
|> Enum.with_index()
|
||
|
|> Enum.map(fn {row, row_index} ->
|
||
|
row
|
||
|
|> Enum.with_index()
|
||
|
|> Enum.map(fn {el, col_index} ->
|
||
|
if el == ?. do
|
||
|
?.
|
||
|
else
|
||
|
count = count_fn.(map, row_index, col_index)
|
||
|
|
||
|
case count do
|
||
|
0 -> ?#
|
||
|
c when c >= empty_threshold -> ?L
|
||
|
_ -> el
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
def count_adjacent_occupied(map, row, col) do
|
||
|
max(0, row - 1)..min(row + 1, length(map) - 1)
|
||
|
# |> IO.inspect()
|
||
|
|> Enum.map(fn test_row ->
|
||
|
# IO.inspect(test_row)
|
||
|
map_test_row = Enum.at(map, test_row)
|
||
|
|
||
|
max(0, col - 1)..min(col + 1, length(map_test_row))
|
||
|
|> Enum.reject(fn c -> test_row == row && c == col end)
|
||
|
|> Enum.count(fn test_col ->
|
||
|
Enum.at(map_test_row, test_col) == ?#
|
||
|
end)
|
||
|
end)
|
||
|
|> Enum.sum()
|
||
|
end
|
||
|
|
||
|
@directions -1..1
|
||
|
|> Enum.flat_map(fn dr ->
|
||
|
-1..1
|
||
|
|> Enum.map(fn dc -> {dr, dc} end)
|
||
|
end)
|
||
|
|> List.delete({0, 0})
|
||
|
|
||
|
def count_visible_occupied(map, row, col) do
|
||
|
Enum.count(@directions, fn {dr, dc} = dir ->
|
||
|
get_visible_seat(map, row + dr, col + dc, dir) == ?#
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
def get_visible_seat(_, -1, _, _), do: nil
|
||
|
def get_visible_seat(map, row, _, _) when row == length(map), do: nil
|
||
|
def get_visible_seat(_, _, -1, _), do: nil
|
||
|
def get_visible_seat(map, _, col, _) when col == length(hd(map)), do: nil
|
||
|
|
||
|
def get_visible_seat(map, row, col, {dr, dc} = dir) do
|
||
|
map
|
||
|
|> Enum.at(row)
|
||
|
|> Enum.at(col)
|
||
|
|> case do
|
||
|
?. ->
|
||
|
get_visible_seat(map, row + dr, col + dc, dir)
|
||
|
|
||
|
el ->
|
||
|
el
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def count_occupied(map) do
|
||
|
map
|
||
|
|> Enum.flat_map(& &1)
|
||
|
|> Enum.count(&(&1 == ?#))
|
||
|
end
|
||
|
end
|