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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I thought the same.. with me it turned out they were the same length, but when I printed them (as charlists) the backslashes got quoted - ie. printed as <code>\\</code> rather than <code>\</code> - and so visually they looked as if they’d have different length.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312252" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-16/60408/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-312252" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312252"
                     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="312255" data-post-id="312255">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="igorb" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/igorb/120/35715_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  igorb
                    <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>For this problem I made an exception to how I usually provide input and instead read the input from a file, because I suspected the backsplashes would mess up the input within IEx.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312255" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-16/60408/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-312255" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312255"
                     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="312444" data-post-id="312444">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>This was it. I usually write tests asserting on the example outputs by throwing the sample inputs in a multi-line string. I’m just having this day’s tests read from a text file instead, and now I’m seeing the correct row lengths. Cheers!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312444" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-16/60408/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-312444" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312444"
                     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="312830" data-post-id="312830">
  <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>Okay, sorted it out. I was making it more complex by considering the “next” space rather than the current space and I was not using the correct origin point for rays emanating from a reflection object. Changed the origin to {0,0} and</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">     ?/ -&gt;
        trace(
          new(
            Nx.add(ray.origin, Nx.multiply(ray.dir, ray.len)),
            update_dir(ray.dir, :reflect270)
          ),
          scene
        )

      ?\\ -&gt;
        trace(
          new(
            Nx.add(ray.origin, Nx.multiply(ray.dir, ray.len)),
            update_dir(ray.dir, :reflect90)
          ),
          scene
        )
</code></pre>
<p>needed to be</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">      ?/ -&gt;
        dir = update_dir(ray.dir, :reflect270)
        origin = Nx.add(ray.origin, Nx.multiply(ray.dir, ray.len)) |&gt; Nx.add(dir)

        trace(new(origin, dir), scene)

      ?\\ -&gt;
        dir = update_dir(ray.dir, :reflect90)
        origin = Nx.add(ray.origin, Nx.multiply(ray.dir, ray.len)) |&gt; Nx.add(dir)

        trace(new(origin, dir), scene)
