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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bjorng" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bjorng/120/13187_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bjorng
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Erlang Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>My solution:</p>
<p><a href="https://github.com/bjorng/advent-of-code-2023/blob/main/day03/lib/day03.ex" class="onebox" target="_blank" rel="noopener nofollow ugc">https://github.com/bjorng/advent-of-code-2023/blob/main/day03/lib/day03.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="309834" 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-3/60113/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-309834" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="309834"
                     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="309839" data-post-id="309839">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><a href="https://github.com/viniciusmuller/aoc2023/blob/main/day3/day03.exs" class="onebox" target="_blank" rel="noopener nofollow ugc">https://github.com/viniciusmuller/aoc2023/blob/main/day3/day03.exs</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="309839" 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-3/60113/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-309839" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="309839"
                     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="309852" data-post-id="309852">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I have to admit, my favorite part of these puzzles is</p>
<ol>
<li>Seeing if I can parse the input into a structure that is useful for parts one and two</li>
<li>Seeing if I can break apart part one into functions also useful for part two</li>
</ol>
<p>Essentially, seeing if I can implement good abstractions upfront. Today was a good day for that!</p>
<h2><a name="p-309852-input-1" class="anchor" href="#p-309852-input-1" aria-label="Heading link" rel="nofollow"></a>Input</h2>
<details><summary>Processing</summary>
<p>The datastructure I chose to use here was <code>{symbols, numbers}</code>, each as maps, with their indexed location in the grid as the keys and the parsed data from the grid as the values. In the case of numbers, their column index is a range representing their span in the grid.</p>
<details><summary>Types</summary>
<pre data-code-wrap="elixir"><code class="lang-elixir">@type index :: non_neg_integer()

@type symbol_index :: {row_num :: index(), col_num :: index()}

@type symbols :: %{
  symbol_index() =&gt; symbol :: String.t()
}

@type number_index :: {row_num :: index(), col_num :: Range.t()}

@type numbers :: %{
  number_index() =&gt; number :: non_neg_integer()
}

@type input :: {symbols(), numbers()}
</code></pre>
</details>
<details><summary>Example Input</summary>
<pre data-code-wrap="elixir"><code class="lang-elixir">{symbols, numbers} = {%{
   {1, 3} =&gt; "*",
   {3, 6} =&gt; "#",
   {4, 3} =&gt; "*",
   {5, 5} =&gt; "+",
   {8, 3} =&gt; "$",
   {8, 5} =&gt; "*"
 },
 %{
   {0, 0..2} =&gt; 467,
   {0, 5..7} =&gt; 114,
   {2, 2..3} =&gt; 35,
   {2, 6..8} =&gt; 633,
   {4, 0..2} =&gt; 617,
   {5, 7..8} =&gt; 58,
   {6, 2..4} =&gt; 592,
   {7, 6..8} =&gt; 755,
   {9, 1..3} =&gt; 664,
   {9, 5..7} =&gt; 598
 }}
</code></pre>
</details>
<p><code>Regex.scan(regex, string, return: :index)</code> carried the day. I never really use it for anything but programming puzzles where I am indexing into a string grid, but boy is it handy here.</p>
<p>Source code available <a href="https://github.com/christhekeele/aoc/blob/main/2023/day/3/input.ex" rel="noopener nofollow ugc">here</a>.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule AoC.Day.Three.Input do
  def parse(input_file \\ System.fetch_env!("INPUT_FILE")) do
    input_file
    |&gt; File.read!()
    |&gt; String.split("\n")
    |&gt; Enum.with_index()
    |&gt; Enum.reduce({%{}, %{}}, fn {row, y}, {symbols, numbers} -&gt;
      symbols = scan_symbols({row, y}, symbols)
      numbers = scan_numbers({row, y}, numbers)

      {symbols, numbers}
    end)
  end

  def scan_symbols({row, y}, symbols) do
    Regex.scan(~r{[^\d\.]}, row, return: :index)
    |&gt; List.flatten()
    |&gt; Enum.reduce(symbols, fn {x, 1}, symbols -&gt;
      Map.put(symbols, {y, x}, String.at(row, x))
    end)
  end

  def scan_numbers({row, y}, numbers) do
    Regex.scan(~r{\d+}, row, return: :index)
    |&gt; List.flatten()
    |&gt; Enum.reduce(numbers, fn {x, length}, numbers -&gt;
      x_start = x
      x_end = x + length - 1

      number =
        row
        |&gt; String.slice(x_start..x_end)
        |&gt; String.to_integer()

      Map.put(numbers, {y, x_start..x_end}, number)
    end)
  end
