Proper solution for 2023 Day8 part 2

This commit is contained in:
Adam Millerchip 2024-12-01 14:58:18 +09:00
parent bf6fa2af47
commit fb8ea486cc

33
2023/day8.exs Normal file → Executable file
View file

@ -1,3 +1,4 @@
#!/usr/bin/env elixir
defmodule Day8 do defmodule Day8 do
def part1({instructions, network}) do def part1({instructions, network}) do
instructions instructions
@ -8,24 +9,24 @@ defmodule Day8 do
end) end)
end end
# Runs forever.
# Need a better answer. Start at the end and validate can get there or something?
def part2({instructions, network}) do def part2({instructions, network}) do
starting_nodes = # Following the algorithm from the question naively seems to take too long, so we need to
network # find a shortcut.
|> Map.keys() # It seems that each ghost runs in a cycle, so we can solve the number of steps for each
|> Enum.filter(&match?(<<_::binary-2, "A">>, &1)) # ghost's path, and then find the lowest common multiple of those lengths, which will
# be the first time they arrive at the final spaces together.
instructions network
|> Stream.cycle() |> Map.keys()
|> Enum.reduce_while({starting_nodes, 0}, fn side, {current_nodes, count} -> |> Enum.filter(&match?(<<_::binary-2, "A">>, &1))
if Enum.all?(current_nodes, &match?(<<_::binary-2, "Z">>, &1)) do |> Enum.map(fn start ->
{:halt, count} instructions
else |> Stream.cycle()
next_nodes = Enum.map(current_nodes, fn node -> elem(network[node], side) end) |> Enum.reduce_while({start, 0}, fn
{:cont, {next_nodes, count + 1}} _side, {<<_::binary-2, "Z">>, count} -> {:halt, count}
end side, {node, count} -> {:cont, {elem(network[node], side), count + 1}}
end)
end) end)
|> Enum.reduce(fn a, b -> div(a * b, Integer.gcd(a, b)) end)
end end
def input do def input do