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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="faried" data-post="7" data-topic="36300">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/faried/48/17538_2.png" class="avatar"> faried:</div>
<blockquote>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def split(s) do
    s
    |&gt; String.replace("(", "( ")
    |&gt; String.replace(")", " )")
    |&gt; String.split()
  end
</code></pre>
</blockquote>
</aside>
<p>Such a pragmatic solution <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">, I was so tired when tackling this and spent more-time-than-I-want-to-admit solving for merging the numbers back after splitting with <code>String.graphemes()</code> due to those parenthesis without whitespace <img src="https://forum.elixirforum.com/images/emoji/apple/blush.png?v=15" title=":blush:" class="emoji" alt=":blush:" 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="197905" data-batch-url="/posts/batch_likers">
                        3
                      </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-2020-day-18/36300/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-197905" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="197905"
                     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="197938" data-post-id="197938">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I originally parsed each equation into an expression tree to evaluate them - which worked, but then I saw on reddit someone mention the shunting yard algorithm - did a bunch of reading on operator precedence parsing and stack based calculators and was able to refactor my code in a really satisfying way.  The implementation of the algorithm and the evaluator could use some clean up, but it works, and it works about 10 times faster then the expression tree approach</p>
<p><a href="https://github.com/camilleryr/advent20/blob/main/lib/day_18.ex" class="onebox" target="_blank" rel="noopener nofollow ugc">https://github.com/camilleryr/advent20/blob/main/lib/day_18.ex</a></p>
<aside class="onebox wikipedia" data-onebox-src="https://en.wikipedia.org/wiki/Shunting-yard_algorithm">
  <header class="source">

      <a href="https://en.wikipedia.org/wiki/Shunting-yard_algorithm" target="_blank" rel="noopener nofollow ugc">en.wikipedia.org</a>
  </header>

  <article class="onebox-body">
    

<h3><a href="https://en.wikipedia.org/wiki/Shunting-yard_algorithm" target="_blank" rel="noopener nofollow ugc">Shunting yard algorithm</a></h3>

<p>In computer science, the shunting yard algorithm is a method for parsing arithmetical or logical expressions, or a combination of both, specified in infix notation. It can produce either a postfix notation string, also known as reverse Polish notation (RPN), or an abstract syntax tree (AST). The algorithm was invented by Edsger Dijkstra, first published in November 1961, and named because its operation resembles that of a railroad shunting yard.
 Like the evaluation of RPN, the shunting yard algo...</p>

  </article>

  <div class="onebox-metadata">
    
    
  </div>

  <div style="clear: both"></div>
</aside>
 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="197938" data-batch-url="/posts/batch_likers">
                        4
                      </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-2020-day-18/36300/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-197938" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="197938"
                     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="197949" data-post-id="197949">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Honestly, I’m a bit blown away by people cracking open the AST and evaluating the expressions in Elixir. Once advent of code is complete I feel like I need to go back through the days and really try to grock everyone’s code. Lot’s of good stuff that I haven’t had the chance to look at.</p>
<p>I had a much more mundane, tree based approach. My solution to part 2 was just to wrap addition in some parens.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Day18 do

  def part_1, do: load() |&gt; Enum.map(&amp;interpret/1) |&gt; Enum.sum()
  def part_2, do: load() |&gt; Enum.map(&amp;interpret2/1) |&gt; Enum.sum()

  def interpret(text), do: text |&gt; lex() |&gt; parse() |&gt; eval()
  def interpret2(text), do: text |&gt; lex() |&gt; parse() |&gt; wrap() |&gt; eval()

  def lex(""), do: []
  def lex(" " &lt;&gt; rest), do: lex(rest)
  def lex(&lt;&lt;n::bytes-size(1)&gt;&gt; &lt;&gt; rest) when n in ["(", ")", "+", "*"], do: [n|lex(rest)]
  def lex(&lt;&lt;n::bytes-size(1)&gt;&gt; &lt;&gt; rest), do: [String.to_integer(n)|lex(rest)]

  def parse(tokens=["("|_]), do: parse(match_parens(tokens, []))
  def parse([n|rest]), do: [parse(n)|parse(rest)]
  def parse(n), do: n

  def match_parens(["("|t], stack), do: match_parens(t, [[]|stack])
  def match_parens([")"|t], [c,p|rest]), do: match_parens(t, [[parse(Enum.reverse(c))|p]|rest])
  def match_parens([")"|rest], [group]), do: [Enum.reverse(group)|rest]
  def match_parens([n|t], [group|rest]), do: match_parens(t, [[n|group]|rest])

  def wrap([]), do: []
  def wrap([left, "+", right|rest]), do: wrap([[wrap(left), "+", wrap(right)]|rest])
  def wrap([left, "*", right|rest]), do: [wrap(left), "*"| wrap([wrap(right)|rest])]
  def wrap([n]), do: [n]
  def wrap(n), do: n

  def eval(prev, []), do: prev
  def eval(prev, ["+", n|rest]), do: eval(prev + eval(n), rest)
  def eval(prev, ["*", n|rest]), do: eval(prev * eval(n), rest)
  def eval([n, "+", m|rest]), do: eval(eval(n) + eval(m), rest)
  def eval([n, "*", m|rest]), do: eval(eval(n) * eval(m), rest)
  def eval([l=[_|_]]), do: eval(l)
  def eval(n), do: n

  def load, do: File.read!("day-18.input") |&gt; String.split("\n", trim: true)
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="197949" 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-2020-day-18/36300/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-197949" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="197949"
                     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="197953" data-post-id="197953">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>That’s what I also ended up doing but my code was a lot messier. Tried reimplementing it using the Shunting Yard algorithm suggested by <a class="mention" href="/u/camilleryr" rel="nofollow">@camilleryr</a> which made it a lot nicer and easier to change as part 2 would have been a simple change of:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def precedence(operator) do
    case operator do
      "+" -&gt; 3
      "*" -&gt; 2
    end
  end
