<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="310721" data-post-id="310721">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="seeplusplus" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/seeplusplus/120/32772_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  seeplusplus
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<blockquote>
<p>FYI, each of the ghosts has only one possible position that ends with a <code>"Z"</code> on its path.</p>
</blockquote>
<p><strong>Edit</strong>: I was thinking about this and this post might not be true because entry node could leave the terminal node in different ways (by being on different steps and exiting either left or right). I thought about removing this post, but maybe someone will find interesting. Skip past if you don’t like sort-of-wrong explanations of things.</p>
<p>A bit of graph theory, if folks are interested: the instructions induce a set of disjoint cyclic graphs (in non-graph theory speak the entry “room”, its exit, and all of the rooms in between form a ring). So, each entry node (read, node that ends in A) belongs to <em>some cycle</em> that also contains a terminating node (read, node that ends in a Z). Otherwise the problem wouldn’t be solvable.</p>
<p>What may not be obvious, is if any cycle contains more than one terminating node (if any room could reach multiple exits) it must also contain an additional entry node. That is, if any entry node could reach more than one terminating node then there exists at least one other entry node that can also reach both.</p>
<p>If such a cycle existed (one that contains two terminating nodes), the only way this problem would be solvable is if both entry nodes reach their corresponding terminus in the same number of steps.</p>
<p>Visually, this a graph like this would never be solvable:<br>
</p><div class="lightbox-wrapper"><a class="lightbox" href="https://forum.elixirforum.com/uploads/default/original/3X/c/1/c13003ee83ab64429c9a9d3471c22ded093b6652.png" data-download-href="https://forum.elixirforum.com/uploads/default/c13003ee83ab64429c9a9d3471c22ded093b6652" title="DAY8" rel="nofollow"><img src="https://forum.elixirforum.com/uploads/default/original/3X/c/1/c13003ee83ab64429c9a9d3471c22ded093b6652.png" alt="DAY8" data-base62-sha1="rz11v80smipXKv3IYQVmYWqpK8i" width="501" height="483"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">DAY8</span><span class="informations">501×483 23.3 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div><p></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="310721" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-8/60244/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-310721" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="310721"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #11"></div>
  </section>
</div>
    <div class="postbit" id="310729" data-post-id="310729">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Aetherus" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Aetherus/120/17203_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Aetherus
                      <span class="op-star" title="Thread Starter">
                        <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                      </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Someone on Reddit plotted the paths of the ghosts.</p>
<p><a href="https://svgshare.com/i/10YN.svg" class="onebox" target="_blank" rel="noopener nofollow ugc">https://svgshare.com/i/10YN.svg</a></p>
<p>The red nodes are the starting positions, and the green ones are the nodes ending with a Z.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="310729" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-8/60244/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-310729" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="310729"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #12"></div>
  </section>
</div>
    <div class="postbit" id="310737" data-post-id="310737">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="seeplusplus" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/seeplusplus/120/32772_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  seeplusplus
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Wow, I love this - thanks for sharing. I didn’t think about generating these visualizations. I think what captivates me now is whether or not it’s possible for a given solvable input to produce a graph such as this where a Z-node is included in more than one of these graphs. In my earlier post I was sure it wasn’t, but the more I thought about it I’m not so sure. Hopefully trying to answer this question doesn’t eat away from AoC solving time!</p>
<p><strong>Edit</strong> Do you happen to have link to the post? I might want to play around with this and if they shared the code for making this vis. that would make life easier.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="310737" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-8/60244/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-310737" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="310737"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #13"></div>
  </section>
</div>
    <div class="postbit" id="310757" data-post-id="310757">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="mrsk" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/mrsk/120/32738_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  mrsk
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>For me it was not obvious that ghosts converge into cyclic paths so I went with brute force with some optimizations.</p>
<p><a href="https://gitlab.com/mrsk/aoc-elixir/-/blob/main/lib/Aoc2023/D08.ex" class="onebox" target="_blank" rel="noopener nofollow ugc">https://gitlab.com/mrsk/aoc-elixir/-/blob/main/lib/Aoc2023/D08.ex</a></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="310757" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-8/60244/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-310757" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="310757"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #14"></div>
  </section>
