<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="270984" data-post-id="270984">
  <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">
								<pre data-code-wrap="elixir"><code class="lang-elixir">def parse(input) do
    input
    |&gt; String.split()
    |&gt; Enum.with_index()
    |&gt; Enum.map(&amp;parse_line/1)
    |&gt; List.flatten()
    |&gt; Enum.reduce(Map.new(), fn {value, key}, map -&gt; Map.put(map, key, value) end)
  end
</code></pre>
<p>Maybe purely stylistic but in a previous year’s AOC thread someone pointed out to me that <code>Map.new/2</code> makes <code>Enum.reduce(Map.new(), ...</code> unnecessary. Just pipe the enumerable into <code>Map.new(fn {v, k} -&gt; {k, v} end)</code>. Also I think <code>Enum.flat_map(&amp;parse_line/1)</code> does the same thing in one line as your current <code>Enum.map(&amp;parse_line/1) |&gt; List.flatten()</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="270984" 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-2022-day-8/52349/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-270984" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="270984"
                     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="271099" data-post-id="271099">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’m still one day behind but here goes my day 8. I struggled at puzzle 2 getting my ranges right. Yup, and I had the same issue with counting the taller tree.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule ExAOC2022.Day8 do
  @input "./lib/day8_input.txt"

  def puzzle1() do
    lines = file_by_line(@input)
    grid = Enum.map(lines, &amp;(String.split(&amp;1, "", trim: true)))

    rows_num = length(lines)
    cols_num = hd(grid) |&gt; length

    for i &lt;- 0..rows_num-1, j &lt;- 0..cols_num-1, reduce: 0 do
      acc -&gt;
        if visible?(grid, i, j, rows_num, cols_num), do: acc + 1, else: acc
    end
  end

  def puzzle2() do
    lines = file_by_line(@input)
    grid = Enum.map(lines, &amp;(String.split(&amp;1, "", trim: true)))

    rows_num = length(lines)
    cols_num = hd(grid) |&gt; length

    for i &lt;- 1..rows_num-2, j &lt;- 1..cols_num-2, reduce: 0 do
      acc -&gt;
        score = scenic_score(grid, i, j, rows_num-1, cols_num-1)
        if score &gt; acc, do: score, else: acc
    end
  end

  defp visible?(grid, x, y, max_x, max_y) do
    v = val(grid, x, y)

    cond do
      # edge
      x == 0 or y == 0 or x == (max_x - 1) or y == (max_y - 1) -&gt;
        true
      # up
      max_num_y(grid, x, 0, y-1) &lt; v -&gt;
        true
      # down
      max_num_y(grid, x, y+1, max_y-1) &lt; v -&gt;
        true
      # left
      max_num_x(grid, y, 0, x-1) &lt; v -&gt;
        true
      # right
      max_num_x(grid, y, x+1, max_x-1) &lt; v -&gt;
        true
      true -&gt;
        false
    end
  end

  defp scenic_score(grid, x, y, max_x, max_y) do
    v = val(grid, x, y)
    up_trees = Enum.map(y-1..0//-1, &amp;val(grid, x, &amp;1)) |&gt; dist(v)
    left_trees = Enum.map(x-1..0//-1, &amp;val(grid, &amp;1, y)) |&gt; dist(v)
    down_trees = Enum.map(y+1..max_y, &amp;val(grid, x, &amp;1)) |&gt; dist(v)
    right_trees = Enum.map(x+1..max_x, &amp;val(grid, &amp;1, y)) |&gt; dist(v)

    up_trees * down_trees * left_trees * right_trees
  end

  defp dist(trees, our_tree) do
    Enum.reduce_while(trees, 0, fn tree, score -&gt;
      if tree &gt;= our_tree, do: {:halt, score + 1}, else: {:cont, score + 1}
    end)
  end

  defp max_num_y(grid, x, from, to), do:
    Enum.map(from..to, &amp;val(grid, x, &amp;1)) |&gt; Enum.max()

  defp max_num_x(grid, y, from, to), do:
    Enum.map(from..to, &amp;val(grid, &amp;1, y)) |&gt; Enum.max()

  defp int(s), do: String.to_integer(s)

  defp val(grid, x, y) do
    get_in(grid, [Access.at(y), Access.at(x)]) |&gt; int
  end

  defp file_by_line(file) do
    file
    |&gt; File.read!()
    |&gt; String.split(~r/\R/, trim: true)
  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="271099" 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-2022-day-8/52349/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-271099" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="271099"
                     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="288740" data-post-id="288740">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Way late with this, but I took the last Advent of Code as a means to learn Elixir a bit and this is what I came up with for the day 8 challenge.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Aoc2022.Day8 do
  @moduledoc """
  Documentation for `Day 8`.
  
  --- Day 8: Treetop Tree House ---
  https://adventofcode.com/2022/day/8
  
  """

  defmodule Tree do
    defstruct height: nil, visible: false, score: 1
  end

  def process_input do
    rows =
      File.read!("./input/day8.txt")
      |&gt; String.split("\r\n")

    row_count = Enum.count(rows) - 1
    cols = rows |&gt; Enum.at(0) |&gt; String.graphemes()
    col_count = Enum.count(cols) - 1

    trees =
      rows
      |&gt; Enum.with_index()
      |&gt; Enum.map(fn {x, i} -&gt;
        t =
          x
          |&gt; String.graphemes()
          |&gt; Enum.with_index()
          |&gt; Enum.reduce(%{}, fn {y, j}, acc -&gt;
            Map.put(acc, {i, j}, %Tree{height: String.to_integer(y), visible: false})
          end)

        t
      end)
      |&gt; Enum.reduce(%{}, fn x, acc -&gt;
        Map.merge(acc, x)
      end)

    trees_with_visibility =
      0..row_count
      |&gt; Enum.map(fn i -&gt;
        0..col_count
        |&gt; Enum.map(fn j -&gt;
          case {i, j} do
            {0, _} -&gt;
              tree = Map.get(trees, {i, j})
              %{{i, j} =&gt; %Tree{tree | visible: true}}

            {_, 0} -&gt;
              tree = Map.get(trees, {i, j})
              %{{i, j} =&gt; %Tree{tree | visible: true}}

            {r, _} when r == row_count -&gt;
              tree = Map.get(trees, {i, j})
              %{{i, j} =&gt; %Tree{tree | visible: true}}

            {_, c} when c === col_count -&gt;
              tree = Map.get(trees, {i, j})
              %{{i, j} =&gt; %Tree{tree | visible: true}}

            {r, c} when r == row_count and c == col_count -&gt;
              tree = Map.get(trees, {i, j})
              %{{i, j} =&gt; %Tree{tree | visible: true}}

            {row, column} -&gt;
              %{height: current, visible: _v} = Map.get(trees, {i, j})

              trees_left = traverse_x(trees, column - 1, 0, row)

              visibility_score_left =
                trees_left
                |&gt; visibility_score(current)

              visible_left? =
                trees_left
                |&gt; Enum.filter(fn x -&gt; current &lt;= x end)
                |&gt; Enum.empty?()

              trees_right = traverse_x(trees, column + 1, col_count, row)

              visibility_score_right =
                trees_right
                |&gt; visibility_score(current)

              visible_right? =
                trees_right
                |&gt; Enum.filter(fn x -&gt; current &lt;= x end)
                |&gt; Enum.empty?()

              trees_up = traverse_y(trees, row - 1, 0, column)

              visibility_score_up =
                trees_up
                |&gt; visibility_score(current)

              visible_up? =
                trees_up
                |&gt; Enum.filter(fn x -&gt; current &lt;= x end)
                |&gt; Enum.empty?()

              trees_down = traverse_y(trees, row + 1, row_count, column)

              visibility_score_down =
                trees_down
                |&gt; visibility_score(current)

              visible_down? =
                trees_down
                |&gt; Enum.filter(fn x -&gt; current &lt;= x end)
                |&gt; Enum.empty?()

              %{
                {i, j} =&gt; %Tree{
                  height: current,
                  visible: visible_up? || visible_down? || visible_left? || visible_right?,
                  score:
                    visibility_score_down * visibility_score_left * visibility_score_right *
                      visibility_score_up
                }
              }
          end
        end)
      end)
      |&gt; List.flatten()
      |&gt; Enum.reduce(%{}, fn w, acc -&gt;
        Map.merge(w, acc)
      end)

    visible_count =
      trees_with_visibility
      |&gt; Enum.filter(fn {_, %{height: _, visible: v}} -&gt; v end)
      |&gt; Enum.count()

    highest_score =
      trees_with_visibility
      |&gt; Enum.map(fn {_, %{score: s}} -&gt; s end)
      |&gt; Enum.max()

    {visible_count, highest_score}
  end

  defp traverse_x(trees, from, to, axis) do
    from..to
    |&gt; Enum.map(fn x -&gt;
      %{height: u, visible: _v} = Map.get(trees, {axis, x})
      u
    end)
  end

  defp traverse_y(trees, from, to, axis) do
    from..to
    |&gt; Enum.map(fn x -&gt;
      %{height: u, visible: _v} = Map.get(trees, {x, axis})
      u
    end)
  end

  defp visibility_score(trees, current) do
    score =
      trees
      |&gt; Enum.reduce_while(0, fn x, acc -&gt;
        if x &gt;= current, do: {:halt, acc + 1}, else: {:cont, acc + 1}
      end)

    score
  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="288740" 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-2022-day-8/52349/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-288740" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="288740"
                     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="288813" data-post-id="288813">
  <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>A tiny bit of code review on the above - nothing major, mostly “here’s a shorter way to write the same ideas” tips.</p>
<ul>
<li>
<p>many <code>Enum</code> functions have a variant that lets you transform the input before doing their thing. For instance, <code>Enum.count/2</code> or <code>Enum.max_by/4</code>. There’s a minor performance benefit of using them since the intermediate list doesn’t need to be constructed, but IMO the readability gain is better.</p>
</li>
<li>
<p><code>Enum.map</code> + <code>List.flatten</code>  == <code>Enum.flat_map</code>, only again the intermediate list doesn’t need to be constructed.</p>
</li>
<li>
<p>Most code that uses <code>Enum.reduce</code> with an initial value of <code>%{}</code> will be clearer with <code>Map.new</code>. I say “most” because sometimes there’s code in the block passed to <code>reduce</code> that returns <code>acc</code> unchanged, which you can’t do with <code>Map.new</code></p>
</li>
<li>
<p>most of the time when you want one-line-at-a-time, <code>File.stream!</code> will save you some typing. By default, it already splits lines. There is also a theoretical memory-usage advantage since using <code>Stream</code> means you don’t need every line in memory at once, but it’s unlikely to be important.</p>
</li>
<li>
<p>functions are basically free: make more of them. In my experience, if you’d use a phrase to name a piece of code when discussing it with a colleague, it should probably be a separate function. For instance, here’s the “read the file in” part from my day 8 solution:</p>
</li>
</ul>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def read(filename) do
    File.stream!(filename)
    |&gt; Stream.map(&amp;String.trim/1)
    |&gt; Stream.with_index()
    |&gt; Stream.flat_map(&amp;parse_line/1)
    |&gt; Map.new()
  end

  defp parse_line({line, row_index}) do
    line
    |&gt; String.codepoints()
    |&gt; Enum.map(&amp;String.to_integer/1)
    |&gt; Enum.with_index()
    |&gt; Enum.map(fn {h, col_index} -&gt; {{row_index, col_index}, h} end)
  end
</code></pre>
<p>If you wanted <code>%Tree{}</code> structs like in your version, you’d change that very last statement of <code>parse_line</code> to build one out of <code>row_index</code> / <code>col_index</code> / <code>h</code> values.</p>
<p>Another guideline I find useful: repeat yourself, find the common parts, and then make THAT a function. For instance, you might notice this pattern (placeholders in <code>SHOUTING_CASE</code>):</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">trees_DIR = GET_TREES

visibility_score_DIR =
  trees_DIR
  |&gt; visibility_score(current)

visible_DIR? =
  trees_DIR
  |&gt; Enum.filter(fn x -&gt; current &lt;= x end)
  |&gt; Enum.empty?()
</code></pre>
<p>This becomes a function:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defp visibility_of(trees, current) do
  score = visibility_score(trees, current)

  flag =
    trees
    |&gt; Enum.filter(fn x -&gt; current &lt;= x end)
    |&gt; Enum.empty? # NOTE: consider using any? instead of filter + empty?

  {score, flag}
end
</code></pre>
<p>then the big branch of the case shortens to:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">            {row, column} -&gt;
              %{height: current, visible: _v} = Map.get(trees, {i, j})

              {visibility_score_left, visible_left?} =
                trees
                |&gt; traverse_x(column - 1, 0, row)
                |&gt; visibility_of(current)

              {visibility_score_right, visible_right?} =
                trees
                |&gt; traverse_x(column + 1, col_count, row)
                |&gt; visibility_of(current)

              {visibility_score_up, visible_up?} =
                trees
                |&gt; traverse_y(row - 1, 0, column)
                |&gt; visibility_of(current)

              {visibility_score_down, visible_down?} =
                trees
                |&gt; traverse_y(row + 1, row_count, column)
                |&gt; visibility_of(current)

              %{
                {i, j} =&gt; %Tree{
                  height: current,
                  visible: visible_up? || visible_down? || visible_left? || visible_right?,
                  score:
                    visibility_score_down * visibility_score_left * visibility_score_right *
                      visibility_score_up
                }
              }
</code></pre>
<p>Writing things this way makes it clearer that <em>only</em> the trees change between the four copies of 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="288813" 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-2022-day-8/52349/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-288813" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="288813"
                     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="288837" data-post-id="288837">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Hi Matt!</p>
<p>Thanks for taking the time to analyze the code, these are very valuable suggestions which I’ll try to use in the future.</p>
<p>Elixir is indeed a special language, there is (almost) always a better and more elegant solution to a particular problem. <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" 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="288837" 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-2022-day-8/52349/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-288837" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="288837"
                     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>