From fb8ea486cc5ab16efb9337e4c3ea51420acf314e Mon Sep 17 00:00:00 2001 From: Adam Millerchip Date: Sun, 1 Dec 2024 14:58:18 +0900 Subject: [PATCH] Proper solution for 2023 Day8 part 2 --- 2023/day8.exs | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) mode change 100644 => 100755 2023/day8.exs diff --git a/2023/day8.exs b/2023/day8.exs old mode 100644 new mode 100755 index 64ba26c..95a40b5 --- a/2023/day8.exs +++ b/2023/day8.exs @@ -1,3 +1,4 @@ +#!/usr/bin/env elixir defmodule Day8 do def part1({instructions, network}) do instructions @@ -8,24 +9,24 @@ defmodule Day8 do end) end - # Runs forever. - # Need a better answer. Start at the end and validate can get there or something? def part2({instructions, network}) do - starting_nodes = - network - |> Map.keys() - |> Enum.filter(&match?(<<_::binary-2, "A">>, &1)) - - instructions - |> Stream.cycle() - |> Enum.reduce_while({starting_nodes, 0}, fn side, {current_nodes, count} -> - if Enum.all?(current_nodes, &match?(<<_::binary-2, "Z">>, &1)) do - {:halt, count} - else - next_nodes = Enum.map(current_nodes, fn node -> elem(network[node], side) end) - {:cont, {next_nodes, count + 1}} - end + # Following the algorithm from the question naively seems to take too long, so we need to + # find a shortcut. + # It seems that each ghost runs in a cycle, so we can solve the number of steps for each + # 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. + network + |> Map.keys() + |> Enum.filter(&match?(<<_::binary-2, "A">>, &1)) + |> Enum.map(fn start -> + instructions + |> Stream.cycle() + |> Enum.reduce_while({start, 0}, fn + _side, {<<_::binary-2, "Z">>, count} -> {:halt, count} + side, {node, count} -> {:cont, {elem(network[node], side), count + 1}} + end) end) + |> Enum.reduce(fn a, b -> div(a * b, Integer.gcd(a, b)) end) end def input do