</div>
    <div class="postbit" id="310787" data-post-id="310787">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="trnasistor" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  trnasistor
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>My beginner’s solution, Day 8 part 1</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Day08 do

  def part1(input) do
    [directions, nodes, start, finish] = parse(input)
      # [[:L, :L, :R], [{1, 1}, {0, 2}, {2, 2}], 0, 2]
    cycle(directions, nodes, start, finish)
  end
  
  def step(directions, nodes, position, finish, count)
  def step([:L | d], n, p, f, c), do: step(d, n, elem(elem(n,p), 0), f, c+1) 
  def step([:R | d], n, p, f, c), do: step(d, n, elem(elem(n,p), 1), f, c+1) 
  def step(_d, _n, p, f, c) when p == f, do: {c}
  def step([], _n, p, _f, c), do: {p, c} 

  def cycle(d, n, p, f, c \\ 0) do
    case step(d, n, p, f, c) do
      {count} -&gt; count
      {position, count} -&gt; cycle(d, n, position, f, count)
    end
  end  


  def parse(raw_document) do
    [raw_directions, 
          raw_nodes] = String.split(raw_document, "\n\n")

    directions = raw_directions
      |&gt; String.graphemes
      |&gt; Enum.map(&amp;(case &amp;1 do "L" -&gt; :L; "R" -&gt; :R end))

    split_nodes = raw_nodes
      |&gt; String.replace([" = (", ", ", ")"], " ")
      |&gt; String.split("\n")
      |&gt; Enum.map(&amp;String.split/1)

    start  = Enum.find_index(split_nodes, &amp;(List.first(&amp;1) == "AAA"))
    finish = Enum.find_index(split_nodes, &amp;(List.first(&amp;1) == "ZZZ"))

    nodes = for [_node, left, right] &lt;- split_nodes do
      left  = Enum.find_index(split_nodes, &amp;(List.first(&amp;1) == left))
      right = Enum.find_index(split_nodes, &amp;(List.first(&amp;1) == right))
      {left, right} 
    end |&gt; List.to_tuple

    [directions, nodes, start, finish] 
  end
  
end
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="310787" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-8/60244/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-310787" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="310787"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #15"></div>
  </section>
</div>
    <div class="postbit" id="310851" data-post-id="310851">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="stevensonmt" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/stevensonmt/120/20503_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  stevensonmt
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Reading the discussion makes me think I just got lucky making an assumption about the paths cycling. I think the assumption must hold that all paths will cycle IF every starting node actually can reach a finishing node AND every finishing node can be reached by a starting node. As long as that is true the LCM approach should be valid, I think. Can anyone think of a counter example where the cycle of the instructions and the length of at least one path from start to finish are such you could endlessly cycle with out ever repeating?</p>
<p>Here’s my code:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  defmodule Parser do
    import NimbleParsec

    instructions = times(choice([ascii_char([?L]), ascii_char([?R])]), min: 1) |&gt; wrap()

    node = times(ascii_char([?A..?Z]), 3) |&gt; wrap()

    parent = node |&gt; ignore(string(" = "))

    children =
      ignore(string("("))
      |&gt; concat(node)
      |&gt; ignore(string(", "))
      |&gt; concat(node)
      |&gt; ignore(string(")\n"))

    tree =
      ignore(string("\n\n"))
      |&gt; times(parent |&gt; concat(children) |&gt; wrap(), min: 1)

    defparsec(:parser, instructions |&gt; concat(tree))
  end

# it was probably overkill to use NimbleParsec on this input, but I'm trying to get more comfortable with it. Starting to feel a little more intuitive.

