<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="311133" data-post-id="311133">
  <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>Too slow to edit my last post. Once I had the thought of getting the area of an irregular polygon it was just a matter of realizing you have to subtract the nodes on the perimeter from that area. Re-wrote my pt 1 to make it reusable for pt 2.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Day10 do
  @moduledoc """
  Day10 AoC Solutions
  """

  alias AocToolbox.Input

  def input(:test),
    do: """
    .....
    .S-7.
    .|.|.
    .L-J.
    .....
    """

  def input(:test2),
    do: """
    ..F7.
    .FJ|.
    SJ.L7
    |F--J
    LJ...
    """

  def input(:test3),
    do: """
    ...........
    .S-------7.
    .|F-----7|.
    .||.....||.
    .||.....||.
    .|L-7.F-J|.
    .|..|.|..|.
    .L--J.L--J.
    ...........
    """

  def input(:test4),
    do: """
    .F----7F7F7F7F-7....
    .|F--7||||||||FJ....
    .||.FJ||||||||L7....
    FJL7L7LJLJ||LJ.L-7..
    L--J.L7...LJS7F-7L7.
    ....F-J..F7FJ|L7L7L7
    ....L7.F7||L7|.L7L7|
    .....|FJLJ|FJ|F7|.LJ
    ....FJL-7.||.||||...
    ....L---J.LJ.LJLJ...
    """

  def input(:test5),
    do: """
    FF7FSF7F7F7F7F7F---7
    L|LJ||||||||||||F--J
    FL-7LJLJ||||||LJL-77
    F--JF--7||LJLJ7F7FJ-
    L---JF-JLJ.||-FJLJJ7
    |F|F-JF---7F7-L7L|7|
    |FFJF7L7F-JF7|JL---7
    7-L-JL7||F7|L7F-7F7|
    L.L7LFJ|||||FJL7||LJ
    L7JLJL-JLJLJL--JLJ.L
    """

  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
    @direction %{0 =&gt; :north, 1 =&gt; :south, 2 =&gt; :east, 3 =&gt; :west}

    def solve(input) do
      input
      |&gt; parse()
      |&gt; find_loop()
      |&gt; furthest_distance()
    end

    def parse(input) do
      input
      |&gt; Input.lines()
      |&gt; Enum.with_index()
      |&gt; Enum.flat_map(fn {line, ndx} -&gt;
        line
        |&gt; String.graphemes()
        |&gt; Enum.with_index()
        |&gt; Enum.map(fn {char, ndx2} -&gt; {ndx, {ndx2, char}} end)
      end)
      |&gt; Enum.reduce({:digraph.new(), {}}, fn {k1, {k2, v}}, {g, start} = acc -&gt;
        case v do
          "." -&gt;
            acc

          "S" -&gt;
            :digraph.add_vertex(g, {k1, k2}, v)
            {g, {k1, k2}}

          _ -&gt;
            :digraph.add_vertex(g, {k1, k2}, v)
            {g, start}
        end
      end)
    end

    def find_loop({graph, start}) do
      start
      |&gt; neighbors()
      |&gt; Enum.map(&amp;:digraph.vertex(graph, &amp;1))
      |&gt; Enum.with_index()
      |&gt; Enum.filter(fn {v, _} -&gt; v end)
      |&gt; Enum.map(fn {v, i} -&gt; {v, @direction[i]} end)
      |&gt; Task.async_stream(fn {v, direction} -&gt;
        conn(graph, v, direction, 1, [start])
      end)
      |&gt; Stream.filter(fn res -&gt;
        res != {:ok, {:err, :dead_end}}
      end)
      |&gt; Enum.at(0)
    end

    def conn(graph, {coord, label}, incoming_direction, count \\ 1, path \\ []) do
      case {label, incoming_direction} do
        {"-", :east} -&gt; next_step(graph, east(coord), count + 1, :east, [coord | path])
        {"-", :west} -&gt; next_step(graph, west(coord), count + 1, :west, [coord | path])
        {"|", :north} -&gt; next_step(graph, north(coord), count + 1, :north, [coord | path])
        {"|", :south} -&gt; next_step(graph, south(coord), count + 1, :south, [coord | path])
        {"J", :east} -&gt; next_step(graph, north(coord), count + 1, :north, [coord | path])
        {"J", :south} -&gt; next_step(graph, west(coord), count + 1, :west, [coord | path])
        {"L", :west} -&gt; next_step(graph, north(coord), count + 1, :north, [coord | path])
        {"L", :south} -&gt; next_step(graph, east(coord), count + 1, :east, [coord | path])
        {"F", :west} -&gt; next_step(graph, south(coord), count + 1, :south, [coord | path])
        {"F", :north} -&gt; next_step(graph, east(coord), count + 1, :east, [coord | path])
        {"7", :east} -&gt; next_step(graph, south(coord), count + 1, :south, [coord | path])
        {"7", :north} -&gt; next_step(graph, west(coord), count + 1, :west, [coord | path])
        _ -&gt; {:err, :dead_end}
      end
    end

    def next_step(graph, curr, count, dir, path) do
      case {:digraph.vertex(graph, curr), dir} do
        {false, _} -&gt; {:err, :dead_end}
        {{^curr, "."}, _} -&gt; {:err, :dead_end}
        {{^curr, "S"}, _} -&gt; {:ok, count, path}
        {{coord, label}, dir} -&gt; conn(graph, {coord, label}, dir, count, path)
      end
    end

    def neighbors({{r, c}, _}), do: neighbors({r, c})

    def neighbors(coord) do
      [north(coord), south(coord), east(coord), west(coord)]
    end

    defp north({r, c}), do: {r - 1, c}
    defp south({r, c}), do: {r + 1, c}
    defp east({r, c}), do: {r, c + 1}
    defp west({r, c}), do: {r, c - 1}

    defp furthest_distance({_, {_, n, _path}}), do: ceil(n / 2)
  end

  defmodule Part2 do
    @moduledoc """
    Do part 1, building the path for the loop. Use the shoelace formula to get the area bounded by the loop.
    Subtract the length of the loop to get the number of blocks enclosed by the loop.
    """
    def solve(input) do
      input
      |&gt; parse()
      |&gt; Day10.Part1.find_loop()
      |&gt; elem(1)
      |&gt; elem(2)
      |&gt; calc_interior_points()
    end

    defp calc_interior_points(path) do
      perimeter = length(path)
      area = AocToolbox.Math.shoelace_formula(path)
      area - perimeter / 2 + 1
    end

    defp parse(input) do
      Day10.Part1.parse(input)
    end
  end
