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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’m well behind but I think I managed this. Grids in functional languages fill me with dread but I took the following approach for part 1 was first check the for a match like this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  @samx "SAMX"
  @xmas "XMAS"
  @new_line "\n"
  defp check_line(&lt;&lt;&gt;&gt;, hits), do: hits

  defp check_line(&lt;&lt;@samx, _::binary&gt;&gt; = line, hits) do
    &lt;&lt;_::binary-size(3), rest::binary&gt;&gt; = line
    check_line(rest, hits + 1)
  end

  defp check_line(&lt;&lt;@xmas, _::binary&gt;&gt; = line, hits) do
    &lt;&lt;_::binary-size(3), rest::binary&gt;&gt; = line
    check_line(rest, hits + 1)
  end

  defp check_line(&lt;&lt;_::binary-size(1), rest::binary&gt;&gt;, hits), do: check_line(rest, hits)
</code></pre>
<p>Then turn the binary into columns and each diagonal. The trick for the diagnonals is to iterate along the top row, then down the rightmost column for sout east diagonals. Then go from top right to back along the top row and down the leftmost column.</p>
<p>Anyway it came out a bit more verbose than I hoped can probably simplify it a bit.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def day4_1() do
    grid = "./day_4_input.txt" |&gt; File.read!()

    line_length = line_length(grid, 0)
    row_count = check_line(grid, 0)
    ne_count = north_east_diagonal(grid, line_length)
    se_count = south_east_diagonal(grid, line_length)
    column_count = column_count(grid, line_length)
    row_count + ne_count + se_count + column_count
  end

  @samx "SAMX"
  @xmas "XMAS"
  @new_line "\n"
  defp check_line(&lt;&lt;&gt;&gt;, hits), do: hits

  defp check_line(&lt;&lt;@samx, _::binary&gt;&gt; = line, hits) do
    &lt;&lt;_::binary-size(3), rest::binary&gt;&gt; = line
    check_line(rest, hits + 1)
  end

  defp check_line(&lt;&lt;@xmas, _::binary&gt;&gt; = line, hits) do
    &lt;&lt;_::binary-size(3), rest::binary&gt;&gt; = line
    check_line(rest, hits + 1)
  end

  defp check_line(&lt;&lt;_::binary-size(1), rest::binary&gt;&gt;, hits), do: check_line(rest, hits)

  # We include the new line in the count because it makes the rest of the stuff work better
  defp line_length(&lt;&lt;@new_line, _::binary&gt;&gt;, count), do: count + 1
  defp line_length(&lt;&lt;_::binary-size(1), rest::binary&gt;&gt;, count), do: line_length(rest, count + 1)

  def column_count(grid, line_length) do
    Enum.reduce(0..(line_length - 1), "", fn x, lines -&gt;
      columns({x, line_length - 2}, grid, line_length, lines)
    end)
    |&gt; check_line(0)
  end

  def columns({_, y}, _, _, acc) when y &lt; 0, do: &lt;&lt;acc::binary, @new_line&gt;&gt;

  def columns({x, y}, grid, line_length, acc) do
    char = :binary.part(grid, x + y * line_length, 1)
    columns({x, y - 1}, grid, line_length, &lt;&lt;acc::binary, char::binary&gt;&gt;)
  end

  def south_east_diagonal(grid, line_length) do
    se_diagonal_index({line_length - 2, 0}, line_length - 2, [])
    |&gt; Enum.reduce("", fn diagonal_indexes, acc -&gt;
      line =
        diagonal_indexes
        |&gt; Enum.reduce("", fn {x, y}, acc -&gt;
          char = :binary.part(grid, x + y * line_length, 1)
          &lt;&lt;acc::binary, char::binary&gt;&gt;
        end)

      &lt;&lt;acc::binary, line::binary, @new_line&gt;&gt;
    end)
    |&gt; check_line(0)
  end

  # We've gone past bottom left.
  def se_diagonal_index({0, y}, last_idx, acc) when y == last_idx, do: acc

  # This is the first case hit - the top right
  def se_diagonal_index({last_idx, 0}, last_idx, acc) do
    se_diagonal_index({last_idx - 1, 0}, last_idx, [[{last_idx, 0}] | acc])
  end

  # This is the switch up case, where we round the corner on the top left hand side going down
  def se_diagonal_index({x, _}, last_idx, acc) when x &lt; 0 do
    se_diagonal_index({0, 1}, last_idx, acc)
  end

  # this is going along the top row, we heading backwards on the x axis
  def se_diagonal_index({x, 0} = current_cell, last_idx, acc) do
    diagonal = [
      current_cell | Enum.map(1..(last_idx - x), fn y_coord -&gt; {x + 1 * y_coord, y_coord} end)
    ]

    se_diagonal_index({x - 1, 0}, last_idx, [diagonal | acc])
  end

  # this is going down the leftmost column.
  def se_diagonal_index({0, y} = current, last_idx, acc) do
    diagonal = [current | Enum.map(1..(last_idx - y), fn y_coord -&gt; {y_coord, y + y_coord} end)]
    se_diagonal_index({0, y + 1}, last_idx, [diagonal | acc])
  end

  def north_east_diagonal(grid, line_length) do
    # It's - 2, 1 because of the newline char at the end of each line 1 because of the 0 index
    # We start at X of 2 because first few rows can never match as they are too short.
    ne_diagonal_idx({0, 0}, line_length - 2, [])
    |&gt; Enum.reduce("", fn diagonal_indexes, acc -&gt;
      line =
        diagonal_indexes
        |&gt; Enum.reduce("", fn {x, y}, acc -&gt;
          char = :binary.part(grid, x + y * line_length, 1)
          &lt;&lt;acc::binary, char::binary&gt;&gt;
        end)

      &lt;&lt;acc::binary, line::binary, @new_line&gt;&gt;
    end)
    |&gt; check_line(0)
  end

  def ne_diagonal_idx({last_idx, y}, last_idx, acc) when y &gt;= last_idx, do: acc

  def ne_diagonal_idx({0, 0}, last_idx, acc) do
    ne_diagonal_idx({1, 0}, last_idx, [[{0, 0}] | acc])
  end

  def ne_diagonal_idx({x, 0}, last_idx, acc) when x &gt; last_idx do
    ne_diagonal_idx({x - 1, 1}, last_idx, acc)
  end

  def ne_diagonal_idx({x, 0} = current_cell, last_idx, acc) do
    diagonal = [current_cell | Enum.map(1..x, fn y_coord -&gt; {x - 1 * y_coord, y_coord} end)]
    ne_diagonal_idx({x + 1, 0}, last_idx, [diagonal | acc])
  end

  def ne_diagonal_idx({x, y} = current, last_idx, acc) do
    diagonal = [
      current | Enum.map(1..(last_idx - y), fn y_coord -&gt; {x - 1 * y_coord, y + y_coord} end)
    ]

    ne_diagonal_idx({x, y + 1}, last_idx, [diagonal | acc])
  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="348707" 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-4/67869/32">Post #31</a>
	                </div>
	            </div>
              <div id="likers-container-348707" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="348707"
                     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="348708" data-post-id="348708">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Oh nice, I managed to beat this. I compared vs your solution:</p>
<pre data-code-wrap="sh"><code class="lang-sh">Operating System: macOS
CPU Information: Apple M1 Max
Number of Available Cores: 10
Available memory: 64 GB
Elixir 1.17.1
Erlang 27.1
JIT enabled: true

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 10 s
memory time: 2 s
reduction time: 2 s
parallel: 1
inputs: none specified
Estimated total run time: 32 s

Benchmarking part 1 ...
Benchmarking sevenseascat ...
Calculating statistics...
Formatting results...

Name                   ips        average  deviation         median         99th %
part 1              310.86        3.22 ms     ±4.15%        3.20 ms        3.58 ms
sevenseascat        107.63        9.29 ms     ±4.02%        9.11 ms       10.24 ms

Comparison:
part 1              310.86
sevenseascat        107.63 - 2.89x slower +6.07 ms

Memory usage statistics:

Name            Memory usage
part 1               4.32 MB
sevenseascat        14.35 MB - 3.33x memory usage +10.04 MB

**All measurements for memory usage were the same**

Reduction count statistics:

Name                 average  deviation         median         99th %
part 1              415.50 K     ±0.01%       415.49 K       415.59 K
sevenseascat        826.31 K     ±0.00%       826.31 K       826.31 K

Comparison:
part 1              415.49 K
sevenseascat        826.31 K - 1.99x reduction count +410.81 K

</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="348708" 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-4/67869/33">Post #32</a>
	                </div>
	            </div>
              <div id="likers-container-348708" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="348708"
                     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="348733" data-post-id="348733">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sevenseacat" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sevenseacat/120/23153_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sevenseacat
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Ash Framework</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Awesome <img src="https://forum.elixirforum.com/images/emoji/apple/smiley.png?v=15" title=":smiley:" class="emoji" alt=":smiley:" 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="348733" 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-4/67869/34">Post #33</a>
	                </div>
	            </div>
              <div id="likers-container-348733" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="348733"
                     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 #33"></div>
  </section>
</div>
    <div class="postbit" id="348814" data-post-id="348814">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Also, for part 2 we kept with the “skip through the binary” approach. We stop as soon as we know we do not have an X and move on. Also realised you can stop two before the end of the row and column as otherwise the X will extend out of bounds.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def day4_2() do
    grid = "./day_4_input.txt" |&gt; File.read!()
    line_length = line_length(grid, 0)
    find_x(grid, {0, 0}, line_length, 0)
  end

  @m "M"
  @a "A"
  @s "S"

  def find_x(binary, {x, y}, line_length, count) do
    if mas_se?(binary, line_length) || sam_se?(binary, line_length) do
      &lt;&lt;_::binary-size(2), rest::binary&gt;&gt; = binary

      count =
        if mas_sw?(rest, line_length) || sam_sw?(rest, line_length) do
          count + 1
        else
          count
        end

      next(binary, {x, y}, line_length, count)
    else
      next(binary, {x, y}, line_length, count)
    end
  end

  # This bounds check essentially.
  def next(binary, {x, y}, line_length, count) do
    if x + 1 &gt; line_length - 4 do
      if y + 1 &gt; line_length - 4 do
        # We stop because we are at max Y depth
        count
      else
        # Skip to next row
        &lt;&lt;_::binary-size((line_length - x)), rest::binary&gt;&gt; = binary
        find_x(rest, {0, y + 1}, line_length, count)
      end
    else
      # Move right
      &lt;&lt;_::binary-size(1), rest::binary&gt;&gt; = binary
      find_x(rest, {x + 1, y}, line_length, count)
    end
  end

  def mas_se?(&lt;&lt;@m, rest::binary&gt;&gt;, line_length) do
    case southeast_once(rest, line_length) do
      &lt;&lt;@a, after_a::binary&gt;&gt; -&gt; match?(&lt;&lt;@s, _::binary&gt;&gt;, southeast_once(after_a, line_length))
      _ -&gt; false
    end
  end

  def mas_se?(_, _), do: false

  def sam_se?(&lt;&lt;@s, rest::binary&gt;&gt;, line_length) do
    case southeast_once(rest, line_length) do
      &lt;&lt;@a, after_a::binary&gt;&gt; -&gt; match?(&lt;&lt;@m, _::binary&gt;&gt;, southeast_once(after_a, line_length))
      _ -&gt; false
    end
  end

  def sam_se?(_, _), do: false

  def mas_sw?(&lt;&lt;@m, rest::binary&gt;&gt;, line_length) do
    case southwest_once(rest, line_length) do
      &lt;&lt;@a, after_a::binary&gt;&gt; -&gt; match?(&lt;&lt;@s, _::binary&gt;&gt;, southwest_once(after_a, line_length))
      _ -&gt; false
    end
  end

  def mas_sw?(_, _), do: false

  def sam_sw?(&lt;&lt;@s, rest::binary&gt;&gt;, line_length) do
    case southwest_once(rest, line_length) do
      &lt;&lt;@a, after_a::binary&gt;&gt; -&gt; match?(&lt;&lt;@m, _::binary&gt;&gt;, southwest_once(after_a, line_length))
      _ -&gt; false
    end
  end

  def sam_sw?(_, _), do: false

  def southwest_once(binary, line_length) do
    skip = line_length - 2
    &lt;&lt;_::binary-size(skip), rest::binary&gt;&gt; = binary
    rest
  end

  # May need bounds checks? so we don't wrap the line? Or handle higher up. But there is
  # a max X coord of line_length - 4, one for new line, one for last char and one for pen char and one to 0 index.
  def southeast_once(binary, line_length) do
    skip = line_length
    &lt;&lt;_::binary-size(skip), rest::binary&gt;&gt; = binary
    rest
  end
</code></pre>
<p>It’s fast.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="348814" 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-4/67869/35">Post #34</a>
	                </div>
	            </div>
              <div id="likers-container-348814" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="348814"
                     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 #34"></div>
  </section>
</div>
    <div class="postbit" id="349041" data-post-id="349041">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Not sure how Elixir-y my solution turned out to be, but it works at least.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Aoc2024.Day4 do
  @moduledoc false

  defp get_input(file) do
    File.read!(file)
    |&gt; String.split("\n")
    |&gt; Enum.filter(fn line_data -&gt; line_data != "" end)
  end

  defp value(grid, x, y) do
    Enum.fetch!(Enum.fetch!(grid, y), x)
  end

  defp diagonal(grid, x, y, x_incr, y_incr) do
    if x &lt; 0 or x &gt;= length(List.first(grid)) or y &lt; 0 or y &gt;= length(grid) do
      []
    else
      [value(grid, x, y) | diagonal(grid, x_incr.(x, 1), y_incr.(y, 1), x_incr, y_incr)]
    end
  end

  def part1(file) do
    search_word = "XMAS"
    lines = get_input(file)
    horizontal = lines
    grid = Enum.map(lines, &amp;String.split(&amp;1, "", trim: true))
    vertical = Enum.zip(grid) |&gt; Enum.map(fn row -&gt; Tuple.to_list(row) |&gt; Enum.join("") end)

    last_x = length(List.first(grid)) - 1
    last_y = length(grid) - 1

    downright =
      (for x &lt;- 0..last_x do
         diagonal(grid, x, 0, &amp;+/2, &amp;+/2)
       end ++
         for y &lt;- 1..last_y do
           diagonal(grid, 0, y, &amp;+/2, &amp;+/2)
         end)
      |&gt; Enum.map(&amp;Enum.join(&amp;1, ""))

    downleft =
      (for x &lt;- 0..last_x do
         diagonal(grid, x, 0, &amp;-/2, &amp;+/2)
       end ++
         for y &lt;- 1..last_y do
           diagonal(grid, last_x, y, &amp;-/2, &amp;+/2)
         end)
      |&gt; Enum.map(&amp;Enum.join(&amp;1, ""))

    forward = Regex.compile!(search_word)
    backward = Regex.compile!(String.reverse(search_word))

    (horizontal ++ vertical ++ downright ++ downleft)
    |&gt; Enum.map(fn s -&gt; (Regex.scan(forward, s) ++ Regex.scan(backward, s)) |&gt; Enum.count() end)
    |&gt; Enum.sum()
  end

  defp xmas?(grid, x, y) do
    top_left = value(grid, x, y)
    top_right = value(grid, x + 2, y)
    center = value(grid, x + 1, y + 1)
    bottom_left = value(grid, x, y + 2)
    bottom_right = value(grid, x + 2, y + 2)

    center == "A" and
      ((top_left == "M" and bottom_right == "S") or (top_left == "S" and bottom_right == "M")) and
      ((top_right == "M" and bottom_left == "S") or (top_right == "S" and bottom_left == "M"))
  end

  def part2(file) do
    lines = get_input(file)
    grid = Enum.map(lines, &amp;String.split(&amp;1, "", trim: true))
    last_x = length(List.first(grid)) - 1
    last_y = length(grid) - 1

    for x &lt;- 0..(last_x - 2), y &lt;- 0..(last_y - 2) do
      if xmas?(grid, x, y), do: 1, else: 0
    end
    |&gt; Enum.sum()
  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="349041" 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-4/67869/36">Post #35</a>
	                </div>
	            </div>
              <div id="likers-container-349041" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="349041"
                     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>