Day 17 Parts 1 and 2
This commit is contained in:
parent
d607504faf
commit
e6991afe00
5 changed files with 177 additions and 1 deletions
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
My (attempted) solutions to [Advent of Code 2020](https://adventofcode.com/2020) in Elixir.
|
My (attempted) solutions to [Advent of Code 2020](https://adventofcode.com/2020) in Elixir.
|
||||||
|
|
||||||
<img width="978" alt="image" src="https://user-images.githubusercontent.com/498229/102717151-cdc3a700-4323-11eb-930e-613465f503d1.png">
|
<img width="978" alt="image" src="https://user-images.githubusercontent.com/498229/102721772-43d60700-4340-11eb-9ccc-baa6479559f8.png">
|
||||||
|
|
||||||
## Strategy
|
## Strategy
|
||||||
|
|
||||||
|
|
44
day17/README
Normal file
44
day17/README
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
Day 17 Notes
|
||||||
|
|
||||||
|
+--------+
|
||||||
|
| Part 1 |
|
||||||
|
+--------+
|
||||||
|
|
||||||
|
$ elixir day17part1.exs
|
||||||
|
362
|
||||||
|
|
||||||
|
Thoughts:
|
||||||
|
|
||||||
|
The answer is not pretty, but it works.
|
||||||
|
|
||||||
|
Rather than iterate through the entire coordinate plane, which would require keeping track of where
|
||||||
|
the current extremities are, I decided to only keep the set of active cubes around. Then for each
|
||||||
|
iteration, check all the active cube's neighbours.
|
||||||
|
|
||||||
|
In addition to counting the neighbours for the active cube, keep track of the inactive neighbours,
|
||||||
|
then check *their* neighbours too to see if they should become active.
|
||||||
|
|
||||||
|
+--------+
|
||||||
|
| Part 2 |
|
||||||
|
+--------+
|
||||||
|
|
||||||
|
$ elixir day17part2.exs
|
||||||
|
1980
|
||||||
|
|
||||||
|
Thoughts:
|
||||||
|
|
||||||
|
In Part 1 I was half expecting a high iteration count for part 2, hence why I avoided iterating the
|
||||||
|
entire plane. Instead, adding a 4th dimension was a two-line change :-)
|
||||||
|
|
||||||
|
+------------------+
|
||||||
|
| Overall Thoughts |
|
||||||
|
+------------------+
|
||||||
|
|
||||||
|
Nice to have a quick Part 2 solve after day 18 which took me ages. I probably dug myself into
|
||||||
|
a hole on day 18 though and should have took a step back and tried with a clearer mind.
|
||||||
|
|
||||||
|
I spent quite a while getting distracted by the examples, because they present a sliding plane.
|
||||||
|
Turns out I had actually written the correct implementation, I just struggled to translate my
|
||||||
|
coordinates to the graphical examples. Running the script produced the correct answer though, but
|
||||||
|
I cross-referenced it with one of the confusing examples, just in case it wasn't pure luck. I'm
|
||||||
|
glad I was able to solve Part 2 without reading all the dreaded 4D examples there too!
|
59
day17/day17part1.exs
Normal file
59
day17/day17part1.exs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
defmodule Day17Part1 do
|
||||||
|
def run do
|
||||||
|
File.read!("input")
|
||||||
|
|> String.split("\n", trim: true)
|
||||||
|
|> parse_input()
|
||||||
|
|> boot(6)
|
||||||
|
|> Enum.count()
|
||||||
|
|> IO.puts()
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_input(input) do
|
||||||
|
{_y, cubes} =
|
||||||
|
Enum.reduce(input, {0, MapSet.new()}, fn row, {y, cubes} ->
|
||||||
|
{_x, cubes} =
|
||||||
|
Enum.reduce(String.graphemes(row), {0, cubes}, fn
|
||||||
|
".", {x, cubes} -> {x + 1, cubes}
|
||||||
|
"#", {x, cubes} -> {x + 1, MapSet.put(cubes, {x, y, 0})}
|
||||||
|
end)
|
||||||
|
|
||||||
|
{y + 1, cubes}
|
||||||
|
end)
|
||||||
|
|
||||||
|
cubes
|
||||||
|
end
|
||||||
|
|
||||||
|
def boot(cubes, 0), do: cubes
|
||||||
|
def boot(cubes, count), do: boot(cycle(cubes), count - 1)
|
||||||
|
|
||||||
|
def cycle(cubes) do
|
||||||
|
{next_cubes, inactives} =
|
||||||
|
Enum.reduce(cubes, {MapSet.new(), MapSet.new()}, fn cube, {next_cubes, inactives} ->
|
||||||
|
{active_count, inactives} =
|
||||||
|
Enum.reduce(neighbours(cube), {0, inactives}, fn neighbour, {active_count, inactives} ->
|
||||||
|
if MapSet.member?(cubes, neighbour) do
|
||||||
|
{active_count + 1, inactives}
|
||||||
|
else
|
||||||
|
{active_count, MapSet.put(inactives, neighbour)}
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
next_cubes = if active_count in 2..3, do: MapSet.put(next_cubes, cube), else: next_cubes
|
||||||
|
{next_cubes, inactives}
|
||||||
|
end)
|
||||||
|
|
||||||
|
Enum.reduce(inactives, next_cubes, fn inactive, next_cubes ->
|
||||||
|
active_neighbours =
|
||||||
|
inactive |> neighbours() |> MapSet.new() |> MapSet.intersection(cubes) |> Enum.count()
|
||||||
|
|
||||||
|
if active_neighbours == 3, do: MapSet.put(next_cubes, inactive), else: next_cubes
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def neighbours({x, y, z} = me) do
|
||||||
|
all = for x <- (x - 1)..(x + 1), y <- (y - 1)..(y + 1), z <- (z - 1)..(z + 1), do: {x, y, z}
|
||||||
|
all -- [me]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Day17Part1.run()
|
65
day17/day17part2.exs
Normal file
65
day17/day17part2.exs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
defmodule Day17Part2 do
|
||||||
|
def run do
|
||||||
|
File.read!("input")
|
||||||
|
|> String.split("\n", trim: true)
|
||||||
|
|> parse_input()
|
||||||
|
|> boot(6)
|
||||||
|
|> Enum.count()
|
||||||
|
|> IO.puts()
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_input(input) do
|
||||||
|
{_y, cubes} =
|
||||||
|
Enum.reduce(input, {0, MapSet.new()}, fn row, {y, cubes} ->
|
||||||
|
{_x, cubes} =
|
||||||
|
Enum.reduce(String.graphemes(row), {0, cubes}, fn
|
||||||
|
".", {x, cubes} -> {x + 1, cubes}
|
||||||
|
"#", {x, cubes} -> {x + 1, MapSet.put(cubes, {x, y, 0, 0})}
|
||||||
|
end)
|
||||||
|
|
||||||
|
{y + 1, cubes}
|
||||||
|
end)
|
||||||
|
|
||||||
|
cubes
|
||||||
|
end
|
||||||
|
|
||||||
|
def boot(cubes, 0), do: cubes
|
||||||
|
def boot(cubes, count), do: boot(cycle(cubes), count - 1)
|
||||||
|
|
||||||
|
def cycle(cubes) do
|
||||||
|
{next_cubes, inactives} =
|
||||||
|
Enum.reduce(cubes, {MapSet.new(), MapSet.new()}, fn cube, {next_cubes, inactives} ->
|
||||||
|
{active_count, inactives} =
|
||||||
|
Enum.reduce(neighbours(cube), {0, inactives}, fn neighbour, {active_count, inactives} ->
|
||||||
|
if MapSet.member?(cubes, neighbour) do
|
||||||
|
{active_count + 1, inactives}
|
||||||
|
else
|
||||||
|
{active_count, MapSet.put(inactives, neighbour)}
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
next_cubes = if active_count in 2..3, do: MapSet.put(next_cubes, cube), else: next_cubes
|
||||||
|
{next_cubes, inactives}
|
||||||
|
end)
|
||||||
|
|
||||||
|
Enum.reduce(inactives, next_cubes, fn inactive, next_cubes ->
|
||||||
|
active_neighbours =
|
||||||
|
inactive |> neighbours() |> MapSet.new() |> MapSet.intersection(cubes) |> Enum.count()
|
||||||
|
|
||||||
|
if active_neighbours == 3, do: MapSet.put(next_cubes, inactive), else: next_cubes
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def neighbours({x, y, z, w} = me) do
|
||||||
|
all =
|
||||||
|
for x <- (x - 1)..(x + 1),
|
||||||
|
y <- (y - 1)..(y + 1),
|
||||||
|
z <- (z - 1)..(z + 1),
|
||||||
|
w <- (w - 1)..(w + 1),
|
||||||
|
do: {x, y, z, w}
|
||||||
|
|
||||||
|
all -- [me]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Day17Part2.run()
|
8
day17/input
Normal file
8
day17/input
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
...###.#
|
||||||
|
#.#.##..
|
||||||
|
.##.##..
|
||||||
|
..##...#
|
||||||
|
.###.##.
|
||||||
|
.#..##..
|
||||||
|
.....###
|
||||||
|
.####..#
|
Loading…
Reference in a new issue