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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’m a few days late.</p>
<p>Day 10 was not too hard, and surprisingly, I had instant part2 resolution, after struggling a bit on part1’s recursion</p>
<p><strong>Part 1</strong></p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Advent.Y2024.Day10.Part1 do
  import Enum

  def run(puzzle) do
    map = parse(puzzle)
    map |&gt; find_zeros() |&gt; map(&amp;hike(map, &amp;1)) |&gt; map(&amp;elem(&amp;1, 0)) |&gt; sum()
  end

  def parse(puzzle) do
    for {row, y} &lt;- puzzle |&gt; String.split("\n") |&gt; with_index(),
        {height, x} &lt;- row |&gt; String.graphemes() |&gt; with_index(),
        into: %{},
        do: {{x, y}, String.to_integer(height)}
  end

  def find_zeros(map), do: for({{x, y}, h} &lt;- map, h == 0, do: {x, y})

  defp hike(map, pos, height \\ 0, visited \\ MapSet.new())
  defp hike(_map, pos, 9, visited), do: {1, MapSet.put(visited, pos)}

  defp hike(map, pos, height, visited) do
    visited = MapSet.put(visited, pos)

    case neighbours(map, pos, height, visited) do
      [] -&gt;
        {0, visited}

      neighbours -&gt;
        for {n, h} &lt;- neighbours, reduce: {0, visited} do
          {total, visited} -&gt;
            {score, visited} = hike(map, n, h, visited)
            {total + score, visited}
        end
    end
  end

  defp neighbours(map, {x, y}, height, visited) do
    for {dx, dy} &lt;- [{-1, 0}, {1, 0}, {0, -1}, {0, 1}],
        {nx, ny} = {x + dx, y + dy},
        not MapSet.member?(visited, {nx, ny}),
        new_height = Map.get(map, {nx, ny}, -1),
        new_height == height + 1,
        do: {{nx, ny}, new_height}
  end
end
</code></pre>
<p><strong>Part 2</strong></p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Advent.Y2024.Day10.Part2 do
  alias Advent.Y2024.Day10.Part1

  def run(puzzle) do
    map = Part1.parse(puzzle)
    map |&gt; Part1.find_zeros() |&gt; Enum.map(&amp;hike(map, &amp;1, 0)) |&gt; Enum.sum()
  end

  defp hike(_map, _pos, 9), do: 1

  defp hike(map, pos, height) do
    case neighbours(map, pos, height) do
      [] -&gt; 0
      ns -&gt; ns |&gt; Enum.map(fn {pos, h} -&gt; hike(map, pos, h) end) |&gt; Enum.sum()
    end
  end

  defp neighbours(map, {x, y}, height) do
    for {dx, dy} &lt;- [{-1, 0}, {1, 0}, {0, -1}, {0, 1}],
        {nx, ny} = {x + dx, y + dy},
        new_height = Map.get(map, {nx, ny}, -1),
        new_height == height + 1,
        do: {{nx, ny}, new_height}
  end
end
</code></pre>
<p>Part 2 is basically a simplified version of part 1, in which I don’t track already visited nodes.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="349589" 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-10/67999/22">Post #21</a>
	                </div>
	            </div>
              <div id="likers-container-349589" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="349589"
                     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 #21"></div>
  </section>
