{"id":5421,"date":"2018-03-18T13:00:52","date_gmt":"2018-03-18T13:00:52","guid":{"rendered":"http:\/\/writeasync.net\/?p=5421"},"modified":"2018-04-27T14:58:23","modified_gmt":"2018-04-27T14:58:23","slug":"four-fours","status":"publish","type":"post","link":"https:\/\/writeasync.net\/?p=5421","title":{"rendered":"Four fours"},"content":{"rendered":"<p>Back in elementary school, I became aware of the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Four_fours\">four fours<\/a> puzzle. It is a seemingly simple mathematical exercise where you must generate all the integers from 1 to 100 using arithmetic expressions and the digit 4 exactly four times. A few sample solutions:<\/p>\n<ol>\n<li>44 \/ 44<\/li>\n<li>4 + 4 &#8211; 4 &#8211; sqrt(4)<\/li>\n<li>(4 + 4 + 4)\/4<\/li>\n<\/ol>\n<p>(For perhaps more than you ever wanted to know about the puzzle, I recommend David Wheeler&#8217;s excellent <a href=\"https:\/\/www.dwheeler.com\/fourfours\/\">Definitive Four Fours Answer Key<\/a>.)<\/p>\n<p>Over the years, I have solved the puzzle a few times by hand (sometimes assisted by a <a href=\"http:\/\/www.ticalc.org\/\">TI calculator<\/a>) but had never seriously attempted it programmatically. That all changes now. I present to you <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/tree\/master\/projects\/Four4Sample\">my Four4Sample project on GitHub<\/a>. The rest of this post describes the design and approach of the code.<\/p>\n<p>Before I even wrote a line of code, I spent some time thinking about how to build up the solution expressions. My first instinct was that traditional <a href=\"https:\/\/en.wikipedia.org\/wiki\/Infix_notation\">infix notation<\/a> (e.g. &#8220;4 + 4&#8221; &#8212; the operator &#8220;+&#8221; appears in between the operands) would be rather complicated to deal with. Thus, I set out to write an <a href=\"https:\/\/en.wikipedia.org\/wiki\/Reverse_Polish_notation\">RPN<\/a> expression evaluator, using postfix notation (e.g. &#8220;4 4 +&#8221; &#8212; the operator &#8220;+&#8221; appears <em>after<\/em> the operands). Postfix has the distinct advantage of requiring absolutely no operator precedence handling; any operator can be applied right away.<\/p>\n<p>The first couple dozen commits built up the base infrastructure to handle rational number calculations. By <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/855de832afcb8e38ec820cf7e9209cb897f20dc4\">that point<\/a>, my calculator could handle the basic arithmetic operators, square root (&#8220;R&#8221;) and factorial (&#8220;!&#8221;), along with raw operands for all the numeral 4 expressions (e.g. &#8220;4&#8221;, &#8220;.4&#8221;, and &#8220;.4_&#8221; representing the repeating decimal .4).<\/p>\n<p>The next interesting challenge was handling of invalid results. <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/5be66b947f930ccd2fb88f6d20b81d5b290f17c5\">Several commits<\/a> were dedicated to <a href=\"https:\/\/en.wikipedia.org\/wiki\/NaN\">NaN<\/a> propagation (e.g. &#8220;4 4 &#8211; 4 &#8211; R&#8221; should result in &#8220;NaN&#8221; due to the attempt of taking the square root of -4). Given this &#8220;NaN hammer,&#8221; I chose to treat every error condition as &#8220;NaN&#8221;. This included too many operands (e.g. &#8220;4 4&#8221;), too few operands (e.g. &#8220;4 +&#8221;), division by zero, and so on. <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/22bcba068daecb59c597bffdbb57b4db6b7fca28\">Many more commits<\/a> and a few renames later, I had an Expression class with a good enough Eval method.<\/p>\n<p>Thinking ahead a few steps, I knew I would need to recursively produce expressions to solve the puzzle. For this reason, I began to <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/5313dbe4092e20366441ea3161a7f154d9d1563e\">make all the data structures immutable<\/a>. This would make it much easier to generate new expressions from old ones without altering previous data, and hence seamlessly allow recursive branching and backtracking. It did make the code a bit weirder, though. (NumberStack as a struct with exactly four item fields?!)<\/p>\n<p><a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/179233e98435653c9344dbee36dee54fe44c6bc7\">The next set of commits<\/a> implemented the append operations and tracking of how many digits were used so far. So for example <code>emptyExpr.Append(\"44\").Append(\"4\").Append(\"+\")<\/code> would produce the result <code>48<\/code> with digit count of 3.<\/p>\n<p>Now in the home stretch, I began to <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/9177cdd64495dc07620c4d05c339ebb25a7f6c81\">create the ExpressionSearch class<\/a>. This was the core recursive algorithm to generate all the valid expressions. In plain English, it does the following, starting from a completely empty expression:<\/p>\n<ul>\n<li>If the current expression is invalid, return.<\/li>\n<li>If the current expression has a valid result, report it to a callback method.<\/li>\n<li>If the current expression has fewer than 4 digits, iteratively append every defined operand and recurse on the new expression.<\/li>\n<li>Iteratively append every defined operator (binary or unary) and recurse on the new expression.<\/li>\n<\/ul>\n<p>Eventually I added <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/ee225ff120fed5619357768286e7b149b0703195\">some logic to stop early<\/a>, to optimize for the traditional case where the user wants only solutions from 1-100.<\/p>\n<p>This algorithm served me well, but initially had some problems. The first thing I noticed is that unary operators were prone to stack overflow. This is because expressions like &#8220;4 4 \/&#8221; (i.e. 1) can have, say, &#8220;R&#8221; (square root) appended infinitely with no change in the result or the digit count. I &#8220;fixed&#8221; this by simply redefining &#8220;R&#8221; to be invalid for any case where <code>x = sqrt(x)<\/code> &#8212; <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/8acf697274335bf671f4333a421323fc50208bf3\">specifically, 0 and 1<\/a>. The &#8220;!&#8221; (factorial) operator had the same problem for some numbers, so I applied <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/911d0cb55d202122ca6b3d200e62705d0ff16649\">a similar fix for 1 and 2<\/a>. (Binary operators were immune to this problem because they always reduced the stack size and would eventually &#8220;error out&#8221; naturally after the stack reached a size of one.)<\/p>\n<p>The final major tweak I made to the program was to allow presenting the results in the more familiar infix style. <a href=\"https:\/\/stackoverflow.com\/questions\/19052960\/converting-from-postfix-to-infix\">Postfix to infix conversion<\/a> is even easier than postfix parsing, so it only took <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/2344b079841fe1cb88c4d576c71f572ce86d13d6\">a handful of commits<\/a> to get this working to my liking. (I did not attempt to remove redundant parentheses &#8212; that would have complicated things quite a bit more.)<\/p>\n<p>Before I was done, I was a little concerned I might need to use parallelism to improve the performance. This would have needed a fundamental rework to the design. Luckily, though, the program already completes surprisingly fast without any special effort.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nFound 100 results in 251 ms.\r\n1 = ((4+(4-(4+4))))!\r\n2 = sqrt(sqrt((4+(4+(4+4)))))\r\n3 = (4-((4*(4-4)))!)\r\n4 = sqrt((4+(4+(4+4))))\r\n . . .\r\n<\/pre>\n<p>Note that some of the shortcuts I took make it impossible to generate some of the more &#8220;clever&#8221; solutions, such as those that require irrational numbers in intermediate steps. Nevertheless, I feel pretty good about the result. Like the four fours puzzle itself, it was a fun diversion, as well as a chance to flex my TDD muscles.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Back in elementary school, I became aware of the four fours puzzle. It is a seemingly simple mathematical exercise where you must generate all the integers from 1 to 100 using arithmetic expressions and the digit 4 exactly four times.&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[103,41],"tags":[],"class_list":["post-5421","post","type-post","status-publish","format-standard","hentry","category-math","category-tdd"],"_links":{"self":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5421","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5421"}],"version-history":[{"count":3,"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5421\/revisions"}],"predecessor-version":[{"id":5432,"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5421\/revisions\/5432"}],"wp:attachment":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5421"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5421"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5421"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}