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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I also used Regex for part1, even though I knew it wouldn’t work for part2 <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>
<p>I spent a long time trying to use recursion with memoization but couldn’t get it to terminate on the input.</p>
<p>I thought about it again but in terms of a flow chart/tree:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">tree for example towels
├── r
│   ├── :end
│   └── b
│       └── :end
├── w
│   └── r
│       └── :end
├── b
│   ├── :end
│   ├── w
│   │   └── u
│   │       └── :end
│   └── r
│       └── :end
└── g
    ├── :end
    └── b
        └── :end
</code></pre>
<p>So if looking at color <code>r</code>, it could end there and start down a new tree or keep going, looking for a <code>b</code>.<br>
I reduce the towels to a tree of maps, the <code>r</code> branch for example: <code>%{:end =&gt; :end, "b" =&gt; %{:end =&gt; :end}}</code>.<br>
I reduce the pattern, one color at a time, accumulating all possible permutations in a list of <code>{times, branch}</code> tuples. All branches with <code>:end</code> states are summed to create a new permutation from the current color. All permutations with a next step matching the current color are advanced. The list should only contain unique states. On completion I sum the <code>:end</code> states.<br>
<a href="https://github.com/liamcmitchell/advent-of-code/blob/main/2024/19/1.exs#L44-L52" class="onebox" target="_blank" rel="noopener nofollow ugc">https://github.com/liamcmitchell/advent-of-code/blob/main/2024/19/1.exs#L44-L52</a><br>
Part 2 runs in 32ms on my old machine.</p> 
	            </div>

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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I solved it using a combination of Trie and memoization. I optimized it further with a custom implementation of Trie that returns back all intermediate prefixes and the remaining strings. For example, If we have a trie with values [“r”, “g”, “b”, “rb”, “rg”, “rbrgr”] and we test it on a value “rbrgr”, it would give the following in one pass:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">[
  ok: %Advent.Structures.Trie.Node{depth: 5, final?: true, children: %{}},
  unfinished: "rgr",
  unfinished: "brgr"
]
</code></pre>
<p>I recursively explored all the options after getting these.<br>
It ran in ~19ms for part2 on my machine.<br>
Code the the same can be found here: <a href="https://github.com/divxvid/AdventOfCodeElixir/blob/main/lib/advent/year2024/day19.ex" class="inline-onebox" rel="noopener nofollow ugc">AdventOfCodeElixir/lib/advent/year2024/day19.ex at main · divxvid/AdventOfCodeElixir · GitHub</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="350397" 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-19/68233/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-350397" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350397"
                     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="350442" data-post-id="350442">
  <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>I have never written  a macro before, but part one inspired me to give it a go. In hindsight, it was a bad idea, but it worked for part one.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule LinenLayout do
  defmacro __using__(_opts) do
    quote do
      import LinenLayout

      # safeq (resp. safer) is needed, because I wanted a clause like:
     # def q(_), do: 0
     # but Idk how to make sure that clause comes _after_ all the def's
     # that would be expanded from macros, so instead I use try/rescue to
     # catch invocations that don't have matching defs (e.g., patterns s.t. no
     # towel exists for.
      def safeq(x) do
        try do
          q(x)
        rescue _ -&gt; nil
        end
      end
  
      def safer(x) do
        try do
          r(x)
        rescue _ -&gt; nil
        end
      end

      # these two stop the recursive steps below
      def qq(nil) do
        0
      end
      # using `raise` for control flow. I don't like it, but I was desperate
      # will be rescued in `count_makeable`
      def qq(1) do
        raise "yes"
      end
      
      def qq(x) do
          (safeq(x) |&gt; qq()) + (safer(x) |&gt; qq())
      end

      # invoked when there is no pattern left - we had all the towels we needed
      def q(""), do: 1
      def r(""), do: 1
      def count_makeable(towels) do
        towels 
        |&gt; String.split("\n", trim: true)
        |&gt; Stream.map(&amp;
          try do
            qq(&amp;1)
          # qq throws when `safeq` (resp. `safer`) finished completing a patttern
          rescue _ in RuntimeError -&gt; 1
          end) 
        |&gt; Enum.sum()
      end
    end
  end

  # I didn't need `f` _and_ `h`, but I wanted
  # the macro to expand out to functions with different names.
  # there is a way to do this as an arg to the macro, but  i was lazy.
  # these are exactly the same, to understand why they exist, read `g/1`
  # 
  # The basic idea of the approach is that we will use Elixir's binary
  # pattern matching to do all of the work. Each towel in our
  # inventory will get its own `def q(color &lt;&gt; rest)`. We will recursively call on `q(rest)` 
  # until either:
  # (a) We exhaust the pattern (yay, we had all the towels we needed!) 
  # (b) we throw an error for no clause matching input params (the pattern began 
  # with color  we don't have a towel for).
  defmacro f(i) do
    quote do
      def q(unquote(i) &lt;&gt; rest), do: rest
    end
  end
  
 defmacro h(i) do
    quote do
      def r(unquote(i) &lt;&gt; rest), do: rest
    end
  end

  # takes a list of towels and expands out to two sets of functions:
  # one set where the clauses are ordered longest towel first, e.g.,
  # if `bgr` and `b` are both towels `q("bgr" &lt;&gt; rest)` will appear before
  # `q("b" &lt;&gt; rest)`.
  # the other set is reversed - these are the `r` functions, expanded from `h`, above.
  # 
  # why did I do this? because just one of these directions will miss some patterns
 # because they will be greedy in either using the towels with more stripes first or
 # using the towels with the least stripes first. Doing both was my attempt to fix the
 # issue where either of these under counted. This doesn't _really_ fix the real issue.
 # There could be a towel `"bg"` that is "between" `"bgr"` and `"b"` that would never be
# accounted for if the pattern began with `"bgr"`. In fact, this exact issue is probably why
# this approach will not work for pt. 2.
  defmacro g(u) do
   # `u` is the list of towels we have 
   u = u
    |&gt; String.split(", ")
    

   # expand out `f` for all the towels
    (u 
      |&gt; Enum.sort_by(fn l -&gt; -String.length(l) end) 
      |&gt; Enum.map(fn o -&gt;
        quote do
          f(unquote(o))
        end  
        end)
    )
    ++
    (
     # then expand out `h`
      u 
      |&gt; Enum.sort_by(&amp;(String.length(&amp;1))) 
      |&gt; Enum.map(&amp;(quote do h(unquote(&amp;1)) end))
    )
  end
end
</code></pre>
<p>Now actually solving part 1:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Foo do
  use LinenLayout

  g "r, wr, b, g, bwu, rb, gb, br"
end
</code></pre>
<pre data-code-wrap="elixir"><code class="lang-elixir">"""
brwrr
bggr
gbbr
rrbgbr
ubwu
bwurrg
brgr
bbrgwb
"""
|&gt; Foo.count_makeable()
</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="350442" 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-19/68233/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-350442" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350442"
                     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>