</code></pre>
<p>It’s still a lot slower than I’d like, probably b/c of all the calls to <code>:ets.lookup_element</code> and <code>:ets.insert</code>.</p>
<p>============================================================================</p>
<p>I’m driving myself crazy on this one. I’m blind to the error I’m making at this point though. I’m getting the right output for the test input. The real input must have some edge cases that cause an inappropriate early return because I’m getting an answer that’s too low.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  @origin Nx.tensor([-1, 0])
  @initial_dir Nx.tensor([1, 0])
  @north Nx.tensor([0, -1])
  @south Nx.tensor([0, 1])
  @west Nx.tensor([-1, 0])
  @east Nx.tensor([1, 0])
  @horizontal [@east, @west]
  @vertical [@north, @south]

  defstruct origin: @origin, dir: @initial_dir, len: 0

  @type t() :: %__MODULE__{dir: dir(), origin: coord(), len: integer}

  @doc "Create new ray at origin {0,0} traveling east, initiate ray path at origin as initial node in path"
  @spec new :: t()
  def new() do
    maybe_start_cache()
    %__MODULE__{}
  end

  @doc "Create new ray at specified oring, with specified direction."
  @spec new(coord(), dir()) :: t()
  def new(origin, dir) do
    maybe_start_cache()
    %__MODULE__{origin: origin, dir: dir}
  end

  @spec maybe_start_cache() :: :ets.table() | atom
  defp maybe_start_cache() do
    if :ets.whereis(:ray_cache) == :undefined do
      :ets.new(:ray_cache, [:named_table])
      :ets.insert(:ray_cache, {:seen, MapSet.new()})
    else
      :cache_already_started
    end
  end

  @doc "At end of ray (OOB, or reflecting/refracting), therefore update the cache with all points travelled by the ray."
  @spec update_cache(t()) :: boolean
  def update_cache(%__MODULE__{dir: dir, origin: origin, len: len} = _ray) do
    seen = :ets.lookup_element(:ray_cache, :seen, 2)

    0..len
    |&gt; Enum.reduce(seen, fn i, acc -&gt;
      MapSet.put(acc, {Nx.add(origin, Nx.multiply(dir, i)), dir})
    end)
    |&gt; do_update_cache()
  end

  @spec do_update_cache(MapSet.t(path_el())) :: boolean
  defp do_update_cache(seen) do
    :ets.insert(:ray_cache, {:seen, seen})
  end

  @doc "Change direction the ray is traveling but not the location of end of ray."
  @spec update_dir(dir(), interaction()) :: t()
  def update_dir(dir, :reflect270),
    do: Nx.multiply(Nx.reverse(dir), -1)

  def update_dir(dir, :reflect90),
    do: Nx.reverse(dir)

  def update_dir(dir, _), do: dir

  @doc """
  Track the ray through the scene. A ray ends when it runs off the edge of the scene, refracts, or is reflected. In the 
  first case the cache is updated but no new ray created. In the second case the cache is updated and two rays are created,
  each orthogonal to the direction of the original ray and opposite and colinear to each other.  In the case of reflection,
  a single new ray is created at 90° or 270° to the original ray. Note that future work could potentiall make it possible
  to have objects with defined interactions that reflect or refract with customized angles but this is not currently available.
  """
  @spec trace(t(), scene()) :: status()
  def trace(ray, scene) do
    next = Nx.add(ray.origin, Nx.multiply(ray.dir, ray.len + 1))
    next_obj = Map.get(scene, List.to_tuple(Nx.to_list(next)))

    cond do
      next_obj == nil -&gt;
        update_cache(ray)
        {:complete, :oob}

      found?({next, ray.dir}) -&gt;
        ray = %__MODULE__{ray | len: ray.len + 1}
        update_cache(ray)
        {:complete, :loop}

      true -&gt;
        ray = %__MODULE__{ray | len: ray.len + 1}
        update_cache(ray)
        do_trace(ray, next_obj, scene)
    end
  end

  @spec found?(path_el()) :: boolean
  defp found?({coord, dir}) do
    seen = :ets.lookup_element(:ray_cache, :seen, 2)
    MapSet.member?(seen, {coord, dir})
  end

  @spec do_trace(t(), obj(), scene()) :: status()
  def do_trace(ray, obj, scene) do
    case obj do
      nil -&gt;
        {:complete, :oob}

      ?. -&gt;
        trace(ray, scene)

      ?- when ray.dir in @horizontal -&gt;
        trace(ray, scene)

      ?| when ray.dir in @vertical -&gt;
        trace(ray, scene)

      ?/ -&gt;
        trace(
          new(
            Nx.add(ray.origin, Nx.multiply(ray.dir, ray.len)),
            update_dir(ray.dir, :reflect270)
          ),
          scene
        )

      ?\\ -&gt;
        trace(
          new(
            Nx.add(ray.origin, Nx.multiply(ray.dir, ray.len)),
            update_dir(ray.dir, :reflect90)
          ),
          scene
        )

      ?- -&gt;
        refract_h(ray, scene)

      ?| -&gt;
        refract_v(ray, scene)
    end
  end

  @spec refract_h(t(), scene()) :: status()
  def refract_h(ray, scene) do
    origin = Nx.add(ray.origin, Nx.multiply(ray.dir, ray.len))
    trace(new(origin, @east), scene)
    trace(new(origin, @west), scene)    
  end

  @spec refract_v(t(), scene()) :: status()
  def refract_v(ray, scene) do
    origin = Nx.add(ray.origin, Nx.multiply(ray.dir, ray.len))
    trace(new(origin, @north), scene)
    trace(new(origin, @south), scene)
  end
</code></pre>
<p>I’m parsing the input into a map of <code>%{{col, row} =&gt; char}</code> and getting the count from</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">:ets.lookup_element(:ray_cache, :seen, 2) 
|&gt; Enum.map(&amp;elem(&amp;1, 0)) 
|&gt; Enum.map(&amp;Nx.to_list/1) 
|&gt; Enum.reject(fn n -&gt; n == {-1, 0} end)
|&gt; Enum.uniq() 
|&gt; Enum.count()
</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="312830" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-16/60408/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-312830" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312830"
                     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="313303" data-post-id="313303">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>My beginner’s solution, Day 16 part 1.</p>
