Watch
1
0
Fork
You've already forked advent-of-code
0
advent-of-code/2020/day17/day17.ex
2021-12-04 21:20:57 -08:00

165 lines
3.1 KiB
Elixir

defmodule Day17 do
defp read_input do
Path.expand('input', Path.dirname(__ENV__.file))
|> File.read!()
end
defp test_input do
"""
.#.
..#
###
"""
end
defp parse_space(text) do
String.split(text, "\n", trim: true)
|> Enum.with_index()
|> Enum.reduce(%{}, fn {line, y}, map ->
String.codepoints(line)
|> Enum.with_index()
|> Enum.reduce(map, fn {char, x}, map ->
Map.put(map, {x, y, 0}, char_to_content(char))
end)
end)
end
defp char_to_content(char) do
case char do
"." -> :inactive
"#" -> :active
end
end
defp state_char(char) do
case char do
:inactive -> "."
:active -> "#"
end
end
defp expand_range(lo..hi, val) do
cond do
val < lo -> val..hi
val > hi -> lo..val
true -> lo..hi
end
end
defp get_bounds(space) do
Enum.reduce(space, %{x: 0..0, y: 0..0, z: 0..0}, fn {{x, y, z}, state}, bounds ->
case state do
:inactive ->
bounds
:active ->
%{
x: expand_range(bounds.x, x),
y: expand_range(bounds.y, y),
z: expand_range(bounds.z, z)
}
end
end)
end
defp show(space) do
bounds = get_bounds(space)
for z <- bounds.z do
IO.puts("z = #{z}")
for y <- bounds.y do
for x <- bounds.x do
state = Map.get(space, {x, y, z}, :inactive)
IO.write(state_char(state))
end
IO.write("\n")
end
IO.write("\n\n")
end
space
end
defp populate(space) do
Enum.reduce(space, %{}, fn {cell, state}, counts ->
if state == :inactive do
counts
else
neighbors(cell)
|> Enum.reduce(counts, fn neighbor, counts ->
Map.put(counts, neighbor, 1 + Map.get(counts, neighbor, 0))
end)
end
end)
end
defp tick(space) do
populate(space)
|> Enum.reduce(%{}, fn {cell, count}, new_space ->
new_state =
case Map.get(space, cell, :inactive) do
:active ->
if count == 2 or count == 3 do
:active
else
:inactive
end
:inactive ->
if count == 3 do
:active
else
:inactive
end
end
case new_state do
:active -> Map.put(new_space, cell, :active)
:inactive -> new_space
end
end)
end
defp neighbors(cell = {x, y, z}) do
for dx <- -1..1,
dy <- -1..1,
dz <- -1..1 do
{x + dx, y + dy, z + dz}
end
|> Enum.reject(&(&1 == cell))
end
defp run(space, 0) do
space
end
defp run(space, cycles) do
IO.puts("cycles = #{cycles}")
show(space)
tick(space)
|> run(cycles - 1)
end
def part1 do
read_input()
|> parse_space()
|> run(6)
|> show()
|> Enum.count(fn {_cell, state} -> state == :active end)
end
def debug do
test_input()
|> parse_space()
|> tick()
# neighbors(%{}, {0, 0, 0})
end
end
Day17.part1() |> IO.inspect()
# Day17.debug() |> IO.inspect()