diff --git a/ipynb/Countdown.ipynb b/ipynb/Countdown.ipynb index d9cc6aa..63e7e0b 100644 --- a/ipynb/Countdown.ipynb +++ b/ipynb/Countdown.ipynb @@ -12,25 +12,14 @@ "source": [ "
Peter Norvig
Jan 2016
revised 2018, 2020
\n", "\n", - "# Making Numbers: Four 4s, Five 5s, Countdowns, etc.\n", + "# Making Numbers: Countdowns, Four 4s, Five 5s, ...\n", "\n", - "On January 1, 2016 Alex Bellos [posed](http://www.theguardian.com/science/2016/jan/04/can-you-solve-it-complete-the-equation-10-9-8-7-6-5-4-3-2-1-2016) (and subsequently [answered](http://www.theguardian.com/science/2016/jan/04/did-you-solve-it-complete-the-equation-10-9-8-7-6-5-4-3-2-1-2016)) this New Year's puzzle:\n", - "\n", - "\n", - "> Fill in the blanks so that this equation makes arithmetical sense:\n", - ">\n", - "> `10 ␣ 9 ␣ 8 ␣ 7 ␣ 6 ␣ 5 ␣ 4 ␣ 3 ␣ 2 ␣ 1 = 2016`\n", - ">\n", - "> You are allowed to use *only* the four basic arithmetical operations: +, -, ×, ÷. But brackets (parentheses) can be used wherever needed. So, for example, the solution could begin\n", - ">\n", - "> `(10 + 9) * (8` ... or `10 + (9 * 8)` ...\n", - "\n", - "Let's see if we can solve this puzzle, and some related puzzles about making mathematical expressions by combining numbers and operators. First some imports:" + "In this notebook we solve a range of related puzzles that all involve making mathematical expressions by combining numbers and operators in various ways to make target numeric values. First some imports, and then we can look at the first problem." ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -54,7 +43,19 @@ } }, "source": [ - "# Four Basic Operators, No Brackets\n", + "# Countdown to 2016\n", + "\n", + "On January 1, 2016 Alex Bellos [posed](http://www.theguardian.com/science/2016/jan/04/can-you-solve-it-complete-the-equation-10-9-8-7-6-5-4-3-2-1-2016) (and subsequently [answered](http://www.theguardian.com/science/2016/jan/04/did-you-solve-it-complete-the-equation-10-9-8-7-6-5-4-3-2-1-2016)) this New Year's puzzle:\n", + "\n", + "\n", + "> Fill in the blanks so that this equation makes arithmetical sense:\n", + ">\n", + "> `10 ␣ 9 ␣ 8 ␣ 7 ␣ 6 ␣ 5 ␣ 4 ␣ 3 ␣ 2 ␣ 1 = 2016`\n", + ">\n", + "> You are allowed to use *only* the four basic arithmetical operations: +, -, ×, ÷. But brackets (parentheses) can be used wherever needed. So, for example, the solution could begin\n", + ">\n", + "> `(10 + 9) * (8` ... or `10 + (9 * 8)` ...\n", + "# Countdown to 2016: Four Operators, No Brackets\n", "\n", "We'll start with a simpler version of the puzzle: a countdown with no brackets. \n", "\n", @@ -73,6 +74,8 @@ }, "outputs": [], "source": [ + "countdown = '10{}9{}8{}7{}6{}5{}4{}3{}2{}1'\n", + "\n", "allops = list(product('+-*/', repeat=9))" ] }, @@ -133,7 +136,7 @@ } ], "source": [ - "'10{}9{}8{}7{}6{}5{}4{}3{}2{}1'.format(*allops[100003])" + "countdown.format(*allops[100003])" ] }, { @@ -162,7 +165,7 @@ "source": [ "(*Warning*: don't use eval on strings that you aren't sure are safe.)\n", "\n", - "We need to catch errors such as dividing by zero, so I'll define a wrapper function, `evaluate`, to do that, and I'll define `simple_countdown` to put the pieces together:" + "We need to catch errors such as dividing by zero, so I'll define a wrapper function, `evaluate`, to do that: " ] }, { @@ -184,34 +187,26 @@ " try:\n", " return eval(exp)\n", " except ArithmeticError:\n", - " return None\n", - "\n", - "@lru_cache(None)\n", - "def simple_countdown(target, operators='+-*/') -> List[Exp]:\n", - " \"\"\"All solutions to the countdown puzzle (with no brackets) for target year.\"\"\"\n", - " exps = ('10{}9{}8{}7{}6{}5{}4{}3{}2{}1'.format(*ops)\n", - " for ops in product(operators, repeat=9))\n", - " return [exp for exp in exps if evaluate(exp) == target]" + " return None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can try to find an expression that evaluates to 2016:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "simple_countdown(2016)" + "for ops in allops:\n", + " exp = countdown.format(*ops)\n", + " if evaluate(exp) == 2016:\n", + " print(exp)" ] }, { @@ -224,7 +219,7 @@ } }, "source": [ - "Too bad; we did all that work and didn't find a solution. What years *can* we find solutions for? I'll define `simple_countdowns` to take a collection of target years rather than a single one, and return a dict of the form `{year: 'expression'}` for each expression that evaluates to one of the target years. I'll also generalize it to allow any format string, with the default being the countdown string." + "Too bad; we did all that work and no solution was printed. What years *can* we find solutions for? I'll define the function `simple_countdowns` to take a collection of target years and return a dict of the form `{year: 'expression'}` for each expression that evaluates to one of the target years. I'll generalize the function to allow any format string, and any collection of Python operators:" ] }, { @@ -258,11 +253,10 @@ } ], "source": [ - "def simple_countdowns(targets, operators='+-*/',\n", - " fmt='10{}9{}8{}7{}6{}5{}4{}3{}2{}1') -> Dict[int, List[Exp]]:\n", + "def simple_countdowns(targets, operators='+-*/', fmt=countdown) -> Dict[int, Exp]:\n", " \"\"\"All solutions to the countdown puzzle (with no brackets) for target years.\"\"\"\n", " exps = (fmt.format(*ops)\n", - " for ops in product(operators, repeat=9))\n", + " for ops in product(operators, repeat=fmt.count('{}')))\n", " table = {evaluate(exp): exp for exp in exps}\n", " return {t: table[t] for t in targets if t in table}\n", "\n", @@ -292,7 +286,7 @@ } }, "source": [ - "# Four Basic Operators, With Brackets\n", + "# Countdown to 2016: Four Operators, With Brackets\n", "\n", "Now we return to the original problem. Can I make use of what I have so far? Well, `simple_countdowns` accepts a `fmt` string as input, so I could give it all possible bracketed format strings and let it fill in all possible operator combinations. How long would that take? I happen to remember that the number of bracketings of *n* operands is the nth [Catalan number](https://oeis.org/A000108), so for *n* = 9 there are 4,862 bracketings. A single call to `simple_countdown` took about 2 seconds, so we could do 4,862 calls in about 160 minutes. That's not terrible, but (a) it would still take work to generate all the bracketings, and (b) I think I can find another way that is much faster.\n", "\n", @@ -301,7 +295,7 @@ " expressions((10,)) ⇒ {10: '10'}\n", " expressions((9, 8)) ⇒ {1: '(9-8)', 1.125: '(9/8)', 17: '(9+8)', 72: '(9*8)'}\n", "\n", - "I'll use the idea of [dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming): break the problem down into simpler subparts, compute an answer for each subpart, and remember intermediate results so we don't need to re-compute them later. How do we break the problem into parts? `expressions((10, 9, 8))` should consist of all the ways of splitting `(10, 9, 8)` into two parts, finding all the expressions that can be made with each part, and combining pairs of expressions with any of the four operators:\n", + "I'll use the idea of [**dynamic programming**](https://en.wikipedia.org/wiki/Dynamic_programming): break the problem down into simpler subparts, compute an answer for each subpart, and remember intermediate results so we don't need to re-compute them later. How do we break the problem into parts? `expressions((10, 9, 8))` should consist of all the ways of splitting `(10, 9, 8)` into two parts, finding all the expressions that can be made with each part, and combining pairs of expressions with any of the four operators:\n", "\n", " expressions((10, 9, 8)) ⇒ {11: '(10+(9-8))', 27: '(10+(9+8))', 720: '(10*(9*8))', ...}\n", "\n", @@ -540,7 +534,7 @@ "source": [ "That looks reasonable. Let's solve the whole puzzle.\n", "\n", - "# Countdown to 2016: A Solution" + "# Countdown to 2016: A Solution\n" ] }, { @@ -558,8 +552,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 26.4 s, sys: 628 ms, total: 27.1 s\n", - "Wall time: 28 s\n" + "CPU times: user 27.3 s, sys: 714 ms, total: 28 s\n", + "Wall time: 28.6 s\n" ] }, { @@ -647,7 +641,7 @@ "\n", "So how can I count expressions? One approach would be to go back to enumerating every equation (all 4862 × 49 = 1.2 bilion of them) and checking which ones equal 2016. That would take about 40 hours with my Python program. A better approach is to mimic `expressions`, but to make a table of counts, rather than expression strings. I want:\n", "\n", - " counts((10, 9, 8))[27] == 2\n", + " expression_counts((10, 9, 8))[27] == 2\n", " \n", "because there are 2 ways to make 27 with the numbers `(10, 9, 8)`, namely, `((10+9)+8)` and `(10+(9+8))`. And in general, if there are `Lcount` ways to make `L` using `Lnums` and `Rcount` ways to make `R` using `Rnums` then there are `Lcount * Rcount` ways of making `L + R` using `Lnums` followed by `Rnums`. So we have:\n" ] @@ -665,15 +659,15 @@ "outputs": [], "source": [ "@lru_cache(None)\n", - "def counts(numbers: tuple) -> Counter:\n", + "def expression_counts(numbers: tuple) -> Counter:\n", " \"Return a Counter of {value: count} for every value that can be made from numbers.\"\n", " if len(numbers) == 1: # Only one way to make an expression out of a single number\n", " return Counter(numbers)\n", " else: \n", " table = Counter()\n", " for (Lnums, Rnums) in splits(numbers):\n", - " for L, R in product(counts(Lnums), counts(Rnums)):\n", - " count = counts(Lnums)[L] * counts(Rnums)[R]\n", + " for L, R in product(expression_counts(Lnums), expression_counts(Rnums)):\n", + " count = expression_counts(Lnums)[L] * expression_counts(Rnums)[R]\n", " if R != 0:\n", " table[L / R] += count\n", " table[L + R] += count\n", @@ -699,7 +693,7 @@ } ], "source": [ - "counts((2, 2)) # corresponds to {0: '2-2', 1.0: '2/2', 4: '2+2' or '2*2'}" + "expression_counts((2, 2)) # corresponds to {0: '2-2', 1.0: '2/2', 4: '2+2' or '2*2'}" ] }, { @@ -725,7 +719,7 @@ } ], "source": [ - "counts((10, 9, 8))[27] # (10+9)+8 or 10+(9+8)" + "expression_counts((10, 9, 8))[27] # (10+9)+8 or 10+(9+8)" ] }, { @@ -764,7 +758,7 @@ } ], "source": [ - "counts(c10)[2016]" + "expression_counts(c10)[2016]" ] }, { @@ -872,7 +866,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now I can count up all the expressions in the `counts(c10)` table that are near 2016, but with `exact` computation to check that the expressions evaluate to exactly 2016:" + "Now I can count up all the expressions in the `expression_counts(c10)` table that are near 2016, but with `exact` computation to check that the expressions evaluate to exactly 2016:" ] }, { @@ -892,7 +886,7 @@ } ], "source": [ - "sum(counts(c10)[y] \n", + "sum(expression_counts(c10)[y] \n", " for y, exp in expressions(c10).items()\n", " if abs(y - 2016) < 1e-10 and eval(exact(exp)) == 2016)" ] @@ -916,7 +910,7 @@ "source": [ "# Four 4s\n", "\n", - "Alex Bellos continues with a related puzzle:\n", + "Alex Bellos continued his original puzzle column with a related puzzle:\n", " \n", "> The most famous “fill in the gaps in the equation” puzzle is known as [**four fours**](https://en.wikipedia.org/wiki/Four_fours), because every equation is of the form\n", ">\n", @@ -975,7 +969,7 @@ "\n", "It seems there are a lot of puzzles that are similar to four 4s, and they all have different rules for which numbers are required and which operators are allowed. To facilitate solving a range of puzzles with different operators, I will redefine `expressions` to take a second argument, `ops`, listing the allowable operations.\n", "\n", - "The operations will be specified as a string of one-character codes. The table below gives the allowable codes, binary operators on the left and unary operators on the right, except that the last row gives two \"operations\" on digits, decimal points and concatenation:\n", + "The operations will be specified as a string of one-character codes. The table below gives the allowable codes, binary operators on the left and unary operators on the right, except that the last row gives two pseudo-operations on digits, decimal points and concatenation:\n", "\n", "|Code|Operator|Code|Operator|\n", "|------|--------|------|--------|\n", @@ -993,26 +987,6 @@ "cell_type": "code", "execution_count": 27, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "4.5 in range(7)" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, "outputs": [], "source": [ "def true(*args): return True\n", @@ -1024,7 +998,8 @@ " Operator('-', sub),\n", " Operator('*', mul),\n", " Operator('/', div, None, lambda L, R: R != 0),\n", - " Operator('^', pow, None, lambda L, R: -10 <= R <= 10 and (L > 0 or R == int(R)))},\n", + " Operator('^', pow, None, lambda L, R: -10 <= R <= 10 and (L > 0 or R == int(R)) \n", + " and not (L == 0 == R))},\n", " 1: {Operator('√', sqrt, '√{}', lambda v: 0 < v <= 100 and (120. * v).is_integer()),\n", " Operator('!', factorial, '{}!', lambda v: v in range(7)),\n", " Operator('_', neg, '-{}'),\n", @@ -1042,14 +1017,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "There are some complications (and how I'll handle them):\n", + "There are some complications; here's how I'll handle them:\n", "\n", "- **Irrationals**: `√2` is an irrational number (I'll use floating point approximations for everything).\n", "- **Imaginaries**: `√-1` is an imaginary number (I won't allow imaginary numbers).\n", "- **Overflow**: `(10. ^ (9. ^ 8.))`, as a `float`, gives an `OverflowError` (I'll drop overflow results).\n", "- **Memory**: `(10 ^ (9 ^ (8 ^ 7)))`, as an `int`, gives an `OutOfMemoryError` (I'll limit exponents).\n", "- **Infinite unary operators**: `√√√√√√...(4!!!!!!!!...)` (I'll only allow two unary operators per expression).\n", - "- **Round-off error**: As we have seen, `(49*(1/49))` evaluates to `0.9999999999999999`, not `1` (I'll try to round off)." + "- **Round-off error**:`(49*(1/49)) == 0.9999999999999999`, not `1` (I'll try to round off)." ] }, { @@ -1117,7 +1092,7 @@ " D = ''.join(map(str, digits))\n", " table = {}\n", " if '.' in ops: table.update({float(d): d for d in decimals(D)})\n", - " if '$' in ops or len(D) == 1: table[int(D)] = D\n", + " if '$' in ops or len(digits) == 1: table[int(D)] = D\n", " return table\n", "\n", "def decimals(digits: str)-> List[str]:\n", @@ -1150,7 +1125,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The function `assign` adds a `{val: exp}` entry to `table`, but if there is already an entry for `val`, it prefers the entry with the lowest total *weight*: the number of characters plus extra points for particularly complex characters. The idea is to prefer simpler expressions, but the weights are completely arbitrary. If you want to prefer complex expressions, you cvan change the weights to be negative. The weights don't change how many different values can be made, they just change which of two or more expressions are chosen to represent a value." + "The function `assign` adds a `{val: exp}` entry to `table`, but if there is already an entry for `val`, it prefers the entry with the lowest total *weight*: the number of characters plus extra points for particularly complex characters. The idea is to prefer simpler expressions, but the weights are completely arbitrary. If you prefer complex expressions, you can change the weights to be negative. The weights don't change how many different values can be made, they just change which of two or more expressions are chosen to represent a value." ] }, { @@ -1183,8 +1158,8 @@ "outputs": [], "source": [ "assert digit_expressions((1, 2), OPS) == {12: '12', 0.12: '.12', 1.2: '1.2'}\n", - "assert digit_expressions((1, 2), '$') == {12.0: '12'}\n", - "assert digit_expressions((1, 2), '') == {} # If concatenation is not allowed, (1, 2) can't be put together.\n", + "assert digit_expressions((1, 2), '$') == {12: '12'}\n", + "assert digit_expressions((1, 2), '') == {} \n", "assert digit_expressions((1,), '$') == {1: '1'}\n", "\n", "assert decimals('123') == ['.123', '1.23', '12.3']\n", @@ -1222,13 +1197,13 @@ }, "outputs": [], "source": [ - "def show(numbers: tuple, limit=10000, ops=OPS, clear=True):\n", + "def show(numbers: tuple, limit=None, ops=OPS, clear=True):\n", " \"\"\"Print expressions for integers from 0 up to limit or the first unmakeable integer.\"\"\"\n", " if clear: expressions.cache_clear() # To free up memory\n", " table = expressions(numbers, ops)\n", " print(f'Can make 0 to {unmakeable(table)-1} with expressions({numbers}, \"{ops}\").'\n", " f' ({len(table):,} table entries)\\n')\n", - " for i in range(unmakeable(table)): \n", + " for i in range(limit or unmakeable(table)): \n", " print('{:4} = {}'.format(i, unbracket(table[i])))\n", " \n", "def unmakeable(table) -> int:\n", @@ -1327,14 +1302,14 @@ " 64 = (4+4)*(4+4)\n", " 65 = (4+(4^4))/4\n", " 66 = √4+(4*(4*4))\n", - " 67 = √4+((4!+√4)/.4)\n", + " 67 = √4+((√4+4!)/.4)\n", " 68 = 4+(4*(4*4))\n", " 69 = (4+(4!-.4))/.4\n", - " 70 = 4!+(√4+44)\n", + " 70 = √4+(4!+44)\n", " 71 = (4!+4.4)/.4\n", " 72 = 4+(4!+44)\n", - "CPU times: user 28.7 s, sys: 101 ms, total: 28.8 s\n", - "Wall time: 28.9 s\n" + "CPU times: user 29.5 s, sys: 224 ms, total: 29.7 s\n", + "Wall time: 30 s\n" ] } ], @@ -1393,7 +1368,7 @@ "source": [ "In a [separate video](https://www.youtube.com/embed/Noo4lN-vSvw), Alex Bellos shows how to form **every** integer from 0 to infinity using four 4s, if the square root and `log` functions are allowed. The solution comes from Paul Dirac (although [Dirac originally developed it](https://nebusresearch.wordpress.com/2014/04/18/how-dirac-made-every-number/) for the \"four 2s\" problem).\n", "\n", - "Donald Knuth has [conjectured](https://www.tandfonline.com/doi/abs/10.1080/0025570X.1964.11975546) that with floor, square root and factorial, you can make any positive integer with just **one** 4.\n", + "Donald Knuth [conjectured](https://www.tandfonline.com/doi/abs/10.1080/0025570X.1964.11975546) that with floor, square root and factorial, you can make any positive integer with just **one** 4.\n", "\n", "Below are some popular variant problems:\n", "\n", @@ -1592,15 +1567,15 @@ " 29 = (5!+(5*5))/5\n", " 30 = 55-(5*5)\n", " 31 = 55-(5!/5)\n", - " 32 = ((5+5)/5)^5\n", + " 32 = (5.5-5)^-5\n", " 33 = .5*(5!*.55)\n", " 34 = 5+(5+(5!/5))\n", " 35 = 5+(5+(5*5))\n", " 36 = (5!+(.5*5!))/5\n", " 37 = 5+(.5^-√(5*5))\n", " 38 = ((5!/5)-5)/.5\n", - "CPU times: user 8.55 s, sys: 17 ms, total: 8.57 s\n", - "Wall time: 8.58 s\n" + "CPU times: user 8.6 s, sys: 19.4 ms, total: 8.62 s\n", + "Wall time: 8.63 s\n" ] } ], @@ -1621,7 +1596,7 @@ "\n", "# Countdown to 2018\n", "\n", - "Now a slightly different kind of puzzle. On December 31 2017, [Michael Littman](http://cs.brown.edu/~mlittman/) posted this:\n", + "Now another type of New Year's countdown puzzle. On December 31 2017, [Michael Littman](http://cs.brown.edu/~mlittman/) posted this:\n", "\n", "> 2+0+1×8, 2+0-1+8, (2+0-1)×8, |2-0-1-8|, -2-0+1×8, -(2+0+1-8), √|2+0-18|, 2+0+1^8, 20-18, 2^(0×18), 2×0×1×8... Happy New Year!\n", "\n", @@ -1649,32 +1624,12 @@ " 7 = -2+(01+8)\n", " 8 = (2-01)*8\n", " 9 = (2-01)+8\n", - " 10 = 2+(01*8)\n", - " 11 = 2+(01+8)\n", - " 12 = 20-(1*8)\n", - " 13 = 20+(1-8)\n", - " 14 = 2*(-01+8)\n", - " 15 = -(2+0!)+18\n", - " 16 = -2+018\n", - " 17 = -(2^0)+18\n", - " 18 = 2*(01+8)\n", - " 19 = (2^0)+18\n", - " 20 = 2+018\n", - " 21 = 20+(1^8)\n", - " 22 = ((2+0!)/.1)-8\n", - " 23 = 20+√(1+8)\n", - " 24 = (2+01)*8\n", - " 25 = 2/(.01*8)\n", - " 26 = 20+√(1+8)!\n", - " 27 = (20-1)+8\n", - " 28 = 20+(1*8)\n", - " 29 = 20+(1+8)\n", - " 30 = (2*(0!+1))!/.8\n" + " 10 = 2+(01*8)\n" ] } ], "source": [ - "show((2,0,1,8), 10)" + "show((2,0,1,8), 11)" ] }, { @@ -1698,38 +1653,12 @@ " 7 = -2+(01*9)\n", " 8 = -2+(01+9)\n", " 9 = (2-01)*9\n", - " 10 = 20-(1+9)\n", - " 11 = 2+(01*9)\n", - " 12 = 2+(01+9)\n", - " 13 = 2+(0!+(1+9))\n", - " 14 = (.2^-01)+9\n", - " 15 = (2+01)!+9\n", - " 16 = 2*(-01+9)\n", - " 17 = -2+019\n", - " 18 = 2*(01*9)\n", - " 19 = (2*0)+19\n", - " 20 = 2*(01+9)\n", - " 21 = 2+019\n", - " 22 = 2+(0!+19)\n", - " 23 = 20+(1*√9)\n", - " 24 = 20+(1+√9)\n", - " 25 = 20/(-.1+.9)\n", - " 26 = 2+(01+√9)!\n", - " 27 = (2+01)*9\n", - " 28 = (20-1)+9\n", - " 29 = 20+(1*9)\n", - " 30 = 20+(1+9)\n", - " 31 = (.2^-(0!+1))+√9!\n", - " 32 = √2^(01+9)\n", - " 33 = (2*(0!+1))!+9\n", - " 34 = (.2^-(0!+1))+9\n", - " 35 = (√2^(0!/.1))+√9\n", - " 36 = 2*(-0!+19)\n" + " 10 = 20-(1+9)\n" ] } ], "source": [ - "show((2,0,1,9), 10)" + "show((2,0,1,9), 11)" ] }, { @@ -1753,29 +1682,12 @@ " 7 = 2+(0!/.20)\n", " 8 = 2^(02+0!)\n", " 9 = (20/2)-0!\n", - " 10 = 2/0.20\n", - " 11 = (20/2)+0!\n", - " 12 = 2*(02+0!)!\n", - " 13 = (2*(0!+2)!)+0!\n", - " 14 = 20-(2+0!)!\n", - " 15 = (2+0!)/.20\n", - " 16 = 20*(-.2+0!)\n", - " 17 = 20-(2+0!)\n", - " 18 = -2+020\n", - " 19 = 20-(2^0)\n", - " 20 = 20+(2*0)\n", - " 21 = 20+(2^0)\n", - " 22 = 2+020\n", - " 23 = 2+(0!+20)\n", - " 24 = (.2*020)!\n", - " 25 = .20^-2.0\n", - " 26 = 20+(2+0!)!\n", - " 27 = (2+0!)^(2+0!)\n" + " 10 = 2/0.20\n" ] } ], "source": [ - "show((2,0,2,0), 10)" + "show((2,0,2,0), 11)" ] }, { @@ -1799,35 +1711,12 @@ " 7 = 2+(0.2^-1)\n", " 8 = 2^(02+1)\n", " 9 = (20/2)-1\n", - " 10 = 20/(2*1)\n", - " 11 = (20/2)+1\n", - " 12 = 2*(02+1)!\n", - " 13 = (2*(0!+2)!)+1\n", - " 14 = 20-(2+1)!\n", - " 15 = 20-(.2^-1)\n", - " 16 = 20*(-.2+1)\n", - " 17 = 20-(2+1)\n", - " 18 = 20-(2*1)\n", - " 19 = -2+021\n", - " 20 = 20*(2-1)\n", - " 21 = (2*0)+21\n", - " 22 = 20+(2*1)\n", - " 23 = 2+021\n", - " 24 = 20*(.2+1)\n", - " 25 = (2*02)!+1\n", - " 26 = 20+(2+1)!\n", - " 27 = (2+0!)!+21\n", - " 28 = -2+((0!+2)/.1)\n", - " 29 = ((2+0!)!/.2)-1\n", - " 30 = ((2^0)+2)/.1\n", - " 31 = (2^(0!/.2))-1\n", - " 32 = 2^(0.2^-1)\n", - " 33 = (2^(0!/.2))+1\n" + " 10 = 20/(2*1)\n" ] } ], "source": [ - "show((2,0,2,1), 10)" + "show((2,0,2,1), 11)" ] }, { @@ -1851,34 +1740,12 @@ " 7 = 2+(0!+(2*2))\n", " 8 = 2*(02*2)\n", " 9 = (20-2)/2\n", - " 10 = 20-(2/.2)\n", - " 11 = (20+2)/2\n", - " 12 = (20/2)+2\n", - " 13 = 2+(0!+(2/.2))\n", - " 14 = 2*((0!/.2)+2)\n", - " 15 = ((2^0)+2)/.2\n", - " 16 = 20-(2*2)\n", - " 17 = 2+((0!+2)/.2)\n", - " 18 = 20-√(2*2)\n", - " 19 = 20-(2/2)\n", - " 20 = -2+022\n", - " 21 = 20+(2/2)\n", - " 22 = (2*0)+22\n", - " 23 = (2^0)+22\n", - " 24 = 2+022\n", - " 25 = 2+(0!+22)\n", - " 26 = 2+(02*2)!\n", - " 27 = 2+(0.2^-2)\n", - " 28 = (2+0!)!+22\n", - " 29 = (.2^-0!)+(2*2)!\n", - " 30 = 20+(2/.2)\n", - " 31 = (2+0!)!+(.2^-2)\n", - " 32 = √2^(02/.2)\n" + " 10 = 20-(2/.2)\n" ] } ], "source": [ - "show((2,0,2,2), 10)" + "show((2,0,2,2), 11)" ] }, { @@ -1929,7 +1796,7 @@ "source": [ "# The 24 Problem\n", "\n", - "In the [538 Riddler for July 10th 2020](https://fivethirtyeight.com/features/can-you-make-24/), Zach Wissner-Gross asks \"Can you make 24?\" from the digits (2, 3, 3, 4), in any order, with just the five binary operators. For extra credit, Zach asks for multiple ways to make 24.\n", + "In the [538 Riddler for July 10th 2020](https://fivethirtyeight.com/features/can-you-make-24/), Zach Wissner-Gross asks \"Can you make 24?\" from the digits (2, 3, 3, 4), in any order, with just the five binary operators. For extra credit, Zach asks for multiple ways to make 24. Readers sent in suggestions for other sets of four digits with which to make 24.\n", "\n", "We haven't dealt with reporting multiple ways, and we haven't allowed different orders for the digits. I'll deal with both by trying all permutations of the digits, and collecting one expression from each permutation (if there is one). If there are multiple ways with a single permutation we won't get more than one of those, but this approach should be good enough to answer the question." ] @@ -1964,18 +1831,173 @@ "can_make(24, (2, 3, 3, 4), '+-*/^')" ] }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'((3^2)+(8+8))', '(8+((3^2)+8))', '(8+(8+(3^2)))'}" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "can_make(25, (2, 3, 8, 8), '+-*/^')" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'(((10-3)*2)+10)',\n", + " '((2*(10-3))+10)',\n", + " '((2^10)-(10^3))',\n", + " '(10+((10-3)*2))',\n", + " '(10+(2*(10-3)))',\n", + " '(10-((3-10)*2))',\n", + " '(10-(2*(3-10)))'}" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "can_make(24, (2, 3, 10, 10), '+-*/^')" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'(8/(3-(8/3)))'}" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "can_make(24, (3, 3, 8, 8), '+-*/^')" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'(((3*6)-6)*2)',\n", + " '(((3+2)*6)-6)',\n", + " '(((3+6)*2)+6)',\n", + " '(((6+3)*2)+6)',\n", + " '((2*(3+6))+6)',\n", + " '((2*(6+3))+6)',\n", + " '((2+6)*(6-3))',\n", + " '(6*(6*(2/3)))',\n", + " '(6+((3+6)*2))',\n", + " '(6+((6+3)*2))',\n", + " '(6+(2*(3+6)))',\n", + " '(6+(2*(6+3)))'}" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "can_make(24, (2, 3, 6, 6), '+-*/^')" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "set()" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "can_make(24, (0, 0, 2, 5), '+-*/^')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "I didn't get an answer for that one. I can allow factorial:" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'(((2*0)-0!)+5)!',\n", + " '((0*2)+(5-0!)!)',\n", + " '((0-(2^0))+5)!',\n", + " '((0-0!)+(5^2))',\n", + " '((2*0)+(5-0!)!)',\n", + " '((5-0!)!+(0*2))',\n", + " '((5^(0+2))-0!)',\n", + " '((5^2)+(0-0!))',\n", + " '(0+((0!-2)+5)!)',\n", + " '(0+((5^2)-0!))',\n", + " '(0+(5+(0!-2))!)',\n", + " '(2*((5^0)+0!))!'}" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "can_make(24, (0, 0, 2, 5), '+-*/^!')" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Even More Fours: The Power of Floor and Ceiling\n", "\n", - "With the standard set of `OPS`, we got all the integers up to 72 with four 4s. If we add the floor and ceiling operators, we get a big jump: suddenly, all the results of a division or a square root that didn't form an integer and hence didn't contribute to the output of `show`, can now be coerced into integers. Instead of stopping at 72, we get all the way up to 1644:" + "With the standard set of `OPS`, we got all the integers up to 72 with four 4s. If we add the floor and ceiling operators, we get a big jump: suddenly, all the results of a division or a square root that didn't form an integer can now be coerced into integers. Instead of getting the integers only up to 72, we now get all the way up to 1644 (although it takes three times as long to get there):" ] }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 52, "metadata": {}, "outputs": [ { @@ -2054,7 +2076,7 @@ " 67 = 4!+(44-⌈.4⌉)\n", " 68 = 4+(4*(4*4))\n", " 69 = 4!+⌈44.4⌉\n", - " 70 = 4!+(√4+44)\n", + " 70 = √4+(4!+44)\n", " 71 = ⌈(.4*(4*44))⌉\n", " 72 = 4+(4!+44)\n", " 73 = 4+⌊(44/√.4)⌋\n", @@ -2192,7 +2214,7 @@ " 205 = ⌈((.4+.4)*(4^4))⌉\n", " 206 = ⌊(44^√√4)⌋-4\n", " 207 = ⌊(4.4^(4-.4))⌋\n", - " 208 = 4*(4+(4!+4!))\n", + " 208 = 4*(4+(√4*4!))\n", " 209 = ⌊((4-√.4)^4.4)⌋\n", " 210 = ⌊(√44^√(4+4))⌋\n", " 211 = ⌊(√4!*44)⌋-4\n", @@ -2266,7 +2288,7 @@ " 279 = ⌈(4*(44/√.4))⌉\n", " 280 = ⌊(√.4*444)⌋\n", " 281 = ⌈(√.4*444)⌉\n", - " 282 = 4!+(√4+(4^4))\n", + " 282 = √4+(4!+(4^4))\n", " 283 = ⌈((4+(.4/4))^4)⌉\n", " 284 = 4+(4!+(4^4))\n", " 285 = ⌈((4^4)/(√4!-4))⌉\n", @@ -2289,7 +2311,7 @@ " 302 = ⌈((4+(4/4!))^4)⌉\n", " 303 = ⌈(.4^(.4-√44))⌉\n", " 304 = 4!+(4!+(4^4))\n", - " 305 = ⌈(44*√(4!+4!))⌉\n", + " 305 = ⌈(44*√(√4*4!))⌉\n", " 306 = ⌊(4^(4*(.4+√.4)))⌋\n", " 307 = ⌈(4^(4*(.4+√.4)))⌉\n", " 308 = 44*⌈√44⌉\n", @@ -2400,7 +2422,7 @@ " 413 = ⌈(.4^-√44)⌉-4!\n", " 414 = 4+⌈((.4-√4!)^4)⌉\n", " 415 = ⌊(44/(√.4^√4!))⌋\n", - " 416 = 4*(4*(4!+√4))\n", + " 416 = 4*(4*(√4+4!))\n", " 417 = ⌈(4!*(4!-√44))⌉\n", " 418 = ⌈(4^((4^.4)/.4))⌉\n", " 419 = ⌊(((.4-4)^4)/.4)⌋\n", @@ -2534,7 +2556,7 @@ " 547 = 4+⌈(4!*(4!-√√4))⌉\n", " 548 = (4!*4!)-(4+4!)\n", " 549 = ⌈(4*(√4!*(4+4!)))⌉\n", - " 550 = (4!*4!)-(4!+√4)\n", + " 550 = (4!*4!)-(√4+4!)\n", " 551 = (4!*4!)-(⌈.4⌉+4!)\n", " 552 = 4!*(4!-(4/4))\n", " 553 = ⌈((.4-4!)^√4)⌉-4\n", @@ -2586,7 +2608,7 @@ " 599 = 4+⌊((.4+4!)^√4)⌋\n", " 600 = 4!/(.44-.4)\n", " 601 = (⌈4.4⌉^4)-4!\n", - " 602 = 4!+(√4+(4!*4!))\n", + " 602 = √4+(4!+(4!*4!))\n", " 603 = ⌊((4!+(4^-.4))^√4)⌋\n", " 604 = 4+(4!+(4!*4!))\n", " 605 = ⌈((4-.4)^⌈4.4⌉)⌉\n", @@ -2606,7 +2628,7 @@ " 619 = 4+⌊(4^(4+√.4))⌋\n", " 620 = 44+(4!*4!)\n", " 621 = (⌈4.4⌉^4)-4\n", - " 622 = (4!*(4!+√4))-√4\n", + " 622 = (4!*(√4+4!))-√4\n", " 623 = (⌈4.4⌉^4)-√4\n", " 624 = 4!*⌊(4*√44)⌋\n", " 625 = ⌈4.44⌉^4\n", @@ -2636,7 +2658,7 @@ " 649 = 4!+(⌈4.4⌉^4)\n", " 650 = (4+(4^4))/.4\n", " 651 = ⌊(.4^(√(4+4)/-.4))⌋\n", - " 652 = ((4!+√4)^√4)-4!\n", + " 652 = ((√4+4!)^√4)-4!\n", " 653 = ⌈((√4!+(4^4))/.4)⌉\n", " 654 = ⌊((4!-√4)^√4.4)⌋\n", " 655 = ⌊((4*√(.4*4))^4)⌋\n", @@ -2663,8 +2685,8 @@ " 676 = (4+√4)!-44\n", " 677 = ⌊(4.4^4.4)⌋\n", " 678 = ⌈(4.4^4.4)⌉\n", - " 679 = ⌊(4^((4!+4!)^.4))⌋\n", - " 680 = 4+((4!+√4)^√4)\n", + " 679 = ⌊(4^((√4*4!)^.4))⌋\n", + " 680 = 4+((√4+4!)^√4)\n", " 681 = ⌊(4!*(4!+4.4))⌋\n", " 682 = ⌈(4!*(4!+4.4))⌉\n", " 683 = ⌈(4^(4+√(√4/4)))⌉\n", @@ -2678,7 +2700,7 @@ " 691 = ⌊((4!-√√4)^√4.4)⌋\n", " 692 = (4+√4)!-(4+4!)\n", " 693 = ⌈((4-(.4/√4))^√4!)⌉\n", - " 694 = (4+√4)!-(4!+√4)\n", + " 694 = (4+√4)!-(√4+4!)\n", " 695 = (4+√4)!-(⌈.4⌉+4!)\n", " 696 = ((4/.4)-4)!-4!\n", " 697 = ⌈((.4*(4^4))^√√4)⌉\n", @@ -2899,8 +2921,8 @@ " 912 = ⌊((4^4)*(4!^.4))⌋\n", " 913 = ⌈((4^4)*(4!^.4))⌉\n", " 914 = ⌈(4!/(.4^4))⌉-4!\n", - " 915 = ⌊(((4!-√4)/4)^4)⌋\n", - " 916 = ⌈(((4!-√4)/4)^4)⌉\n", + " 915 = ⌊(((√4-4!)/4)^4)⌋\n", + " 916 = ⌈(((√4-4!)/4)^4)⌉\n", " 917 = ⌈(((4+√4)^4)/√√4)⌉\n", " 918 = 4+(4!+⌊(4^√4!)⌋)\n", " 919 = 4+(4!+⌈(4^√4!)⌉)\n", @@ -2969,7 +2991,7 @@ " 982 = ⌊((4+(.4/√4!))^√4!)⌋\n", " 983 = ⌊((4+(.4*4))^4)⌋\n", " 984 = ⌈((4+(.4*4))^4)⌉\n", - " 985 = ⌊(4!*(√4+(.4^-4)))⌋\n", + " 985 = ⌊(√4*(4^√(4!-4)))⌋\n", " 986 = (4*4!)+⌊(4^√4!)⌋\n", " 987 = (4*4!)+⌈(4^√4!)⌉\n", " 988 = ⌊((⌈4.4⌉^4)/√.4)⌋\n", @@ -2998,8 +3020,8 @@ "1011 = ⌊(4*(4!^(4^.4)))⌋\n", "1012 = 44*(4!-⌈.4⌉)\n", "1013 = ⌊(4!^(⌈√44⌉^.4))⌋\n", - "1014 = (4!+√4)*⌊(.4^-4)⌋\n", - "1015 = ⌊((4!+√4)/(.4^4))⌋\n", + "1014 = (√4+4!)*⌊(.4^-4)⌋\n", + "1015 = ⌊((√4+4!)/(.4^4))⌋\n", "1016 = 4*((4^4)-√4)\n", "1017 = ⌈(((4!-√√4)/4)^4)⌉\n", "1018 = ⌊(4*((4^4)-√√4))⌋\n", @@ -3107,7 +3129,7 @@ "1120 = 4*(4!+(4^4))\n", "1121 = ⌈((4+(.4^-√.4))^4)⌉\n", "1122 = ⌈(4^(√4!+(4/4!)))⌉\n", - "1123 = ⌈((4!+4!)^(.4+√√4))⌉\n", + "1123 = ⌈((√4*4!)^(.4+√√4))⌉\n", "1124 = ⌊(√(.4*44)^√4!)⌋\n", "1125 = ⌈(√(.4*44)^√4!)⌉\n", "1126 = ⌊(4.4*(4^4))⌋\n", @@ -3117,7 +3139,7 @@ "1130 = ⌊((4-√(4*4!))^4)⌋\n", "1131 = ⌈((4-√(4*4!))^4)⌉\n", "1132 = √4*⌊(4!*(4!-.4))⌋\n", - "1133 = ⌈(4!*(√4*(4!-.4)))⌉\n", + "1133 = ⌈(√4*(4!*(4!-.4)))⌉\n", "1134 = √4*⌈(4!*(4!-.4))⌉\n", "1135 = ⌈((4+√4)!/√.4)⌉-4\n", "1136 = ⌊(√4!*((4^4)-4!))⌋\n", @@ -3128,20 +3150,20 @@ "1141 = ⌈(4!^(4-(.4^-√.4)))⌉\n", "1142 = ⌊((√√4+4.4)^4)⌋\n", "1143 = ⌈((√√4+4.4)^4)⌉\n", - "1144 = 44*(4!+√4)\n", + "1144 = 44*(√4+4!)\n", "1145 = ⌈((4^4)*√(4!-4))⌉\n", "1146 = (4^4)+⌊(4^√4!)⌋\n", "1147 = (4^4)+⌈(4^√4!)⌉\n", - "1148 = (4!*(4!+4!))-4\n", + "1148 = (√4*(4!*4!))-4\n", "1149 = ⌈(4!^(4^(4^-.4)))⌉\n", - "1150 = (4!*(4!+4!))-√4\n", + "1150 = (√4*(4!*4!))-√4\n", "1151 = ⌊(((4+√.4)^4)/.4)⌋\n", "1152 = 4!*(4+44)\n", - "1153 = ⌈.4⌉+(4!*(4!+4!))\n", - "1154 = √4+(4!*(4!+4!))\n", + "1153 = ⌈.4⌉+(√4*(4!*4!))\n", + "1154 = √4+(√4*(4!*4!))\n", "1155 = ⌈(4*(√4!^(4!^.4)))⌉\n", - "1156 = 4+(4!*(4!+4!))\n", - "1157 = ⌈(√4!+(4!*(4!+4!)))⌉\n", + "1156 = 4+(√4*(4!*4!))\n", + "1157 = ⌈(√4!+(√4*(4!*4!)))⌉\n", "1158 = ⌊(√4!^4.44)⌋\n", "1159 = ⌈(√4!^4.44)⌉\n", "1160 = √4*(4+(4!*4!))\n", @@ -3154,8 +3176,8 @@ "1167 = ⌊(4^(√(4/.4)^√√4))⌋\n", "1168 = 4*⌈(4!^(.4^-√.4))⌉\n", "1169 = ⌈(⌈(4!+√4!)⌉^√4.4)⌉\n", - "1170 = ⌊(4^√(4!+√4))⌋-4\n", - "1171 = ⌈(4^√(4!+√4))⌉-4\n", + "1170 = ⌊(4^√(√4+4!))⌋-4\n", + "1171 = ⌈(4^√(√4+4!))⌉-4\n", "1172 = ⌈((.4-(.4^-√4))^4)⌉\n", "1173 = ⌊(4!*(√4!+44))⌋\n", "1174 = ⌈(4!*(√4!+44))⌉\n", @@ -3163,7 +3185,7 @@ "1176 = 4!*⌈(√4!+44)⌉\n", "1177 = ⌊(4^((4/.4)-√4!))⌋\n", "1178 = ⌈(4^((4/.4)-√4!))⌉\n", - "1179 = 4+⌈(4^√(4!+√4))⌉\n", + "1179 = 4+⌈(4^√(√4+4!))⌉\n", "1180 = 4*(⌈(4!*√4!)⌉/.4)\n", "1181 = ⌊(4^((4^√√4)-√4))⌋\n", "1182 = ⌈(4^((4^√√4)-√4))⌉\n", @@ -3232,7 +3254,7 @@ "1245 = ⌈(√4!*((4^4)-√4))⌉\n", "1246 = ⌊(((.4+√4!)^4)/√.4)⌋\n", "1247 = ⌊((4!/.4)^(4^.4))⌋\n", - "1248 = 4!*(4+(4!+4!))\n", + "1248 = 4!*(4+(√4*4!))\n", "1249 = ⌊(4^((4!/.4)^.4))⌋\n", "1250 = √4*(⌈4.4⌉^4)\n", "1251 = ⌈(√4!*(4^4))⌉-4\n", @@ -3289,8 +3311,8 @@ "1302 = ⌊(((4^√.4)/.4)^4)⌋\n", "1303 = ⌈(((4^√.4)/.4)^4)⌉\n", "1304 = ⌈(√(4+4)^(√4+√4!))⌉\n", - "1305 = ⌊((4^4)*√(4!+√4))⌋\n", - "1306 = ⌈((4^4)*√(4!+√4))⌉\n", + "1305 = ⌊((4^4)*√(√4+4!))⌋\n", + "1306 = ⌈((4^4)*√(√4+4!))⌉\n", "1307 = ⌈((.4+√√4)*(4+√4)!)⌉\n", "1308 = 4*⌊((4!/.4)^√√4)⌋\n", "1309 = ⌊(4!*(4!/.44))⌋\n", @@ -3413,7 +3435,7 @@ "1426 = ⌈(.4*(4*⌈(4^√4!)⌉))⌉\n", "1427 = ⌊(((4!*4!)-√4!)/.4)⌋\n", "1428 = 4*⌈(.4*(4^√4!))⌉\n", - "1429 = ⌈((.4^-√(4!+4!))/.4)⌉\n", + "1429 = ⌈((.4^-√(√4*4!))/.4)⌉\n", "1430 = ((4!*4!)-4)/.4\n", "1431 = ⌈(4!*((4!/.4)-.4))⌉\n", "1432 = √4*((4+√4)!-4)\n", @@ -3544,7 +3566,7 @@ "1557 = 4!+⌊(4^√(4+4!))⌋\n", "1558 = 4!+⌈(4^√(4+4!))⌉\n", "1559 = ⌊((4+4)^(√√4/.4))⌋\n", - "1560 = 4!*((4!+√4)/.4)\n", + "1560 = 4!*((√4+4!)/.4)\n", "1561 = 4!+⌊(√(4!-4)^√4!)⌋\n", "1562 = ⌊((⌈4.4⌉^4)/.4)⌋\n", "1563 = ⌈((⌈4.4⌉^4)/.4)⌉\n", @@ -3564,8 +3586,8 @@ "1577 = 4+⌊(√4!^(4+√.4))⌋\n", "1578 = 4+⌈(√4!^(4+√.4))⌉\n", "1579 = ⌊((√4!-.4)^√4!)⌋-4\n", - "1580 = ⌊((4^(√4!+√√4))/4)⌋\n", - "1581 = ⌈((4^(√4!+√√4))/4)⌉\n", + "1580 = ⌊((4^(√√4+√4!))/4)⌋\n", + "1581 = ⌈((4^(√√4+√4!))/4)⌉\n", "1582 = ⌈((√4!-.4)^√4!)⌉-√4\n", "1583 = ⌊((√4+√√4)^(4+√4))⌋\n", "1584 = 4!*⌊(4!^(√4^.4))⌋\n", @@ -3576,7 +3598,7 @@ "1589 = ⌊(((4*4!)^√√4)/.4)⌋\n", "1590 = ⌈((4*4!)^√√4)⌉/.4\n", "1591 = ⌈(4!*(4!^(√4^.4)))⌉\n", - "1592 = 4+⌊((√4!+√√4)^4)⌋\n", + "1592 = 4+⌊((√√4+√4!)^4)⌋\n", "1593 = ⌊(.4^-(√√4+√44))⌋\n", "1594 = ⌊(4^(4+(√4^.4)))⌋\n", "1595 = ⌈(4^(4+(√4^.4)))⌉\n", @@ -3629,8 +3651,8 @@ "1642 = ⌈(√4!^(√(4+4!)-√.4))⌉\n", "1643 = ⌊((√.4-⌈√44⌉)^4)⌋\n", "1644 = ⌈((√.4-⌈√44⌉)^4)⌉\n", - "CPU times: user 1min 22s, sys: 192 ms, total: 1min 22s\n", - "Wall time: 1min 23s\n" + "CPU times: user 1min 25s, sys: 512 ms, total: 1min 25s\n", + "Wall time: 1min 26s\n" ] } ], @@ -3644,12 +3666,12 @@ "source": [ "# Even More Fives: Five 5s\n", "\n", - "In the [xkcd forum](http://forums.xkcd.com/viewtopic.php?f=14&t=116813&start=280) they took up the problem of **five 5s** and got all the integers up to 298, using the \"double factorial\" and π functions. We can get up to 171, using just the default operators, but it does take about seven minutes, whereas all the other puzzles (with four or three digits) took less than a minute. I suspect you could go much further using floor and ceiling, but that computation would take even longer, so for now let's stick with our default set of operations:" + "In the [xkcd forum](http://forums.xkcd.com/viewtopic.php?f=14&t=116813&start=280) they took up the problem of **five 5s** and got all the integers up to 298, using the \"double factorial\" and π functions. We can get up to 171, using just the default operators, but with five digits it does take about seven minutes, whereas all the other puzzles with four or three digits (and without floor and ceiling) took less than a minute. I suspect you could go much further using floor and ceiling, but that computation would take even longer, so for now let's stick with our default set of operations:" ] }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 53, "metadata": {}, "outputs": [ { @@ -3695,7 +3717,7 @@ " 34 = (5!+(55-5))/5\n", " 35 = 5+(55-(5*5))\n", " 36 = (5*5)+(55/5)\n", - " 37 = 5+(((5+5)/5)^5)\n", + " 37 = 5+((5.5-5)^-5)\n", " 38 = .5+(5*(5+(.5*5)))\n", " 39 = ((5*5)-5.5)/.5\n", " 40 = 55-(5+(5+5))\n", @@ -3810,7 +3832,7 @@ " 149 = (5!/5)+(5*(5*5))\n", " 150 = 5*(55-(5*5))\n", " 151 = 5!+(55-(5!/5))\n", - " 152 = 5!+(((5+5)/5)^5)\n", + " 152 = 5!+((5.5-5)^-5)\n", " 153 = 5!+(.5*(5!*.55))\n", " 154 = 5+(5+(5!+(5!/5)))\n", " 155 = 5+(5*(5+(5*5)))\n", @@ -3830,8 +3852,8 @@ " 169 = 5!+((5*5)+(5!/5))\n", " 170 = 5!+((5*5)+(5*5))\n", " 171 = (5.5/(.5^5))-5\n", - "CPU times: user 6min 41s, sys: 1.24 s, total: 6min 42s\n", - "Wall time: 6min 44s\n" + "CPU times: user 7min 28s, sys: 1.75 s, total: 7min 30s\n", + "Wall time: 9h 7min 36s\n" ] } ],