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