</code></pre>
<p>Was a fun exercise!</p>
<p>The <a href="https://gist.github.com/hallski/2f38039c64da7305237900ca45722045" rel="noopener nofollow ugc">code</a> if anyone is interested.</p>
<p>And the <a href="https://gist.github.com/hallski/878fa736493a7cb4f78f3ff7ce2a1603" rel="noopener nofollow ugc">code from this morning</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="197953" 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-2020-day-18/36300/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-197953" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="197953"
                     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="197957" data-post-id="197957">
  <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
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I tried to do that in Elixir tonight, it works. Of course, it is absolutely terrible. But it works <img src="https://forum.elixirforum.com/images/emoji/apple/wink.png?v=15" title=":wink:" class="emoji" alt=":wink:" loading="lazy" width="20" height="20"> I still like my first solution better though.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule NoPrecedence do
  import Kernel, except: [-: 2]

  def a - b, do: a * b

  def eval(expression) do
    env = Map.update!(__ENV__, :functions, &amp;[{__MODULE__, -: 2} | &amp;1])

    expression
    |&gt; String.replace("*", "-")
    |&gt; Code.eval_string([], env)
    |&gt; elem(0)
  end
end

defmodule AdditionPrecedence do
  import Kernel, except: [-: 2, /: 2]

  def a / b, do: a + b
  def a - b, do: a * b

  def eval(expression) do
    env = Map.update!(__ENV__, :functions, &amp;[{__MODULE__, -: 2}, {__MODULE__, "/": 2} | &amp;1])

    expression
    |&gt; String.replace("+", "/")
    |&gt; String.replace("*", "-")
    |&gt; Code.eval_string([], env)
    |&gt; elem(0)
  end
end

for line &lt;- File.stream!("../src/adventofcode/priv/input/2020/day-18.inp") do
  NoPrecedence.eval(line)
end
|&gt; Enum.sum()
|&gt; IO.inspect(label: "part 1")

for line &lt;- File.stream!("../src/adventofcode/priv/input/2020/day-18.inp"), reduce: 0 do
  sum -&gt; sum + AdditionPrecedence.eval(line)
end
|&gt; IO.inspect(label: "part 2")

</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="197957" 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-2020-day-18/36300/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-197957" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="197957"
                     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="198077" data-post-id="198077">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Slower pace now so I <a href="https://github.com/adamu/AdventOfCode2020/tree/main/day18" rel="noopener nofollow ugc">only just</a> got around to finishing this.</p>
<p>I noticed <a href="https://github.com/adamu/AdventOfCode2020/blob/main/day18/day18part1.exs" rel="noopener nofollow ugc">Part 1</a> could be optimised to just walk the string, using recursion for the parentheses. Unfortunately, that meant I had to effectively start again for Part 2. Here’s an excerpt from Part 1:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def evaluate(command), do: evaluate(command, nil, 0)
  def evaluate([], nil, acc), do: acc
  def evaluate(["*" | rest], nil, acc), do: evaluate(rest, "*", acc)
  def evaluate(["+" | rest], nil, acc), do: evaluate(rest, "+", acc)
  def evaluate(["(" | rest], op, acc), do: evaluate(rest) |&gt; evaluate(op, acc)
  def evaluate([")" | rest], nil, acc), do: [acc | rest]
  def evaluate([num | rest], "*", acc), do: evaluate(rest, nil, acc * num)
  def evaluate([num | rest], "+", acc), do: evaluate(rest, nil, acc + num)
  def evaluate([num | rest], nil, 0), do: evaluate(rest, nil, num)
</code></pre>
<p>I also went the AST route for <a href="https://github.com/adamu/AdventOfCode2020/blob/main/day18/day18part2.exs" rel="noopener nofollow ugc">Part 2</a>, first building up a tree and then evaluating it. I spent more time that I care to admit on that fixing silly bugs and staring at logging output, and the end result is not exactly pretty either. I wasn’t sure how to parse the precedence correctly. I decided to do it in two passes: first construct the <code>+</code> operations, then go back and pick up any <code>*</code> operations left - although it felt pretty awkward.</p>
<p>I wanted to do the AST, so it was a good exercise, but I wish I’d come up with <a class="mention" href="/u/princemaple" rel="nofollow">@princemaple</a>’s elegant solution.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="198077" 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-2020-day-18/36300/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-198077" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="198077"
                     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="198105" data-post-id="198105">
  <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>This seemed like a good time to try out NimbleParsec, it worked out pretty well:</p>
<p><a href="https://github.com/al2o3cr/advent-of-code-2020/blob/main/day18/part1.exs" class="onebox" target="_blank" rel="noopener nofollow">https://github.com/al2o3cr/advent-of-code-2020/blob/main/day18/part1.exs</a></p>
<p>I still don’t have a great mental model for what adding <code>wrap()</code> does, but some experimentation got me through.</p>
<p>I’m curious what somebody who knows the library better would do…</p> 
	            </div>

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