http://wordplay.blogs.nytimes.com/2015/09/07/24/

The numbers are: 1 3 4 6 ; find 24 The numbers are: 1 1 5 8 ; find 10

Operations: + – × /


In [1]:
from operator import mul, add, sub, truediv
from itertools import product, permutations

ops = [
    [ mul, "{a} x {b}" ],
    [ add, "{a} + {b}" ],
    [ sub, "{a} - {b}" ],
    [ lambda a, b: sub(b, a), "{b} - {a}" ],
    [ truediv, "{a} / {b}" ],
    [ lambda a, b: truediv(b, a), "{b} / {a}" ],
]

# Implement search for all possible combinations with an operand stack (starting with input values in some order)
# and an operator stack. Apply the operators from the stack to the last two values, pushing on the result, until
# there is just one value remaing 

def calc_result(values, ops):
    values = list(values)
    ops = list(ops)
    top_str = str(values[-1])
    while len(values) > 1:
        a = values.pop()
        b = values.pop()
        op = ops.pop()
        try:
            r = op[0](a, b)
            top_str = "({})".format(op[1].format(a=top_str, b=str(b)))
            values.append(r)
        except ZeroDivisionError:
            return None, ""
    return values[0], top_str

# Example use: print "10 = {}".format(find_op([1, 1, 5, 8], 10))
def find_op(values, answer):
    for ordered_values in permutations(values):
        for operations in product(ops, repeat=len(values)-1):
            result, formula = calc_result(ordered_values, operations)
            if result == answer:
                return formula
            if result and abs(result - answer) < .001:
                return "~ {}".format(formula)
    return False

In [2]:
print "10 = {}".format(find_op([1, 1, 5, 8], 10))
print "24 = {}".format(find_op([1, 3, 4, 6], 10))


10 = (8 / (1 - (1 / 5)))
24 = (((4 + 1) x 6) / 3)

In [3]:
values = [1, 3, 4, 6]
for result in range(1,50):
    eq = find_op(values, result)
    if eq:
        print "{} = {}".format(result, eq)
    else:
        print "{}: none".format(result)


1 = (((4 - 6) + 3) x 1)
2 = (((4 / 6) x 3) x 1)
3 = (((4 / 6) x 3) + 1)
4 = (((6 - 4) + 3) - 1)
5 = (((6 - 4) + 3) x 1)
6 = (((6 - 4) x 3) x 1)
7 = (((6 + 4) - 3) x 1)
8 = (((6 x 4) / 3) x 1)
9 = (((6 x 4) / 3) + 1)
10 = (((4 + 1) x 6) / 3)
11 = (((6 - 3) x 4) - 1)
12 = (((6 + 4) + 3) - 1)
13 = (((6 + 4) + 3) x 1)
14 = (((6 + 4) + 3) + 1)
15 = (((6 x 3) - 4) + 1)
16 = (((6 - 3) + 1) x 4)
17 = (((4 x 3) + 6) - 1)
18 = (((4 x 3) + 6) x 1)
19 = (((4 x 3) + 6) + 1)
20 = (((6 x 4) - 3) - 1)
21 = (((6 x 4) - 3) x 1)
22 = (((6 x 4) - 3) + 1)
23 = (((6 x 3) + 4) + 1)
24 = (6 / (1 - (3 / 4)))
25 = (((6 + 1) x 4) - 3)
26 = (((6 x 4) + 3) - 1)
27 = (((6 x 4) + 3) x 1)
28 = (((6 x 4) + 3) + 1)
29 = (((6 + 4) x 3) - 1)
30 = (((6 + 4) x 3) x 1)
31 = (((6 + 4) x 3) + 1)
32 = (((6 + 3) - 1) x 4)
33 = (((6 + 4) + 1) x 3)
34: none
35 = (((6 + 3) x 4) - 1)
36 = (((6 + 3) x 4) x 1)
37 = (((6 + 3) x 4) + 1)
38: none
39: none
40 = (((6 + 3) + 1) x 4)
41 = (((4 + 3) x 6) - 1)
42 = (((4 + 3) x 6) x 1)
43 = (((4 + 3) x 6) + 1)
44: none
45: none
46: none
47: none
48 = (((3 - 1) x 6) x 4)
49: none

In [4]:
print "17 = {}".format(find_op([6, 6, 5, 2], 17))


17 = (((5 / 6) + 2) x 6)

In [7]:
print "0 = {}".format(find_op([1, 5, 2, 3], 0.7))


0 = (1 - ((3 / 2) / 5))

In [ ]: