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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>This one is utterly unreadable after all the golfing.</p>
<p>LOC: 37</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Aoc2024.Day12 do
  import Enum
  import String, only: [split: 3]
  def part1(file), do: main(file, &amp;perimeter/1)
  def part2(file), do: main(file, &amp;num_sides/1)
  def area(region), do: length(region)
  def perimeter(region), do: count(segment_counts(region), fn {_, count} -&gt; count == 1 end)
  def segment_counts(region), do: frequencies(flat_map(region, &amp;s/1))
  def s(p), do: for(q &lt;- [p], r &lt;- g(p), do: {q, r}) ++ for(q &lt;- g(p), r &lt;- [inc(p)], do: {q, r})
  def inc({x, y}), do: {x + 1, y + 1}
  def g({x, y}), do: [{x + 1, y}, {x, y + 1}]
  def t1?({a, b}, {c, d}), do: (a == c and abs(d - b) == 1) or (b == d and abs(c - a) == 1)
  def t2?(meets), do: fn {a, b}, {c, d} -&gt; t3?(a, d, meets) or t3?(b, c, meets) end
  def t3?(p, q, meets), do: p == q and not (p in meets or q in meets)

  def main(file, side_fun) do
    rows = file |&gt; File.read!() |&gt; split("\n", trim: true) |&gt; map(&amp;split(&amp;1, "", trim: true))
    grid = for {row, i} &lt;- with_index(rows), {x, j} &lt;- with_index(row), into: %{}, do: {{i, j}, x}
    rs = for {_, r} &lt;- group_by(grid, &amp;elem(&amp;1, 1), &amp;elem(&amp;1, 0)), do: contiguous(r, &amp;t1?/2)
    sum_by(rs, fn lr -&gt; sum_by(lr, &amp;(area(&amp;1) * side_fun.(&amp;1))) end)
  end

  def contiguous([h | t], fun?) do
    reduce(t, [[h]], fn x, ys -&gt;
      {touches, disjoint} = split_with(ys, fn y -&gt; any?(y, &amp;fun?.(&amp;1, x)) end)
      [[x] ++ List.flatten(touches)] ++ disjoint
    end)
  end

  def num_sides(region) do
    s = segment_counts(region) |&gt; filter(fn {_, count} -&gt; count == 1 end) |&gt; map(&amp;elem(&amp;1, 0))
    %{true: v, false: h} = group_by(s, fn {{x1, _}, {x2, _}} -&gt; x1 == x2 end)
    p_counts = (v ++ h) |&gt; flat_map(fn {{a, b}, {c, d}} -&gt; [{a, b}, {c, d}] end) |&gt; frequencies()
    meets = p_counts |&gt; filter(fn {_, count} -&gt; count &gt; 2 end) |&gt; map(&amp;elem(&amp;1, 0))
    count(contiguous(v, t2?(meets))) + count(contiguous(h, t2?(meets)))
  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="349565" 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-2024-day-12/68054/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-349565" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="349565"
                     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="349567" data-post-id="349567">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’ve read about a simple concept for calculating corners in r/adventofcode. It checks for convex and concave corners for each direction.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">def count_corners(garden, pos) do
  plant = at(garden, pos)

  [
    {up(pos), left(pos), left(pos) |&gt; up()},
    {up(pos), right(pos), right(pos) |&gt; up()},
    {down(pos), left(pos), left(pos) |&gt; down()},
    {down(pos), right(pos), right(pos) |&gt; down()}
  ]
  |&gt; Enum.count(fn {pos1, pos2, diagonal} -&gt;
    val1 = at(garden, pos1)
    val2 = at(garden, pos2)
    diagonal_val = at(garden, diagonal)

    # Convex corner: both adjacents are different from group
    convex_corner = val1 != plant and val2 != plant

    # Concave corner: both adjacents match group AND diagonal is different
    concave_corner = val1 == plant and val2 == plant and diagonal_val != plant

    convex_corner or concave_corner
  end)
end
</code></pre>
<p>Here is my full solution:<br>
<a href="https://github.com/Flo0807/adventofcode/blob/main/2024/12.livemd" class="onebox" target="_blank" rel="noopener nofollow ugc">https://github.com/Flo0807/adventofcode/blob/main/2024/12.livemd</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="349567" 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-12/68054/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-349567" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="349567"
                     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="349570" data-post-id="349570">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>behold, i bring code that i am highly ashamed of:<br>
