89 lines
2.5 KiB
Elixir
89 lines
2.5 KiB
Elixir
|
defmodule Cell do
|
||
|
defstruct [:x, :y]
|
||
|
end
|
||
|
|
||
|
defmodule Day24Part2 do
|
||
|
def run do
|
||
|
File.read!("input")
|
||
|
|> String.split("\n", trim: true)
|
||
|
|> Enum.map(&parse_line/1)
|
||
|
|> Enum.reduce(MapSet.new(), fn cell, black ->
|
||
|
if MapSet.member?(black, cell) do
|
||
|
MapSet.delete(black, cell)
|
||
|
else
|
||
|
MapSet.put(black, cell)
|
||
|
end
|
||
|
end)
|
||
|
|> flip_times(100)
|
||
|
|> Enum.count()
|
||
|
|> IO.puts()
|
||
|
end
|
||
|
|
||
|
def parse_line(str) do
|
||
|
str
|
||
|
|> String.graphemes()
|
||
|
|> Enum.chunk_while(
|
||
|
nil,
|
||
|
fn
|
||
|
"n", nil -> {:cont, :north}
|
||
|
"s", nil -> {:cont, :south}
|
||
|
"e", :north -> {:cont, :northeast, nil}
|
||
|
"e", :south -> {:cont, :southeast, nil}
|
||
|
"e", nil -> {:cont, :east, nil}
|
||
|
"w", :north -> {:cont, :northwest, nil}
|
||
|
"w", :south -> {:cont, :southwest, nil}
|
||
|
"w", nil -> {:cont, :west, nil}
|
||
|
end,
|
||
|
fn acc -> {:cont, acc} end
|
||
|
)
|
||
|
|> Enum.reduce(%Cell{x: 0, y: 0}, &move/2)
|
||
|
end
|
||
|
|
||
|
def move(:east, %Cell{x: x, y: y}), do: %Cell{x: x + 2, y: y}
|
||
|
def move(:west, %Cell{x: x, y: y}), do: %Cell{x: x - 2, y: y}
|
||
|
def move(:northeast, %Cell{x: x, y: y}), do: %Cell{x: x + 1, y: y + 1}
|
||
|
def move(:northwest, %Cell{x: x, y: y}), do: %Cell{x: x - 1, y: y + 1}
|
||
|
def move(:southeast, %Cell{x: x, y: y}), do: %Cell{x: x + 1, y: y - 1}
|
||
|
def move(:southwest, %Cell{x: x, y: y}), do: %Cell{x: x - 1, y: y - 1}
|
||
|
|
||
|
# Below code adapted from Day 17 Part 2
|
||
|
|
||
|
def flip_times(cells, 0), do: cells
|
||
|
def flip_times(cells, count), do: flip_times(flip(cells), count - 1)
|
||
|
|
||
|
def flip(cells) do
|
||
|
{flipped, whites} =
|
||
|
Enum.reduce(cells, {MapSet.new(), MapSet.new()}, fn cell, {flipped, whites} ->
|
||
|
{black_count, whites} =
|
||
|
Enum.reduce(neighbours(cell), {0, whites}, fn neighbour, {black_count, whites} ->
|
||
|
if MapSet.member?(cells, neighbour) do
|
||
|
{black_count + 1, whites}
|
||
|
else
|
||
|
{black_count, MapSet.put(whites, neighbour)}
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
flipped =
|
||
|
if black_count == 0 or black_count > 2,
|
||
|
do: flipped,
|
||
|
else: MapSet.put(flipped, cell)
|
||
|
|
||
|
{flipped, whites}
|
||
|
end)
|
||
|
|
||
|
Enum.reduce(whites, flipped, fn white, flipped ->
|
||
|
black_neighbours =
|
||
|
white |> neighbours() |> MapSet.new() |> MapSet.intersection(cells) |> Enum.count()
|
||
|
|
||
|
if black_neighbours == 2, do: MapSet.put(flipped, white), else: flipped
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
def neighbours(cell) do
|
||
|
[:east, :west, :northeast, :northwest, :southeast, :southwest]
|
||
|
|> Enum.map(&move(&1, cell))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
Day24Part2.run()
|