'''
October 2019 Puzzler
10/3/19
You are equipped with two 2's, two 3's, and the ability to combine them using
addition, subtraction, multiplication, division, and exponentiation.
Your job is to create all of the integers from 0 to 36.
You may use any number of parentheses to control the order of operations and
when possible, all four of the numbers must be used to create a given integer.
For example: 11 = 2^3+3, however 11 can be created using all four numbers
and therefore, this solution would not be sufficient.
'''
from __future__ import print_function
from __future__ import division
import itertools as it
class Solution(object):
'''
A Solution is a solution to the puzzler.
'''
def __init__(self, value, equation):
self.value = value #Value is the result of the equation
self.equation = equation #The expression that evaluates to value
self.hash = hash(equation) #An unique integer for the expression
def __repr__(self):
'''
Text representation of a Solution object. For example:
"15 = 3 + (2 + 2) * 3"
'''
return str(self.value) + " = " + self.equation
def __eq__(self, other):
'''
Solutions are equal if the equations give identical hashes.
'''
return other.hash == self.hash
def __ne__(self, other):
return other.hash != self.hash
def __hash__(self):
return self.hash
def __gt__(self, other):
return self.value > other.value
def __lt__(self, other):
return self.value < other.value
##End Solution
def evaluate(equation):
'''
Evaluate equation. If the result is 0 to 36, create a Solution object
and add it to the answer set.
'''
#Test for and ignore errors
try:
result = eval(equation)
resultInt = int(result)
#Test that the result is an integer and is 0 -> 36
if result == resultInt and result in range(0, 37):
beforeLength = len(answers)
a = Solution(resultInt, equation)
answers.add(a)
if len(answers) > beforeLength: #If answers set grew, then this is a
histogram[resultInt] += 1 # another unique solution
except KeyboardInterrupt:
quit()
#We ignore errors, like divide by zero...
except:
pass
def findInSet(value):
'''
Find and return a Solution with the given value as an example of
an equation that gives the value for display below.
'''
for answer in answers:
if answer.value == value:
return answer
############
####Main####
if __name__ == "__main__":
answers = set() #Create a Set of solutions to remove duplicates
histogram = [0 for x in range(37)] #To keep track the number of solutions found
# for each value 0->36
#All possible arrangements of operands
operands = it.permutations('2233')
#All possible arrangements of operators
# less all exponetiation (results too big)
operators =[]
for a in ['+', '-', '*', '/', '**']:
for b in ['+', '-', '*', '/', '**']:
for c in ['+', '-', '*', '/', '**']:
if not (a=="**" and b=="**" and c=="**"):
operators.append([a, b, c])
#Test each of the operand/operator possibilities
for d in operands:
for t in operators:
## Only 4 term equations needed for this one
##
## #Two term equations
## eqn = str(d[0]) + " " + str(t[0]) + " " + str(d[1])
## evaluate(eqn)
##
## #Three term equations
## eqn = str(d[0]) + " " + str(t[0]) + " " + str(d[1]) \
## + " " + str(t[1]) + " " + str(d[2])
## evaluate(eqn)
##
## eqn = "(" + str(d[0]) + " " + str(t[0]) + " " + str(d[1]) + ")" \
## + " " + str(t[1]) + " " + str(d[2])
## evaluate(eqn)
##
## eqn = str(d[0]) + " " + str(t[0]) + " " + "(" + str(d[1]) \
## + " " + str(t[1]) + " " + str(d[2]) + ")"
## evaluate(eqn)
#Four term equations
eqn = str(d[0]) + " " + str(t[0]) + " " + str(d[1]) \
+ " " + str(t[1]) + " " + str(d[2]) \
+ " " + str(t[2]) + " " + str(d[3])
evaluate(eqn)
eqn = "(" + str(d[0]) + " " + str(t[0]) + " " + str(d[1]) \
+ ") " + str(t[1]) + " " + str(d[2]) \
+ " " + str(t[2]) + " " + str(d[3])
evaluate(eqn)
eqn = str(d[0]) + " " + str(t[0]) + " (" + str(d[1]) \
+ " " + str(t[1]) + " " + str(d[2]) \
+ ") " + str(t[2]) + " " + str(d[3])
evaluate(eqn)
eqn = str(d[0]) + " " + str(t[0]) + " " + str(d[1]) \
+ " " + str(t[1]) + " (" + str(d[2]) \
+ " " + str(t[2]) + " " + str(d[3]) + ")"
evaluate(eqn)
eqn = "(" + str(d[0]) + " " + str(t[0]) + " " + str(d[1]) \
+ " " + str(t[1]) + " " + str(d[2]) \
+ ") " + str(t[2]) + " " + str(d[3])
evaluate(eqn)
eqn = str(d[0]) + " " + str(t[0]) + " (" + str(d[1]) \
+ " " + str(t[1]) + " " + str(d[2]) \
+ " " + str(t[2]) + " " + str(d[3]) + ")"
evaluate(eqn)
eqn = "(" + str(d[0]) + " " + str(t[0]) + " " + str(d[1]) \
+ ") " + str(t[1]) + " (" + str(d[2]) \
+ " " + str(t[2]) + " " + str(d[3]) + ")"
evaluate(eqn)
## #Print all solutions found in order by the value
## answers = sorted(answers)
## for answer in answers:
## print(answer)
#Print the results
sum = 0
print("Find solutions using 2, 2, 3, 3 and +, -, *, /, **")
print("with no or one level of parentheses")
print()
print("Num", "\t", "# solns", "\t", "One solution")
for value in range(len(histogram)):
eqn = findInSet(value) #Find one of the eqns that = value
print(value, "\t", histogram[value], "\t\t", eqn)
sum += histogram[value]
print("Total number of solutions: ", len(answers))