</div>
    <div class="postbit" id="350060" data-post-id="350060">
  <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>I didn’t see a <code>:digraph</code> solution in here yet, so this is mine:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Trails do
  def read(filename) do
    File.stream!(filename)
    |&gt; Stream.map(&amp;String.trim/1)
    |&gt; Stream.with_index()
    |&gt; Stream.flat_map(fn {row, r_idx} -&gt;
      row
      |&gt; String.codepoints()
      |&gt; Enum.with_index()
      |&gt; Enum.flat_map(fn
        {".", _} -&gt; []
        {c, c_idx} -&gt; [{{r_idx, c_idx}, String.to_integer(c)}]
      end)
    end)
    |&gt; Map.new()
  end

  def trailheads_and_summits(map) do
    Enum.reduce(map, {[], []}, fn
      {pos, 0}, {th_acc, sum_acc} -&gt; {[pos | th_acc], sum_acc}
      {pos, 9}, {th_acc, sum_acc} -&gt; {th_acc, [pos | sum_acc]}
      _, acc -&gt; acc
    end)
  end

  def to_graph(map) do
    graph = :digraph.new()
    points = Map.keys(map)

    Enum.each(points, &amp;:digraph.add_vertex(graph, &amp;1))

    Enum.each(points, fn {row, col} = pos -&gt;
      maybe_add_edge(graph, map, pos, {row+1, col})
      maybe_add_edge(graph, map, pos, {row-1, col})
      maybe_add_edge(graph, map, pos, {row, col+1})
      maybe_add_edge(graph, map, pos, {row, col-1})
    end)

    graph
  end

  defp maybe_add_edge(graph, map, pos1, pos2) do
    case {Map.get(map, pos1), Map.get(map, pos2)} do
      {a, b} when a+1 == b -&gt;
        :digraph.add_edge(graph, pos1, pos2)

      _ -&gt;
        nil
    end
  end

  def score(trailhead, summits, graph) do
    summits
    |&gt; Enum.filter(fn summit -&gt;
      :digraph.get_path(graph, trailhead, summit)
    end)
    |&gt; length()
  end

  def count_paths(_, t, s) when t == s, do: 1

  def count_paths(graph, trailhead, summit) do
    graph
    |&gt; :digraph.out_neighbours(trailhead)
    |&gt; Enum.map(&amp;count_paths(graph, &amp;1, summit))
    |&gt; Enum.sum()
  end
end

map = Trails.read("input.txt")

{trailheads, summits} = Trails.trailheads_and_summits(map)

graph = Trails.to_graph(map)

trailheads
|&gt; Enum.map(&amp;Trails.score(&amp;1, summits, graph))
|&gt; Enum.sum()
|&gt; IO.inspect(label: "part 1")

trailheads
|&gt; Stream.flat_map(fn t -&gt; Stream.map(summits, &amp;{t, &amp;1}) end)
|&gt; Stream.map(fn {t, s} -&gt; Trails.count_paths(graph, t, s) end)
|&gt; Enum.sum()
|&gt; IO.inspect(label: "part 2")
</code></pre>
<p>Since there’s a strict “only up by 1” rule for moving on the grid, I used a single scan across the whole grid to calculate an equivalent graph of “can move from A to neighbor B”. With that graph, it’s straightforward to find paths from a given point.</p>
<p><code>count_paths</code> also has two minor optimizations:</p>
<ul>
<li>since the caller only ever passes in summits, <code>trailhead</code> == <code>summit</code> is sufficient to check for “is the trail over”</li>
<li>since the graph is guaranteed to have no cycles, there’s no need for the “visiting” tracking that standard DFS would use</li>
</ul> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="350060" 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-10/67999/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-350060" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350060"
                     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 #22"></div>
  </section>
</div>
    <div class="postbit" id="350088" data-post-id="350088">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Part 2 solved first crowd++</p>
<p>Simple recursion with flat_map based return in part we take <code>&amp;Enum.uniq/2</code> and then <code>&amp;length/1</code> whereas in case of part 2 its just <code>&amp;length/1</code> on each individual trail result and then summation.</p>
<p><a href="https://github.com/king-11/AdventOfCode/blob/main/lib/advent_of_code/day_10.ex" class="onebox" target="_blank" rel="noopener nofollow ugc">https://github.com/king-11/AdventOfCode/blob/main/lib/advent_of_code/day_10.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="350088" 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-10/67999/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-350088" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350088"
                     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 #23"></div>
  </section>