defmodule Day8 do
  @moduledoc """
  Day8 AoC Solutions
  """

  alias AocToolbox.Input

  def input(:test),
    do: """
    RL

    AAA = (BBB, CCC)
    BBB = (DDD, EEE)
    CCC = (ZZZ, GGG)
    DDD = (DDD, DDD)
    EEE = (EEE, EEE)
    GGG = (GGG, GGG)
    ZZZ = (ZZZ, ZZZ)
    """

  def input(:test2),
    do: """
    LLR

    AAA = (BBB, BBB)
    BBB = (AAA, ZZZ)
    ZZZ = (ZZZ, ZZZ)
    """

  def input(:test3),
    do: """
    LR

    11A = (11B, XXX)
    11B = (XXX, 11Z)
    11Z = (11B, XXX)
    22A = (22B, XXX)
    22B = (22C, 22C)
    22C = (22Z, 22Z)
    22Z = (22B, 22B)
    XXX = (XXX, XXX)
    """

  def input(:real), do: Input.load(__DIR__ &lt;&gt; "/input.txt")

  def solve(1, mode) do
    __MODULE__.Part1.solve(input(mode))
  end

  def solve(2, mode) do
    __MODULE__.Part2.solve(input(mode))
  end

  defmodule Part1 do
    def solve(input) do
      input
      |&gt; parse()
      |&gt; build_tree()
      |&gt; traverse_instructions()
    end

    def parse(input) do
      input
      |&gt; Input.Parser.parser()
      |&gt; elem(1)
    end

    defp build_tree([instructions | tree]) do
      graph =
        tree
        |&gt; Enum.reduce(%{}, fn [p, l, r], acc -&gt;
          Map.put(acc, p, %{~c"L" =&gt; l, ~c"R" =&gt; r})
        end)

      {instructions, graph}
    end

    defp traverse_instructions({instructions, tree}) do
      instructions
      |&gt; Stream.cycle()
      |&gt; Enum.reduce_while({~c"AAA", 0}, fn direction, {key, steps} -&gt;
        if key == ~c"ZZZ" do
          {:halt, steps}
        else
          {:cont, {tree[key][[direction]], steps + 1}}
        end
      end)
    end
  end

  defmodule Part2 do
    def solve(input) do
      input
      |&gt; parse()
      |&gt; build_tree()
      |&gt; traverse_all_starting_nodes()
      |&gt; Enum.reduce(&amp;AocToolbox.Math.lcm(&amp;1, &amp;2))
    end

    defp parse(input) do
      Part1.parse(input)
    end

    defp build_tree([instructions | tree]) do
      {instructions,
       tree
       |&gt; Enum.reduce({%{}, MapSet.new()}, fn
         [[_, _, ?A] = p, l, r], {graph, starters} -&gt;
           {Map.put(graph, p, %{~c"L" =&gt; l, ~c"R" =&gt; r}), MapSet.put(starters, p)}

         [p, l, r], {graph, starters} -&gt;
           {Map.put(graph, p, %{~c"L" =&gt; l, ~c"R" =&gt; r}), starters}
       end)}
    end

    defp traverse_all_starting_nodes({instructions, {tree, starters}}) do
      starters
      |&gt; Task.async_stream(fn starter -&gt;
        instructions
        |&gt; Stream.cycle()
        |&gt; Enum.reduce_while({starter, 0}, fn direction, {key, steps} -&gt;
          if match?([_, _, ?Z], key) do
            {:halt, steps}
          else
            {:cont, {tree[key][[direction]], steps + 1}}
          end
        end)
      end)
      |&gt; Enum.map(&amp;elem(&amp;1, 1))
    end
  end
end
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="310851" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-8/60244/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-310851" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="310851"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #16"></div>
  </section>
</div>
    <div class="postbit" id="310856" data-post-id="310856">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Aetherus" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Aetherus/120/17203_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Aetherus
                      <span class="op-star" title="Thread Starter">
                        <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                      </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="stevensonmt" data-post="17" data-topic="60244">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/stevensonmt/48/20503_2.png" class="avatar"> stevensonmt:</div>
<blockquote>
<p>Can anyone think of a counter example where the cycle of the instructions and the length of at least one path from start to finish are such you could endlessly cycle with out ever repeating?</p>
</blockquote>
</aside>
<p>I guess that’s impossible. If there’s a loop in the path, then starting from the ghost enters the loop, after at most <code>lcm(instruction_length, loop_circumfrerence_length)</code>, the ghost will go back to its starting point in the loop.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="310856" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-8/60244/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-310856" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="310856"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #17"></div>
  </section>
</div>
    <div class="postbit" id="310943" data-post-id="310943">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="seeplusplus" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/seeplusplus/120/32772_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  seeplusplus
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="stevensonmt" data-post="17" data-topic="60244">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/stevensonmt/48/20503_2.png" class="avatar"> stevensonmt:</div>
<blockquote>
<p>Can anyone think of a counter example where the cycle of the instructions and the length of at least one path from start to finish are such you could endlessly cycle with out ever repeating?</p>
</blockquote>
</aside>
<p>I’ve had this in draft and haven’t finished writing all I wanted to, day 10 sucked away most of my time from giving this the full attention I wanted to. The short answer is it’s not possible.</p>
<p>The longer answer is that it is sort of possible, but maybe not as interesting as one might hope. One <em>could</em> create a solvable puzzle input s.t. one of the ghosts path gets stuck in a loop that <em>doesn’t</em> include the room Z*. To do this, you need only make sure that the number of steps from the ghost start room to its Z is divisible by the lengths of the other paths. E.g., if the other ghosts reach their Z rooms, in say, 2, 3, and 5 steps you could create such a path that took the ghost 30 steps to reach its Z room, then after that got stuck in a loop and never returned to Z. This path doesn’t repeat Z ever, but is still solvable because the other paths repeat.</p>
<p>*this isn’t exactly what you asked, you can’t have a path go on endlessly without ever repeating, because endless implies infinite steps and as you know the number of rooms is finite, so you <em>must</em> repeat at some point.</p>
<p><strong>Edit</strong>: as I mentioned above, I didn’t get to write the full post I was originally planning on writing. There are some other interesting things in this puzzle I didn’t first notice. We all know that the answer to pt 2 is the lcm of all of the ghosts paths, but did you also know that each of the ghosts answers is divisible by the length of the instructions? This isn’t technically a requirement to make the puzzle solvable (the example input for pt 2 does not have this property), but something interesting I noticed.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="310943" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-8/60244/19">Post #18</a>
	                </div>
	            </div>
              <div id="likers-container-310943" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="310943"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #18"></div>
  </section>