end
</code></pre>
</details>
<h2><a name="p-309852-part-one-2" class="anchor" href="#p-309852-part-one-2" aria-label="Heading link" rel="nofollow"></a>Part One</h2>
<details><summary>Solution</summary>
<p>My adjacency check here is not as inefficient as scanning the whole grid ever time, but still suboptimal. It was easy and fun to implement, thought. It checks every symbol against every number.</p>
<p>A more optimal approach would probably be to generate the indices of every possible symbol location around each number, and do a lookup to see if there was an entry (or vice-versa).</p>
<p>I don’t love the variable names I came up with in the adjacency logic, but readability is less at a premium in these sorts of application as being able to see where the different <code>- 1</code>s and <code>+ 1</code>s are, and terseness helps there.</p>
<p>Source code available <a href="https://github.com/christhekeele/aoc/blob/main/2023/day/3/part/1.ex" rel="noopener nofollow ugc">here</a>.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule AoC.Day.Three.Part.One do
  def solve({symbols, numbers}) do
    symbols
    |&gt; Enum.map(&amp;adjacent_numbers_indices(&amp;1, numbers))
    |&gt; List.flatten()
    |&gt; Enum.uniq()
    |&gt; Enum.map(&amp;Map.get(numbers, &amp;1))
    |&gt; Enum.sum()
  end

  def adjacent_numbers_indices({symbol_index, _symbol}, numbers) do
    numbers
    |&gt; Map.keys()
    |&gt; Enum.filter(&amp;adjacent?(symbol_index, &amp;1))
  end

  # The geometry of considers 8 neighbours to be adjacent, cardinals and diagonals
  # We hardcode these in function heads, going clockwise, starting north
  def adjacent?(symbol_index, number_index)

  # North
  def adjacent?({s_y, s_x}, {n_y, n_xs..n_xe})
      when s_y + 1 == n_y and s_x in n_xs..n_xe,
      do: true

  # North-East
  def adjacent?({s_y, s_x}, {n_y, n_xs..n_xe})
      when s_y + 1 == n_y and (s_x + 1) in n_xs..n_xe,
      do: true

  # East
  def adjacent?({s_y, s_x}, {n_y, n_xs..n_xe})
      when s_y == n_y and (s_x + 1) in n_xs..n_xe,
      do: true

  # South-East
  def adjacent?({s_y, s_x}, {n_y, n_xs..n_xe})
      when s_y - 1 == n_y and (s_x + 1) in n_xs..n_xe,
      do: true

  # South
  def adjacent?({s_y, s_x}, {n_y, n_xs..n_xe})
      when s_y - 1 == n_y and s_x in n_xs..n_xe,
      do: true

  # South-West
  def adjacent?({s_y, s_x}, {n_y, n_xs..n_xe})
      when s_y - 1 == n_y and (s_x - 1) in n_xs..n_xe,
      do: true

  # West
  def adjacent?({s_y, s_x}, {n_y, n_xs..n_xe})
      when s_y == n_y and (s_x - 1) in n_xs..n_xe,
      do: true

  # North-West
  def adjacent?({s_y, s_x}, {n_y, n_xs..n_xe})
      when s_y + 1 == n_y and (s_x - 1) in n_xs..n_xe,
      do: true

  def adjacent?(_symbol_index, _number_index), do: false
end
</code></pre>
</details>
<h2><a name="p-309852-part-two-3" class="anchor" href="#p-309852-part-two-3" aria-label="Heading link" rel="nofollow"></a>Part Two</h2>
<details><summary>Solution</summary>
<p>Exactly what you want to see: use the same datastructure you developed for part one, use functions from part one to solve! Source code available <a href="https://github.com/christhekeele/aoc/blob/main/2023/day/3/part/2.ex" rel="noopener nofollow ugc">here</a>.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule AoC.Day.Three.Part.Two do
  @gear "*"

  import AoC.Day.Three.Part.One

  def solve({symbols, numbers}) do
    symbols
    |&gt; Enum.filter(fn {_index, symbol} -&gt; symbol == @gear end)
    |&gt; Enum.map(&amp;adjacent_numbers_indices(&amp;1, numbers))
    |&gt; Enum.filter(&amp;(length(&amp;1) == 2))
    |&gt; Enum.reduce(0, fn [gear1, gear2], acc -&gt;
      acc + numbers[gear1] * numbers[gear2]
    end)
  end
