Conway Cubes
defmodule Aoc2020.Day17 do
@moduledoc "Conway Cubes"
def run() do
initial_state = parse_input()
run_cycles(initial_state, 6)
|> MapSet.size()
end
def parse_input() do
File.read!("priv/inputs/2020/day17.txt")
|> String.trim()
|> String.split("\n")
|> Enum.with_index()
|> Enum.flat_map(fn {row, y} ->
String.codepoints(row)
|> Enum.with_index()
|> Enum.filter(fn {v, _} -> v == "#" end)
|> Enum.map(fn {_, x} -> {x, y, 0} end)
end)
|> MapSet.new()
end
def run_cycles(state, 0), do: state
def run_cycles(state, remaining) do
run_cycles(next_state(state), remaining - 1)
end
def next_state(current_active) do
active_neighbourhood(current_active)
|> Enum.filter(fn cube ->
is_active = Enum.member?(current_active, cube)
case {is_active, active_neighbour_count(current_active, cube)} do
{true, c} when c in [2, 3] -> true
{false, 3} -> true
_ -> false
end
end)
|> MapSet.new()
end
def active_neighbourhood(current_active) do
Enum.reduce(current_active, MapSet.new(), fn cube, neighbourhood ->
MapSet.union(neighbourhood, neighbours(cube))
end)
end
def neighbours({x, y, z}) do
ns =
for x1 <- (x - 1)..(x + 1),
y1 <- (y - 1)..(y + 1),
z1 <- (z - 1)..(z + 1),
{x1, y1, z1} != {x, y, z},
do: {x1, y1, z1}
MapSet.new(ns)
end
def active_neighbour_count(current_active, cube) do
MapSet.size(MapSet.intersection(current_active, neighbours(cube)))
end
end