AdventOfCode/2020/day11/day11part1.exs

94 lines
1.8 KiB
Elixir

defmodule Day11Part1 do
def run do
File.read!("input")
|> String.split("\n", trim: true)
|> Enum.map(&String.to_charlist/1)
|> parse_seat_plan()
|> run_until_stable()
|> count_occupied()
|> IO.inspect()
end
def run_until_stable(seats) do
new_seats = tick(seats)
if new_seats == seats do
seats
else
run_until_stable(new_seats)
end
end
def tick(seats) do
Map.new(seats, fn {{x, y}, old_seat} -> toggle(old_seat, x, y, seats) end)
end
def toggle(:empty, x, y, seats) do
new_value =
if occupied_adjacent(x, y, seats) == 0 do
:occupied
else
:empty
end
{{x, y}, new_value}
end
def toggle(:occupied, x, y, seats) do
new_value =
if occupied_adjacent(x, y, seats) >= 4 do
:empty
else
:occupied
end
{{x, y}, new_value}
end
def toggle(:floor, x, y, _), do: {{x, y}, :floor}
def occupied_adjacent(x, y, seats) do
adjacent = [
{x - 1, y - 1},
{x - 1, y},
{x - 1, y + 1},
{x, y - 1},
{x, y + 1},
{x + 1, y - 1},
{x + 1, y},
{x + 1, y + 1}
]
seats
|> Map.take(adjacent)
|> count_occupied()
end
def count_occupied(seats) do
Enum.count(seats, &match?({_, :occupied}, &1))
end
def parse_seat_plan(input) do
{_, seats} =
Enum.reduce(input, {0, %{}}, fn row, {y, seats} ->
{_, seats} =
Enum.reduce(row, {0, seats}, fn seat, {x, seats} ->
seat =
case seat do
?L -> :empty
?. -> :floor
?# -> :occupied
end
{x + 1, Map.put(seats, {x, y}, seat)}
end)
{y + 1, seats}
end)
seats
end
end
Day11Part1.run()