end
</code></pre>
</details> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="309852" 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-3/60113/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-309852" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="309852"
                     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="309857" data-post-id="309857">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I did something I didn’t see in other solutions. I created an index of positions for all the numbers, but also added a unique id to each number. That way, the number 467 can be indexed as <code>[{{0,0}, {id_1, 467}}, {{0,1}, {id_1, 467}}, {{0,2}, {id_1, 467}}]</code><br>
That way, adjacency is trivial, and then deduplicating numbers is also trivial (as the same number might be adjacent to a symbol multiple times)</p>
<p>Solution: <a href="https://github.com/juanperi/advent_of_code/blob/master/2023/day_03.ex" class="inline-onebox" rel="noopener nofollow ugc">advent_of_code/2023/day_03.ex at master · juanperi/advent_of_code · 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="309857" 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-3/60113/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-309857" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="309857"
                     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="309876" data-post-id="309876">
  <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>I have not yet looked at the solutions in this thread but I just wanted to state that for day 3 this was a very difficult challenge relative to previous years. I think there may have been an effort to handicap the AI coders with the difficult input parsing this year.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="309876" data-batch-url="/posts/batch_likers">
                        4
                      </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-3/60113/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-309876" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="309876"
                     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="309888" data-post-id="309888">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>It could also be because it’s Sunday, and they’re typically more involved.</p>
<p>I skipped part 2 today, not a fan of these grid challenges in Elixir. I did get part 1 running in 3ms using :ets for constant time lookups though. And I wrote a crazy single-pass binary pattern-matching recursive function to parse the input that I’ll spare you all from seeing <img src="https://forum.elixirforum.com/images/emoji/apple/laughing.png?v=15" title=":laughing:" class="emoji" alt=":laughing:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="309888" 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-3/60113/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-309888" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="309888"
                     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="309901" data-post-id="309901">
  <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>Finally managed to get part 2 correct after completely redoing my parser approach. I still don’t understand the bug my original approach had as it worked for part 1 and the example input for part 2. Still, the second attempt is much cleaner (not CLEAN, but not the mess of spaghetti my first attempt was).<br>