</div>
    <div class="postbit" id="351459" data-post-id="351459">
  <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 had the same ideas but used comprehensions to add the edges and get the valid paths. First time this year I’ve used <code>:digraph</code> and didn’t have to refactor it away when I realized it wasn’t the right setup.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Day10 do
  @test """
  89010123
  78121874
  87430965
  96549874
  45678903
  32019012
  01329801
  10456732
  """
  @real File.read!(__DIR__ &lt;&gt; "/input.txt")

  @neighbors [{0, 1}, {0, -1}, {1, 0}, {-1, 0}]

  defp input(:test), do: @test
  defp input(:real), do: @real
  defp input(_), do: raise("Please use :test or :real as the mode to run.")

  defp parse(input) do
    input
    |&gt; String.split("\n", trim: true)
    |&gt; Enum.with_index()
    |&gt; Enum.reduce({:digraph.new(), %{}}, fn {line, i}, {map, indexed} -&gt;
      line
      |&gt; String.graphemes()
      |&gt; Enum.map(&amp;String.to_integer/1)
      |&gt; Enum.with_index()
      |&gt; Enum.reduce({map, indexed}, fn {n, j}, {mp, ndxd} -&gt;
        :digraph.add_vertex(mp, {i, j}, n)
        {mp, Map.update(ndxd, n, [{i, j}], fn curr -&gt; [{i, j} | curr] end)}
      end)
    end)
  end

  defp add_edges(graph) do
    for {i, j} &lt;- :digraph.vertices(graph),
        {k, l} &lt;- :digraph.vertices(graph) -- [{i, j}],
        {di, dj} &lt;- @neighbors,
        {i + di, j + dj} == {k, l} do
      {{i, j}, n} = :digraph.vertex(graph, {i, j})
      {{k, l}, m} = :digraph.vertex(graph, {k, l})

      case n - m do
        1 -&gt; :digraph.add_edge(graph, {k, l}, {i, j})
        -1 -&gt; :digraph.add_edge(graph, {i, j}, {k, l})
        _ -&gt; false
      end
    end

    graph
  end

  def run(mode) do
    {map, indexed} =
      mode
      |&gt; input()
      |&gt; parse()

    add_edges(map)

    part_1({map, indexed}) |&gt; IO.inspect(label: :part_1)
    part_2({map, indexed}) |&gt; IO.inspect(label: :part_2)
  end

  defp part_1({map, indexed}) do
    trailheads = indexed[0]
    targets = indexed[9]

    good_trails =
      for th &lt;- trailheads, te &lt;- targets, :digraph.get_path(map, th, te), reduce: %{} do
        acc -&gt; Map.update(acc, th, [te], fn curr -&gt; [te | curr] end)
      end

    score(good_trails)
  end

  defp score(trails) do
    trails
    |&gt; Enum.map(fn {_, nines} -&gt; Enum.count(nines) end)
    |&gt; Enum.sum()
  end

  defp part_2({map, indexed}) do
    for hd &lt;- indexed[0],
        one &lt;- indexed[1],
        :digraph.get_path(map, hd, one),
        two &lt;- indexed[2],
        :digraph.get_path(map, one, two),
        three &lt;- indexed[3],
        :digraph.get_path(map, two, three),
        four &lt;- indexed[4],
        :digraph.get_path(map, three, four),
        five &lt;- indexed[5],
        :digraph.get_path(map, four, five),
        six &lt;- indexed[6],
        :digraph.get_path(map, five, six),
        seven &lt;- indexed[7],
        :digraph.get_path(map, six, seven),
        eight &lt;- indexed[8],
        :digraph.get_path(map, seven, eight),
        nine &lt;- indexed[9],
        :digraph.get_path(map, eight, nine), reduce: 0 do
      acc -&gt; acc + 1
    end
  end
end

Day10.run(:real)
</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="351459" 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-10/67999/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-351459" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="351459"
                     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>