<p>I decided this was a good opportunity to learn elixir processes.<br>
For each tile, a process is spawned that “knows” it’s type and <code>pid</code>s of it’s neighbors.<br>
When a process receives a message, it sends a message(s), depending on tile type and source location. First time it happens, it also sends a message to <code>:energized</code> which counts towards the result.<br>
It was tricky to get my head around it and get it right, but I’m pretty proud I succeeded.<br>
I can still see many ways to improve, but I will take those lessons with me for Advent of Code 2024.<br>
Cheers <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>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Day16 do

  def part1(input) do
    {border_pid,
     top_left_tile_pid} = initialize(input)
    Process.register spawn(fn -&gt; energized() end), :energized
    send(top_left_tile_pid, border_pid) # the beam enters
  end

  def energized(count \\ 0) do
    receive do
      _ -&gt; energized(count+1)
    after # 1000ms without a message
      1000 -&gt; IO.puts "No. energized tiles: #{count} "
    end
  end

  def init(tile), do: (receive do {l, u, r, d} -&gt; tile_cold(l, u, r, d, tile) end)
  def tile_cold(left, up, right, down, tile) do
    reflect(left, up, right, down, tile)
    send(:energized, self())
    tile_hot(left, up, right, down, tile)
  end
  def tile_hot(left, up, right, down, tile) do
    reflect(left, up, right, down, tile)
    tile_hot(left, up, right, down, tile)
  end
  def reflect(left, up, right, down, tile) do
    case tile do
      #dot
      :. -&gt; receive do 
              ^left  -&gt; right
              ^up    -&gt; down
              ^right -&gt; left
              ^down  -&gt; up
            end |&gt; send(self())
      #slash
      :/ -&gt; receive do
              ^left  -&gt; up    
              ^up    -&gt; left  
              ^right -&gt; down  
              ^down  -&gt; right 
            end |&gt; send(self())
      #backslash
      :"\\" -&gt; receive do
                 ^left  -&gt; down
                 ^up    -&gt; right
                 ^right -&gt; up
                 ^down  -&gt; left
               end |&gt; send(self())
      #pipe
      :| -&gt; receive do
              ^left  -&gt; [up, down]
              ^up    -&gt; [down]
              ^right -&gt; [up, down]
              ^down  -&gt; [up]
            end |&gt; Enum.map(&amp;send(&amp;1, self()))
      #dash
      :- -&gt; receive do
              ^left  -&gt; [right]
              ^up    -&gt; [left, right]
              ^right -&gt; [left]
              ^down  -&gt; [left, right]
            end |&gt; Enum.map(&amp;send(&amp;1, self()))
      end
  end
     
  def loop(), do: loop()

  def initialize(raw_layout) do
    border = spawn(fn -&gt; loop() end)

    border_row = raw_layout
    |&gt; String.split("\n")
    |&gt; List.first
    |&gt; String.length
    |&gt; then(&amp;List.duplicate(border, (&amp;1)+2))
    
    grid = raw_layout
    |&gt; String.split("\n")
    |&gt; Enum.map(fn raw_line -&gt; raw_line
         |&gt; String.graphemes
         |&gt; Enum.map(&amp;String.to_atom/1)
         |&gt; Enum.map(&amp;spawn(__MODULE__, :init, [&amp;1]))
         |&gt; then(&amp;([border] ++ &amp;1 ++ [border]))
       end)
    |&gt; then(&amp;([border_row] ++ &amp;1 ++ [border_row]))

    for {row, r} &lt;- Enum.with_index(grid) |&gt; Enum.slice(1..-2) do

      for {pid, c} &lt;- Enum.with_index(row) |&gt; Enum.slice(1..-2) do

        left  = grid |&gt; Enum.at(r)   |&gt; Enum.at(c-1)
        up    = grid |&gt; Enum.at(r-1) |&gt; Enum.at(c)
        right = grid |&gt; Enum.at(r)   |&gt; Enum.at(c+1)
        down  = grid |&gt; Enum.at(r+1) |&gt; Enum.at(c)

        send(pid, {left, up, right, down})

      end
    end

    {
     border,
     grid |&gt; Enum.at(1) |&gt; Enum.at(1)
    }
  end

end
</code></pre>
<p>PS. Check this out (not me):<br>
<a href="https://nitter.net/miladamilli/status/1736095441798795746#m" rel="noopener nofollow ugc">https://nitter.net/miladamilli/status/1736095441798795746#m</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="313303" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/advent-of-code-2023-day-16/60408/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-313303" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="313303"
                     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>