Full code <a href="https://github.com/stevensonmt/advent_of_code/blob/2023/2023/day3/lib/day3.ex" rel="noopener nofollow ugc">here</a>. Just the parser:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Parser do
    alias AocToolbox.Input

    defstruct [
      :max_ndx,
      line: "",
      row: 0,
      ndx: 0,
      graph: %{},
      num_map: %{},
      symbol_neighbors_map: %{}
    ]

    def parse_raw_graph(text) do
      text
      |&gt; Input.lines()
      |&gt; Enum.with_index()
      |&gt; Enum.map(fn {line, row} -&gt;
        parse_lines(%__MODULE__{line: line, row: row, max_ndx: String.length(line)})
      end)
      |&gt; Enum.reduce(fn row, acc -&gt;
        row
        |&gt; Enum.map(fn {key, val} -&gt;
          {key, Map.merge(val, acc[key], fn _, v1, v2 -&gt; MapSet.union(v1, v2) end)}
        end)
      end)
    end

    def parse_lines(%__MODULE__{
          ndx: ndx,
          max_ndx: max_ndx,
          graph: graph,
          num_map: num_map,
          symbol_neighbors_map: symbol_neighbors_map
        })
        when ndx &gt; max_ndx,
        do: [graph: graph, num_map: num_map, symbol_neighbors_map: symbol_neighbors_map]

    def parse_lines(%__MODULE__{
          line: &lt;&lt;".", rest::binary&gt;&gt;,
          row: row,
          ndx: ndx,
          max_ndx: max_ndx,
          graph: graph,
          num_map: num_map,
          symbol_neighbors_map: symbol_neighbors_map
        }),
        do:
          parse_lines(%__MODULE__{
            line: rest,
            row: row,
            ndx: ndx + 1,
            max_ndx: max_ndx,
            graph: Map.put(graph, {row, ndx}, nil),
            num_map: num_map,
            symbol_neighbors_map: symbol_neighbors_map
          })

    def parse_lines(%__MODULE__{
          line: &lt;&lt;?*, rest::binary&gt;&gt;,
          row: row,
          ndx: ndx,
          max_ndx: max_ndx,
          graph: graph,
          num_map: num_map,
          symbol_neighbors_map: symbol_neighbors_map
        }) do
      parse_lines(%__MODULE__{
        line: rest,
        row: row,
        ndx: ndx + 1,
        max_ndx: max_ndx,
        graph: Map.put(graph, {row, ndx}, :gear),
        num_map: num_map,
        symbol_neighbors_map:
          update_symbol_neighbors(symbol_neighbors_map, row, ndx, max_ndx, :gear)
      })
    end

    def parse_lines(%__MODULE__{
          line: &lt;&lt;d, rest::binary&gt;&gt;,
          row: row,
          ndx: ndx,
          max_ndx: max_ndx,
          graph: graph,
          num_map: num_map,
          symbol_neighbors_map: symbol_neighbors_map
        })
        when d &gt; 47 and d &lt; 58 do
      {num, rem_line, last_ndx} = parse_nums(d - 48, rest, ndx)

      graph =
        ndx..last_ndx
        |&gt; Enum.reduce(graph, fn n, g -&gt; Map.update(g, {row, n}, num, fn _ -&gt; num end) end)

      num_map =
        all_associations(ndx, last_ndx, row)
        |&gt; Map.merge(num_map, fn _, v1, v2 -&gt; MapSet.union(v1, v2) end)

      parse_lines(%__MODULE__{
        line: rem_line,
        row: row,
        ndx: last_ndx + 1,
        max_ndx: max_ndx,
        graph: graph,
        num_map: num_map,
        symbol_neighbors_map: symbol_neighbors_map
      })
    end

    def parse_lines(%__MODULE__{
          line: "",
          graph: graph,
          num_map: num_map,
          symbol_neighbors_map: symbol_neighbors_map
        }),
        do: [graph: graph, num_map: num_map, symbol_neighbors_map: symbol_neighbors_map]

    def parse_lines(%__MODULE__{
          line: &lt;&lt;s, rest::binary&gt;&gt;,
          row: row,
          ndx: ndx,
          max_ndx: max_ndx,
          graph: graph,
          num_map: num_map,
          symbol_neighbors_map: symbol_neighbors_map
        }),
        do:
          parse_lines(%__MODULE__{
            line: rest,
            row: row,
            ndx: ndx + 1,
            max_ndx: max_ndx,
            graph: Map.put(graph, {row, ndx}, :symbol),
            num_map: num_map,
            symbol_neighbors_map:
              update_symbol_neighbors(symbol_neighbors_map, row, ndx, max_ndx, :symbol)
          })

    defp parse_nums(acc, &lt;&lt;d, rest::binary&gt;&gt;, ndx) when d &gt; 47 and d &lt; 58 do
      parse_nums(acc * 10 + d - 48, rest, ndx + 1)
    end

    defp parse_nums(acc, bin, ndx), do: {acc, bin, ndx}

    defp all_associations(start, stop, row) do
      start..stop
      |&gt; Enum.to_list()
      |&gt; AocToolbox.Math.permutations()
      |&gt; Enum.map(fn [a | rest] -&gt;
        {{row, a}, MapSet.new(Enum.map(rest, fn b -&gt; {row, b} end))}
      end)
      |&gt; Enum.into(%{})
    end

    defp update_symbol_neighbors(symbol_neighbors_map, row, ndx, max_ndx, symbol) do
      for i &lt;- -1..1,
          j &lt;- -1..1,
          not (i == 0 and j == 0),
          row + i &gt;= 0,
          ndx + j &gt;= 0,
          ndx + j &lt;= max_ndx,
          reduce: symbol_neighbors_map do
        acc -&gt;
          Map.update(acc, {symbol, {row, ndx}}, MapSet.new([{row + i, ndx + j}]), fn curr -&gt;
            MapSet.put(curr, {row + i, ndx + j})
          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="309901" 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-3/60113/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-309901" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="309901"
                     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="309903" data-post-id="309903">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="kip" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/120/1440_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  kip
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>ex_cldr Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>For part 1 I decided to try a “sliding window” approach. After splitting into lines, the code “slides” a window over three adjacent lines simultaneously looking for a number on the second line that is has a symbol somewhere around it.  This limits the amount of parsing done and yes, it’s not very reusable for the second part (which I may not finish today).</p>
<p>It’s not super pretty, but it does run in about 3.5ms on my MacBook Pro (M1 Max). And I do think its quite easy to comprehend.</p>
<details><summary>Preprocessing</summary>
Just split the lines. To ensure a regular window frame for the sliding window, add a border of one "." one each side.
<pre data-code-wrap="elixir"><code class="lang-elixir">  def part_1 do
    input = parse_input()

    find_parts(input, 0, tl(input))
  end

  def parse_input do
    list = String.split(@input, "\n", trim: true)
    length = String.length(hd(list))
    header = String.duplicate(".", length)

    [header | list] ++ [header]
    |&gt; Enum.map(&amp;("." &lt;&gt; &amp;1 &lt;&gt; "."))
  end

# Guards used for surrounding symbol detection
  defguard are_digits(c1, c2, c3) when
    (c1 in ?0..?9 and c2 in ?0..?9 and c3 in ?0..?9)

  defguard are_digits(c1, c2) when
    (c1 in ?0..?9 and c2 in ?0..?9)

  defguard are_digits(c1) when
    (c1 in ?0..?9)

  defguard is_surrounded_by_symbol(l1c1, l1c2, l1c3, l1c4, l1c5, l3c1, l3c2, l3c3, l3c4, l3c5, l2c1, l2c5) when
    (l1c1 != ?. or l1c2 != ?. or l1c3 != ?. or l1c4 != ?. or l1c5 != ?. or
    l3c1 != ?. or l3c2 != ?. or l3c3 != ?. or l3c4 != ?. or l3c5 != ?. or
    l2c1 != ?. or l2c5 != ?.)

  defguard is_surrounded_by_symbol(l1c1, l1c2, l1c3, l1c4, l3c1, l3c2, l3c3, l3c4, l2c1, l2c4) when
    (l1c1 != ?. or l1c2 != ?. or l1c3 != ?. or l1c4 != ?. or
    l3c1 != ?. or l3c2 != ?. or l3c3 != ?. or l3c4 != ?. or
    l2c1 != ?. or l2c4 != ?.)

  defguard is_surrounded_by_symbol(l1c1, l1c2, l1c3, l3c1, l3c2, l3c3, l2c1, l2c3) when
    (l1c1 != ?. or l1c2 != ?. or l1c3 != ?. or
    l3c1 != ?. or l3c2 != ?. or l3c3 != ?. or
    l2c1 != ?. or l2c3 != ?.)
</code></pre>
</details>
<details><summary>Part 1</summary>
<pre data-code-wrap="elixir"><code class="lang-elixir">  # Three digit number
  def find_parts([&lt;&lt;l1c1, l1c2, l1c3, l1c4, l1c5, l1_rest::binary&gt;&gt;, &lt;&lt;l2c1, l2c2, l2c3, l2c4, l2c5, l2_rest::binary&gt;&gt;, &lt;&lt;l3c1, l3c2, l3c3, l3c4, l3c5, l3_rest::binary&gt;&gt; | rest], acc, tail)
      when are_digits(l2c2, l2c3, l2c4) and
        is_surrounded_by_symbol(l1c1, l1c2, l1c3, l1c4, l1c5, l3c1, l3c2, l3c3, l3c4, l3c5, l2c1, l2c5) do
    acc = ((l2c2 - ?0) * 100) + ((l2c3 - ?0) * 10) + (l2c4 - ?0) + acc
    find_parts([&lt;&lt;l1c5,  l1_rest::binary&gt;&gt;, &lt;&lt;l2c5, l2_rest::binary&gt;&gt;, &lt;&lt;l3c5, l3_rest::binary&gt;&gt; | rest], acc, tail)
  end

  # Three digit number but no symbol, skip over the number
  def find_parts([&lt;&lt;_, _, _, _, l1c5, l1_rest::binary&gt;&gt;, &lt;&lt;_, l2c2, l2c3, l2c4, l2c5, l2_rest::binary&gt;&gt;, &lt;&lt;_, _, _, _, l3c5, l3_rest::binary&gt;&gt; | rest], acc, tail)
      when are_digits(l2c2, l2c3, l2c4) do
   find_parts([&lt;&lt;l1c5,  l1_rest::binary&gt;&gt;, &lt;&lt;l2c5, l2_rest::binary&gt;&gt;, &lt;&lt;l3c5, l3_rest::binary&gt;&gt; | rest], acc, tail)
  end

  # Two digit number surrounded by a symbol
  def find_parts([&lt;&lt;l1c1, l1c2, l1c3, l1c4, l1_rest::binary&gt;&gt;, &lt;&lt;l2c1, l2c2, l2c3, l2c4, l2_rest::binary&gt;&gt;, &lt;&lt;l3c1, l3c2, l3c3, l3c4, l3_rest::binary&gt;&gt; | rest], acc, tail)
    when are_digits(l2c2, l2c3) and
      is_surrounded_by_symbol(l1c1, l1c2, l1c3, l1c4, l3c1, l3c2, l3c3, l3c4, l2c1, l2c4) do
    acc = ((l2c2 - ?0) * 10) + (l2c3 - ?0) + acc
    find_parts([&lt;&lt;l1c4,  l1_rest::binary&gt;&gt;, &lt;&lt;l2c4, l2_rest::binary&gt;&gt;, &lt;&lt;l3c4, l3_rest::binary&gt;&gt; | rest], acc, tail)
  end

  # Two digit number but no symbol, skip over the number
  def find_parts([&lt;&lt;_, _, _, l1c4, l1_rest::binary&gt;&gt;, &lt;&lt;_, l2c2, l2c3, l2c4, l2_rest::binary&gt;&gt;, &lt;&lt;_, _, _, l3c4, l3_rest::binary&gt;&gt; | rest], acc, tail)
      when are_digits(l2c2, l2c3) do
   find_parts([&lt;&lt;l1c4,  l1_rest::binary&gt;&gt;, &lt;&lt;l2c4, l2_rest::binary&gt;&gt;, &lt;&lt;l3c4, l3_rest::binary&gt;&gt; | rest], acc, tail)
  end

  # One digit number surrounded with a symbol
  def find_parts([&lt;&lt;l1c1, l1c2, l1c3, l1_rest::binary&gt;&gt;, &lt;&lt;l2c1, l2c2, l2c3, l2_rest::binary&gt;&gt;, &lt;&lt;l3c1, l3c2, l3c3, l3_rest::binary&gt;&gt; | rest], acc, tail)
      when are_digits(l2c2) and
       is_surrounded_by_symbol(l1c1, l1c2, l1c3, l3c1, l3c2, l3c3, l2c1, l2c3) do
   acc = (l2c2 - ?0) + acc
   find_parts([&lt;&lt;l1c3,  l1_rest::binary&gt;&gt;, &lt;&lt;l2c3, l2_rest::binary&gt;&gt;, &lt;&lt;l3c3, l3_rest::binary&gt;&gt; | rest], acc, tail)
  end

  # Move the window across one character
  def find_parts([&lt;&lt;_, rest_1::binary&gt;&gt;, &lt;&lt;_, rest_2::binary&gt;&gt;, &lt;&lt;_, rest_3::binary&gt;&gt; | rest], acc, tail) do
    find_parts([rest_1, rest_2, rest_3 | rest], acc, tail)
  end

  # Move the window down one line
  def find_parts(["", "", "" | _rest], acc, [line_1, line_2, line_3 | tail]) do
    find_parts([line_1, line_2, line_3], acc, [line_2, line_3 | tail])
  end

  # End of input, return the accumulator
  def find_parts([_, _, _], acc, _tail) do
    acc
  end
</code></pre>
</details> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="309903" 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-3/60113/19">Post #18</a>
	                </div>
	            </div>
              <div id="likers-container-309903" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="309903"
                     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="309910" data-post-id="309910">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I did the same, just with <code>make_ref()</code> instead of number.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="309910" 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-3/60113/20">Post #19</a>
	                </div>
	            </div>
              <div id="likers-container-309910" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="309910"
                     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="309924" data-post-id="309924">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>oohhhh, completely missed!! nicely done with the <code>Integer.parse(str)</code>… never thought about splitting numbers vs rest this way</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="309924" 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-3/60113/21">Post #20</a>
	                </div>
	            </div>
              <div id="likers-container-309924" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="309924"
                     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 #20"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/60113/load_more?page=3">Load more posts (2 remaining)</a>
</div></template></turbo-stream>