end
#########
defmodule AocToolbox.Math do
  defp do_shoelace([[r1 | r_tl] = rows, [c1 | c_tl] = cols]) do
    blue = Enum.zip(rows, c_tl ++ [c1]) |&gt; Enum.reduce(0, fn {r, c}, sum -&gt; sum + r * c end)

    red = Enum.zip(cols, r_tl ++ [r1]) |&gt; Enum.reduce(0, fn {c, r}, sum -&gt; sum + c * r end)
    (abs(blue - red) / 2) |&gt; floor()
  end
end
</code></pre>
<p>Would have been cool to try it with Nx but now I’m too far behind to keep tinkering.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="311133" 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-10/60279/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-311133" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="311133"
                     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="311899" data-post-id="311899">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="APB9785" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/APB9785/120/24101_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  APB9785
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of ECSx</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I was close to giving up on Part 2, because I couldn’t get the logic quite right for determining whether a given coordinate was inside or outside the loop.  Whenever I would fix one case, a different one would start failing.  Then I realized - I was only looking at the current symbol in isolation.  But in fact, a corner pipe (e.g. “L” or “J”) means something different depending on the <em>previous</em> corner pipe.  Once I started keeping a buffer of the last seen corner pipe, I could finally know for sure whether we were “opening” or “closing” the loop.  If it goes back in the same direction it came, the <code>inside?</code> flag is unchanged.  But if the pair of corners send the pipes in opposite directions, then it works the same as a <code>"-"</code> symbol, flipping the flag to <code>!inside?</code></p>
<p>Example, scanning columns vertically:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defp area_in_col([{{_, y}, "J"} | next], inside?, {_prev_y, prev_symbol}, total) do
  now_inside? = if prev_symbol == "7", do: inside?, else: !inside?
  area_in_col(next, now_inside?, {y, "J"}, total)