</div>
    <div class="postbit" id="311088" data-post-id="311088">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="al2o3cr" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/al2o3cr/120/3457_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  al2o3cr
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="seeplusplus" data-post="19" data-topic="60244">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/seeplusplus/48/32772_2.png" class="avatar"> seeplusplus:</div>
<blockquote>
<p>but did you also know that each of the ghosts answers is divisible by the length of the instructions</p>
</blockquote>
</aside>
<p>I suspect this is an artifact of the problem-generation process, but it has an interesting consequence: applying the whole sequence of moves to <em>every</em> starting point creates a <strong>permutation</strong> of the points.</p>
<p>That turns “apply the whole sequence of moves N times” into “apply a single permutation N times”, and then <a href="https://en.wikipedia.org/wiki/Cyclic_permutation#Basic_properties" rel="nofollow">fundamental mathematical properties</a> tell us that permutation has multiple disjoint cycles.</p>
<p>Going to try applying one of the “write a permutation in cycle notation” algorithms for part 2 - I suspect the sizes of the cycles will be very familiar.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="311088" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-8/60244/20">Post #19</a>
	                </div>
	            </div>
              <div id="likers-container-311088" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="311088"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #19"></div>
  </section>
</div>
    <div class="postbit" id="311143" data-post-id="311143">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="al2o3cr" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/al2o3cr/120/3457_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  al2o3cr
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Still haven’t done the “convert to cycle notation” part, but the transformation to a permutation works (at least for my input):</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Day8Part2 do
  def read(filename) do
    [path | map] =
      filename
      |&gt; File.read!()
      |&gt; String.split("\n", trim: true)

    {parse_path(path), parse_map(map)}
  end

  defp parse_path(path) do
    path
    |&gt; String.split("", trim: true)
    # |&gt; Stream.cycle()
  end

  @regex ~r/([A-Z]{3})\s+=\s+\(([A-Z]{3}),\s+([A-Z]{3})/

  defp parse_map(map) do
    map
    |&gt; Enum.map(&amp;Regex.run(@regex, &amp;1, capture: :all_but_first))
    |&gt; Map.new(fn [x, l, r] -&gt; {x, %{"L" =&gt; l, "R" =&gt; r}} end)
  end

  def step(direction, from, map) do
    map[from][direction]
  end

  def start?(point) do
    String.ends_with?(point, "A")
  end

  def done?(point) do
    String.ends_with?(point, "Z")
  end

  def perm_multiply(p1, p2) do
    Map.new(p1, fn {k, v} -&gt; {k, p2[v]} end)
  end

  def perm_power(p, n) when rem(n, 2) == 0 do
    perm_power(perm_multiply(p, p), div(n, 2))
  end

  def perm_power(p, 1), do: p

  def perm_power(p, n) when n &gt; 0 do
    perm_multiply(p, perm_power(p, n-1))
  end
end

{path, map} = Day8Part2.read("input.txt")

step = fn dir, froms -&gt;
  Enum.map(froms, &amp;Day8Part2.step(dir, &amp;1, map))
end

starts = Map.keys(map)

one_cycle = Enum.reduce(path, starts, step)

permutation =
  starts
  |&gt; Enum.zip(one_cycle)
  |&gt; Map.new()

product =
  Day8Part2.perm_power(permutation, LARGE_NUMBER_WITH_SIX_FACTORS)

product
|&gt; Map.filter(fn {k, _} -&gt; Day8Part2.start?(k) end)
|&gt; IO.inspect()
</code></pre>
<p>The exponent passed to <code>perm_power</code> is the answer for part 2 divided by the length of the move sequence. For my input, this prints:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">%{
  "AAA" =&gt; "ZZZ",
  "DTA" =&gt; "FQZ",
  "JHA" =&gt; "TBZ",
  "MMA" =&gt; "QDZ",
  "NCA" =&gt; "LQZ",
  "TVA" =&gt; "FNZ"
}
</code></pre>
<p>which is <em>where</em> the ghosts ended up at the end of the many trillions of steps!</p>
<p>Another interesting fact: using a smaller exponent with only some of the factors from the final answer will give the position of the ghosts when only some of them were at points ending in “Z”:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">%{
  "AAA" =&gt; "KGP",
  "DTA" =&gt; "FQZ",   # &lt;===
  "JHA" =&gt; "KXQ",
  "MMA" =&gt; "CVC",
  "NCA" =&gt; "LQZ",   # &lt;===
  "TVA" =&gt; "FBH"
}
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="311143" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-8/60244/21">Post #20</a>
	                </div>
	            </div>
              <div id="likers-container-311143" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="311143"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>