<a href="https://gitea.codingthemsoftly.com/caleb/advent_of_code/src/branch/main/elixir/livebook/2024/day12.livemd" class="onebox" target="_blank" rel="noopener nofollow ugc">https://gitea.codingthemsoftly.com/caleb/advent_of_code/src/branch/main/elixir/livebook/2024/day12.livemd</a></p>
<p>truly attrocious performance</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Name           ips        average  deviation         median         99th %
p2           44.02       22.72 ms     ±4.79%       22.62 ms       25.43 ms
p1            4.37      228.70 ms     ±3.14%      227.56 ms      242.19 ms
</code></pre>
<p>edit: omg i made the code uglier and faster</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Name           ips        average  deviation         median         99th %
p1           93.85       10.66 ms     ±7.19%       10.61 ms       12.65 ms
p2           45.60       21.93 ms     ±4.21%       21.87 ms       24.31 ms
</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="349570" 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-12/68054/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-349570" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="349570"
                     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="349578" data-post-id="349578">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Got part 1 first the naive cartesian way, but didn’t hang around long enough for the input to evaluate. Clearly incorrect for the problem space.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">#!/usr/bin/env elixir

defmodule Day12.Part1 do
  defp parse(str) do
    [row | _rows] =
      rows =
      str
      |&gt; String.split("\n", trim: true)
      |&gt; Enum.map(&amp;to_charlist/1)

    height = Enum.count(rows)
    length = Enum.count(row)

    graph = :digraph.new([:acyclic])

    for y &lt;- 0..(height - 1) do
      for x &lt;- 0..(length - 1) do
        value = rows |&gt; Enum.at(y) |&gt; Enum.at(x)
        :digraph.add_vertex(graph, {x, y}, value)
        [{x + 1, y}, {x - 1, y}, {x, y + 1}, {x, y - 1}]
        |&gt; Enum.filter(
          fn {n_x, n_y} = neighbor -&gt;
            on_board?(neighbor, height, length) and rows |&gt; Enum.at(n_y) |&gt; Enum.at(n_x) == value
          end
        )
        |&gt; Enum.each(fn neighbor -&gt; :digraph.add_edge(graph, {x, y}, neighbor) end)
      end
    end

    :digraph_utils.components(graph)
  end

  defp on_board?({x, y}, height, length) when x &lt; 0 or x &gt;= length or y &lt; 0 or y &gt;= height,
    do: false

  defp on_board?(_pair, _height, _length), do: true

  defp area(contiguous_region) do
    contiguous_region |&gt; Enum.count()
  end

  defp perimeter({x, y} = _point, %MapSet{} = contiguous_region) do
    [{x + 1, y}, {x - 1, y}, {x, y + 1}, {x, y - 1}]
    |&gt; Enum.map(fn neighbor -&gt;
      if MapSet.member?(contiguous_region, neighbor), do: 0, else: 1
    end)
    |&gt; Enum.sum()
  end

  defp perimeter(contiguous_region) do
    contiguous_region
    |&gt; Enum.map(&amp;perimeter(&amp;1, contiguous_region))
    |&gt; Enum.sum()
  end

  defp fence_cost([point|_points] = contiguous_region) when is_tuple(point) do
    area = area(contiguous_region)
    perimeter = perimeter(MapSet.new(contiguous_region))
    area * perimeter
  end

  defp fence_cost([region|_regions] = contiguous_regions) when is_list(region) do
    contiguous_regions
    |&gt; Enum.map(&amp;fence_cost(&amp;1))
    |&gt; Enum.sum()
  end

  def solve() do
    File.read!("lib/advent_of_code/year/2024/day/12/input.txt")
    |&gt; parse()
    |&gt; fence_cost()
    |&gt; IO.puts()
  end
end