end
</code></pre>
<p>Full solution <a href="https://github.com/APB9785/AoC-2023-elixir/blob/master/lib/advent_2023/day_10.ex" rel="noopener nofollow ugc">here on Github</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="311899" 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-10/60279/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-311899" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="311899"
                     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="313422" data-post-id="313422">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Part 2 I only was able to solve after watching this video where it was introduced to the Ray Casting Algorithm <a href="https://www.youtube.com/watch?v=zhmzPQwgPg0&amp;t=425s" rel="noopener nofollow ugc">Day 10: Pipe Maze | Advent of Code 2023</a></p>
<p>So first it traverses the sketch map by keeping track of the pipes of the loop by adding them to a MapSet, then to count the points inside the loop it traverses the whole sketch map by checking if a point is not in the pipes loop and if not it applies the Ray Casting to count the intersections with the pipes in the loop.</p>
<p>So here’s my code following what was suggested there:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># "F" and "7" are not edge pipes because let's say a line passes
  # through an "L" and a "7", which means the line only intersects the edge of the polygon once.
  # This video explains it: https://www.youtube.com/watch?v=zhmzPQwgPg0&amp;t=425s
  @edge_pipes ["L", "J", "|"]

def part_two(input, {row_dir, col_dir} = start_direction, pipe_of_s) do
    {sketch_map, {start_row, start_col}} =
      input
      |&gt; parse_sketch_to_map_finding_start_position()

    pipes_in_loop =
      move_keeping_track_of_pipes(
        Map.get(sketch_map, {start_row + row_dir, start_col + col_dir}),
        {start_row + row_dir, start_col + col_dir},
        start_direction,
        sketch_map,
        MapSet.new() |&gt; MapSet.put({start_row, start_col})
      )

    {row_length, col_length} = get_sketch_dimensions(input)

    sketch_map = Map.update(sketch_map, {start_row, start_col}, pipe_of_s, fn _ -&gt; pipe_of_s end)

    1..(row_length - 2)
    |&gt; Enum.reduce(0, fn row, acc -&gt;
      1..(col_length - 2)
      |&gt; Enum.reduce(acc, fn col, acc -&gt;
        if MapSet.member?(pipes_in_loop, {row, col}) do
          acc
        else
          # traverse row applying the ray casting algorithm
          # https://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm
          col + 1..col_length - 1
          |&gt; Enum.reduce(0, fn col_inner_loop, ray_casting_acc -&gt;
            if MapSet.member?(pipes_in_loop, {row, col_inner_loop}) &amp;&amp; sketch_map[{row, col_inner_loop}] in @edge_pipes do
              ray_casting_acc + 1
            else
              ray_casting_acc
            end
          end)
          |&gt; then(&amp;(if rem(&amp;1, 2) == 1, do: acc + 1, else: acc))
        end
      end)
    end)
  end
</code></pre>
<p>The full code is here: <a href="https://github.com/tiagoavila/advent_of_code_2023/blob/main/lib/day_ten.ex" class="inline-onebox" rel="noopener nofollow ugc">advent_of_code_2023/lib/day_ten.ex at main · tiagoavila/advent_of_code_2023 · GitHub</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="313422" 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-2023-day-10/60279/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-313422" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="313422"
                     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>