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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I hope people don’t mind us chiming in with our experiences/solutions well after the fact, because I<br>
came here to share a unique approach to Part Two which proved quite effective.  I had no clear idea<br>
what the Christmas tree would look like, but I figured it would probably involve statistically unlikely<br>
clustering of the robots in both x and y coordinates.  So I came up with the following measure.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  @fuzz 5  # Defines binning of locations to look for robot clusters
  def find_interesting(robots, dims, count, threshold) do
    {w, h} = dims
    rcount = Enum.count(robots)
    avg_ctx = @fuzz * rcount / w
    avg_cty = @fuzz * rcount / h
    thresh_ctx = avg_ctx + threshold * :math.sqrt(avg_ctx)
    thresh_cty = avg_ctx + threshold * :math.sqrt(avg_cty)
    Enum.filter(1..count, fn t -&gt;
      robots = Robots.move_robots(robots, dims, t)
      {cts_x, cts_y} = Enum.reduce(robots, {%{}, %{}}, fn {{x, y}, _v}, {cx, cy} -&gt;
        {Map.update(cx, div(x, @fuzz), 1, fn c -&gt; c + 1 end),
          Map.update(cy, div(y, @fuzz), 1, fn c -&gt; c + 1 end)}
      end)
      Enum.any?(cts_x, fn {_x, c} -&gt; c &gt; thresh_ctx end) and 
        Enum.any?(cts_y, fn {_y, c} -&gt; c &gt; thresh_cty end)
    end)
  end
</code></pre>
<p>It worked beautifully on my input data with a <code>threshold</code> of 4 (roughly speaking, the threshold here is<br>
the number of standard deviations away from the mean of robot counts in a horizontal or vertical<br>
stripe, assuming Poisson counting statistics for the robots landing in the stripe).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="351925" 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-2024-day-14/68091/32">Post #31</a>
	                </div>
	            </div>
              <div id="likers-container-351925" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="351925"
                     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 #31"></div>
  </section>
</div>
    <div class="postbit" id="351982" data-post-id="351982">
  <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>Part 2 very dissatisfying. I tried a couple of approaches that I was clearly not smart enough to implement. I tried checking that a high percentage of bots were contained within a triangle using barycentric coordinates to confirm presence within the triangle. I think I either set the threshold too high or screwed up the implementation b/c it would run forever without finding it.</p>
<p>I then tried to find a state where a high percentage of bots had mirror image bots across a line of reflection. I think I screwed this up by again setting the threshold too high.</p>
<p>Finally I just looked for a state where at least 20 bots were in at least one column and 20 bots were in at least one row. That worked but feels like blind luck.</p>
<p>EDIT: Yeah, setting the threshold to a super majority of bots was way off. Setting it to 20% of the bots having mirrored bots is good enough. I think the problem was worded such that it is misleading to say “most of the robots” arrange into the Christmas tree. Pretty sure my tree has fewer than half the bots in it.</p>
<p>EDIT 2: Got my barycentric triangle method working. It requires a slightly higher threshold than the mirrored bots method to avoid false positive.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">def find_tree() do
      Stream.repeatedly(fn -&gt; Robot.move_all(1) end)
      |&gt; Enum.reduce_while(1, fn :ok, time -&gt;
        if tree_shape?() do
          {:halt, time}
        else
          {:cont, time + 1}
        end
      end)
    end

    defp tree_shape?() do
      min_bots =
        case :ets.lookup_element(:board, :bot_count, 2, false) do
          false -&gt;
            x = Robot.bot_count()
            :ets.insert(:board, {:bot_count, x})
            0.4 * x

          x -&gt;
            0.4 * x
        end

      # min_bots in symmetric pattern bounded by isosceles triangle
      # triangle has area == min_bots and assume ht == base
      # bots inside triangle have mirror or are on center line
      botspots =
        all_occupants()
        |&gt; Enum.map(fn {pos, _name} -&gt; pos end)
        |&gt; MapSet.new()

      [ht, wd] = [:height, :width] |&gt; Enum.map(fn k -&gt; :ets.lookup_element(:board, k, 2) end)
      reflect = 50
      triangle = [{reflect, 30}, {30, ht - 30}, {wd - 30, ht - 30}]

      # botspots |&gt; long_line?()
      botspots
      |&gt; Stream.filter(fn pos -&gt;
        # has_mirror?(pos, reflect, botspots)

        in_triangle?(pos, triangle)
      end)
      |&gt; Enum.reduce_while(0, fn _pos, acc -&gt;
        print_board()

        if acc &lt; min_bots do
          {:cont, acc + 1}
        else
          {:halt, acc}
        end
      end)
      |&gt; Kernel.&gt;=(min_bots)
    end

    @doc "Use barycentric coordinates (alpha, beta, gamma) to determine if point lies within
    the bounding triangle (simplex). The barycentric coordinates with any value of zero are on the
    simplex lines. Any negative values are outside the simplex. The values are the ratio of the 
    area of the sub triangle formed by the point and any two vertices of the simplex to the area
    of the simplex."
    def in_triangle?({px, py}, [{ax, ay}, {bx, by}, {cx, cy}]) do
      area_triangle = abs(ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)) / 2
      alpha = abs((bx - px) * (cy - py) - (cx - px) * (by - py)) / (2 * area_triangle)
      beta = abs((cx - px) * (ay - py) - (ax - px) * (cy - py)) / (2 * area_triangle)
      gamma = 1 - alpha - beta

      [alpha, beta, gamma] |&gt; Enum.all?(fn n -&gt; n &gt;= 0 and n &lt;= 1 end)
    end

    def has_mirror?({reflect, _y}, reflect, _botspots), do: true

    def has_mirror?({x, y}, reflect, botspots) do
      opposite = reflect * 2 - x

      MapSet.member?(botspots, {opposite, y})
    end

    def long_line?(botspots) do
      print_board()

      botspots
      |&gt; Enum.group_by(fn {x, _} -&gt; x end)
      |&gt; Enum.any?(fn {_, v} -&gt; length(v) &gt; 20 end) and
        botspots
        |&gt; Enum.group_by(fn {_, y} -&gt; y end)
        |&gt; Enum.any?(fn {_, v} -&gt; length(v) &gt; 20 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="351982" 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-2024-day-14/68091/33">Post #32</a>
	                </div>
	            </div>
              <div id="likers-container-351982" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="351982"
                     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 #32"></div>
  </section>
</div>
    <div class="postbit" id="352082" data-post-id="352082">
  <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>Can’t edit my post further due to time limit.</p>
<p>EDIT 3: Thinking about this this morning again, I’m wondering if anyone tried a pure math approach? I’m thinking if you calculate the time for each bot to individually get to the midline, then calculate the cycle for each bot to return to midline, you can find a common time with some minimum number of bots in the midline.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">(time_0 * vx) + start_x % width == mid_x 
# gives time to reach midline first by solving for time_0
(time_c * vx) + mid_x % width == mid_x 
# gives time to cycle back to midline by solving for time_c
# find a subset of bots_all of size i where i is the threshold number of bots specified such that subset_bots(0..i) satisfies:
time_00 + n_0 * time_c0 == time_01 + n_1 * time_c1 ... == time_0i + n_i * time_ci  for bots 0..i
</code></pre>
<p>I’ve forgotten (or possibly never knew) the math on how to solve that last bit though.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="352082" data-batch-url="/posts/batch_likers">
                        0
                      </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-2024-day-14/68091/34">Post #33</a>
	                </div>
	            </div>
              <div id="likers-container-352082" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="352082"
                     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>