Day12.Part1.solve()
</code></pre>
<p>Switched it up by trying out <code>:digraph</code>. Once I figured out that the perimeter could be calculated without the rest of the map, it was a piece of cake.</p>
<p>Still working on part 2.</p> 
	            </div>

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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Here’s my Day 12, basic flood fill whilst counting edges for Part 1, using an ETS table to track visited squares (as I’m learning ETS also).</p>
<p>Part 2, realised that’s number of sides == number of corners, so counting covex and concave corners, so just added that to the Part 1 solution, and after some head scratching (and graph paper) caught the cases and got the answer.</p>
<p>If I can get through Part 1 tomorrow I’ll be happy, as that’s further than I got last year!</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Solution for 2024 day 12
part_one: 1457298 in 68.1ms
part_two: 921636 in 67.28ms
</code></pre>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Aoc2024.Solutions.Y24.Day12 do
  alias AoC.Input

  def parse(input, _part) do
    Input.read!(input)
    |&gt; String.split("\n", trim: true)
  end

  def part_one(problem) do
    :ets.new(:store, [:named_table, :public, :ordered_set, :protected])
    build_matrix(problem)

    plots = :ets.tab2list(:store)

    result =
      Enum.reduce(plots, 0, fn {{x, y}, _req, _}, acc -&gt;
        case :ets.lookup(:store, {x, y}) do
          [] -&gt;
            acc

          [{_, req_type, _visited} = plot] -&gt;
            case build_gardens([plot], req_type) do
              {0, 0, 0} -&gt;
                acc

              {plot, fence, _} -&gt;
                acc + plot * fence
            end
        end
      end)

    :ets.delete(:store)
    result
  end

  def part_two(problem) do
    :ets.new(:store, [:named_table, :public, :ordered_set, :protected])
    build_matrix(problem)

    plots = :ets.tab2list(:store)

    result =
      Enum.reduce(plots, 0, fn {{x, y}, _req, _}, acc -&gt;
        case :ets.lookup(:store, {x, y}) do
          [] -&gt;
            acc

          [{_, req_type, _visited} = plot] -&gt;
            case build_gardens([plot], req_type) do
              {0, 0, 0} -&gt;
                acc

              {plot, _fence, corners} -&gt;
                acc + plot * corners
            end
        end
      end)

    :ets.delete(:store)
    result
  end

  def build_gardens([], _req_type), do: {0, 1, 0}

  def build_gardens([{{x, y}, type, visited}], req_type) do
    cond do
      type == req_type and visited == false -&gt;
        :ets.insert(:store, {{x, y}, req_type, true})

        corner = check_for_corners(x, y, type)

        {south_plot, south_fence, south_corners} =
          build_gardens(:ets.lookup(:store, {x, y + 1}), req_type)

        {north_plot, north_fence, north_corners} =
          build_gardens(:ets.lookup(:store, {x, y - 1}), req_type)

        {west_plot, west_fence, west_corners} =
          build_gardens(:ets.lookup(:store, {x - 1, y}), req_type)

        {east_plot, east_fence, east_corners} =
          build_gardens(:ets.lookup(:store, {x + 1, y}), req_type)

        {south_plot + north_plot + west_plot + east_plot + 1,
         south_fence + north_fence + west_fence + east_fence,
         south_corners + north_corners + west_corners + east_corners + corner}

      type == req_type and visited == true -&gt;
        {0, 0, 0}

      type != req_type -&gt;
        {0, 1, 0}
    end
  end

  def check_for_corners(x, y, type) do
    n = is_requested_type?(x, y - 1, type)
    ne = is_requested_type?(x + 1, y - 1, type)
    e = is_requested_type?(x + 1, y, type)
    se = is_requested_type?(x + 1, y + 1, type)
    s = is_requested_type?(x, y + 1, type)
    sw = is_requested_type?(x - 1, y + 1, type)
    w = is_requested_type?(x - 1, y, type)
    nw = is_requested_type?(x - 1, y - 1, type)

    check_for_corner(n, ne, e) + check_for_corner(e, se, s) + check_for_corner(s, sw, w) +
      check_for_corner(w, nw, n)
  end

  def check_for_corner(n, ne, e) do
    cond do
      n == false and e == false -&gt;
        1

      n == true and ne == false and e == true -&gt;
        1

      true -&gt;
        0
    end
  end

  def is_requested_type?(x, y, type) do
    case :ets.lookup(:store, {x, y}) do
      [{_, req_type, _}] -&gt;
        req_type == type

      [] -&gt;
        false
    end
  end

  def build_matrix(grid) do
    Enum.with_index(grid)
    |&gt; Enum.each(fn row -&gt;
      build_matrix_row(row)
    end)
  end

  def build_matrix_row({row, row_index}) do
    row
    |&gt; String.graphemes()
    |&gt; Enum.with_index()
    |&gt; Enum.each(fn {char, col_index} -&gt;
      :ets.insert(:store, {{col_index, row_index}, char, false})
    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="349584" 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-12/68054/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-349584" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="349584"
                     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="349600" data-post-id="349600">
  <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>I created a grid struct yesterday for day 10’s challenge and spent a decent amount of my time adding to it to solve this one. Definitely going to have to implement reduce for it if we keep getting more of these.</p>
<p>My solution today feels much more verbose than it probably could be, but it runs in under 100 ms.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">require Grid

defmodule Aoc2024.Day12 do
  @moduledoc false

  def part1(file) do
    get_input(file)
    |&gt; assign_plots()
    |&gt; fence_price1()
  end

  defp get_input(file) do
    File.read!(file)
    |&gt; Grid.new(fn v -&gt; v end)
  end

  defp assign_plots(grid) do
    for y &lt;- 0..grid.last_y, x &lt;- 0..grid.last_x do
      {x, y}
    end
    |&gt; Enum.reduce({grid, 0}, fn position, {acc, plot_id} -&gt;
      v = Grid.at(acc, position)

      if is_integer(v) do
        {acc, plot_id}
      else
        {explore_plot(acc, position, v, plot_id), plot_id + 1}
      end
    end)
    |&gt; Tuple.to_list()
    |&gt; List.first()
  end

  # Walk through the region from the starting point finding all points within the same plot.
  # Return an updated grid with all points within the plot updated to have the value of the given id.
  defp explore_plot(grid, position, initial, plot_id) do
    if is_integer(Grid.at(grid, position)) do
      grid
    else
      #   IO.inspect("{#{x},#{y}} #{initial} #{plot_id}")
      new = Grid.put(grid, position, plot_id)

      new
      |&gt; Grid.neighbors(position)
      |&gt; then(&amp;Grid.filter(new, &amp;1, fn v -&gt; v == initial end))
      |&gt; Enum.reduce(new, fn neighbor, acc -&gt;
        explore_plot(acc, neighbor, initial, plot_id)
      end)
    end
  end

  defp fence_price1(grid) do
    counts = {%{}, %{}}

    {areas, perimeters} =
      for y &lt;- 0..grid.last_y, x &lt;- 0..grid.last_x do
        {x, y}
      end
      |&gt; Enum.reduce(counts, fn position = {x, y}, {areas, perimeters} -&gt;
        plot_id = Grid.at(grid, position)
        areas = Map.update(areas, plot_id, 1, &amp;(&amp;1 + 1))

        [{1, 0}, {0, 1}, {0, -1}, {-1, 0}]
        |&gt; Enum.map(fn {dx, dy} -&gt; {x + dx, y + dy} end)
        |&gt; Enum.reduce({areas, perimeters}, fn neighbor, {areas, perimeters} -&gt;
          if plot_id == Grid.at(grid, neighbor) do
            {areas, perimeters}
          else
            {areas, Map.update(perimeters, plot_id, 1, &amp;(&amp;1 + 1))}
          end
        end)
      end)

    Map.keys(areas)
    |&gt; Enum.map(fn plot_id -&gt;
      Map.get(areas, plot_id) * Map.get(perimeters, plot_id)
    end)
    |&gt; Enum.sum()
  end

  def part2(file) do
    get_input(file)
    |&gt; assign_plots()
    |&gt; fence_price2()
  end

  defp fence_price2(grid) do
    areas = areas(grid)
    region_sides = region_sides(grid)

    Map.keys(areas)
    |&gt; Enum.map(fn plot_id -&gt;
      Map.get(areas, plot_id) * Map.get(region_sides, plot_id)
    end)
    |&gt; Enum.sum()
  end

  defp areas(grid) do
    areas = %{}

    for y &lt;- 0..grid.last_y, x &lt;- 0..grid.last_x do
      {x, y}
    end
    |&gt; Enum.reduce(areas, fn position, areas -&gt;
      plot_id = Grid.at(grid, position)
      # Map.update(areas, plot_id, MapSet.new([position]), &amp;(MapSet.put(&amp;1, position)))
      Map.update(areas, plot_id, 1, &amp;(&amp;1 + 1))
    end)
  end

  defp region_sides(grid) do
    sides = %{}

    for y &lt;- 0..grid.last_y, x &lt;- 0..grid.last_x do
      {x, y}
    end
    |&gt; Enum.reduce(sides, fn position, sides -&gt;
      plot_id = Grid.at(grid, position)
      fsc = fence_side_cost(grid, position)
      Map.update(sides, plot_id, fsc, &amp;(&amp;1 + fsc))
    end)
  end

  defp fence_side_cost(grid, position) do
    n = named_neighbors(position)
    left_n = named_neighbors(n.left)
    above_n = named_neighbors(n.above)

    above_below_cost(grid, position, n.above, n.left, left_n.above) +
      above_below_cost(grid, position, n.below, n.left, left_n.below) +
      left_right_cost(grid, position, n.left, n.above, above_n.left) +
      left_right_cost(grid, position, n.right, n.above, above_n.right)
  end

  defp above_below_cost(grid, pos, ab, left, left_ab) do
    if fence_between(grid, pos, ab) and
         (fence_between(grid, pos, left) or same_plot(grid, left, left_ab)) do
      1
    else
      0
    end
  end

  defp left_right_cost(grid, pos, lr, above, above_lr) do
    if fence_between(grid, pos, lr) and
         (fence_between(grid, pos, above) or same_plot(grid, above, above_lr)) do
      1
    else
      0
    end
  end

  defp same_plot(grid, position1, position2) do
    Grid.at(grid, position1) == Grid.at(grid, position2)
  end

  defp fence_between(grid, position1, position2) do
    Grid.at(grid, position1) != Grid.at(grid, position2)
  end

  defp named_neighbors({x, y}) do
    %{left: {x - 1, y}, right: {x + 1, y}, above: {x, y - 1}, below: {x, y + 1}}
  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="349600" 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-12/68054/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-349600" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="349600"
                     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="349603" data-post-id="349603">
  <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>You may be ashamed, but this helped me connect the dots for the value of creating doctests for the key helper functions. It seems like a nice middleground to keep my tests focused on the output but still make it easy to check my work step my step as I build up the code.</p> 
	            </div>

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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="lud" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lud/120/14382_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  lud
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<blockquote>
<p>I created a grid struct</p>
</blockquote>
<p>If I can give some advice, do not use a special data structure for your grid.</p>
<p>My Grid module is a bunch of helpers, but the data structure to represent the grid is just a map of <code>{x, y} =&gt; value</code>. It makes it much more direct to use in all the crazy things AoC makes us do, because it works with all the standard library functions like <code>Enum</code>, <code>Stream</code>, with some libraries, etc.</p>
<p>Resist the urge to make everything its own type. Like the <code>:queue</code> module type is just a tuple of two lists. That makes debugging and implement special things easier.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="349604" 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-12/68054/19">Post #18</a>
	                </div>
	            </div>
              <div id="likers-container-349604" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="349604"
                     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="349605" data-post-id="349605">
  <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>My grid struct is a wrapper around a simple map as you described. The only extra is storing the last x &amp; y values to make it easy to generate every possible position. Which as I type that I realized I should just be doing Map.keys() for that. Too much coding, not enough thinking (or sleep)!</p> 
	            </div>

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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="lud" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lud/120/14382_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  lud
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>The parse function for my grid returns <code>{grid, {x_min,x_max,y_min,y_max}}</code> because when parsing you traverse the whole thing.</p>
<p>If you want your grid to have that <code>{x_max,y_max}</code> coordinates and expect it to be correct then you will have to compute it whenever you <code>put</code> in the grid. There is a decent amount of puzzles that require to expand the grid, or to take only a sub part of it like today.</p>
<p>So I would avoid counting on those struct fields to always be up to date.</p>
<p>Also another tip that I do all the time, I name min and max to “a” and “o” (alpha/omega), like <code>xa</code>, <code>xo</code> instead of <code>x_min</code>, <code>x_max</code> … just because the “x” in “max” makes it such a pain to mass rename or do multi-cursor stuff when editing <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="349606" 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-12/68054/21">Post #20</a>
	                </div>
	            </div>
              <div id="likers-container-349606" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="349606"
                     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/68054/load_more?page=3">Load more posts (21 remaining)</a>
</div></template></turbo-stream>