Reputation: 1419
So I wanted to know if it was possible to take 3 numbers from the user all ranging from 1-6 and take 1 more input from the user ranging from 1 - 144 and make a program that takes the first 3 numbers you got and finds a way using addition, subtraction, multiplication, division, roots, and powers to find a way, using the 3 numbers, to get the 4th user input. If you can't get the 4th user input find the closest that you can get to it from the first 3 inputs.Then the program should tell you the operations it used and which numbers it used it on. This is basically recreating the game ThinkFun Math Dice.
For example: If the first 3 numbers the user inuts are 5, 2, and 9 and the 4th number is 86, the program should do 9^2 which is 81 and 81+5 which is 86. In another case if the 3 numbers are 6, 4, and 2 and the the final answer is(4th input)24, the program should do 6*4 -2 or 6*4 +2 or 4^2+6 since these all equal to 26 or 22 and there is no possible solution to get 24.
Upvotes: 0
Views: 239
Reputation: 7740
While btilly's answer is absolutely correct, it is a bit more than what's needed for this problem, at least in python. Using the itertools library and the eval()
function, you can get by with a much shorter and simpler approach. Do note that eval()
and exec()
are considered insecure, since they will execute anything passed, however as a script for personal use it should be fine. Any malicious code would probably trip an exception casting the inputs to ints anyways.
from itertools import permutations
coeffs = list(map(int, input("Coefficents, separated by spaces:\n").split()))
target = int(input("Target value:\n"))
operators = ["({}+{})","({}-{})","({}*{})","({}/{})","({}**{})","({}**(1.0/{}))"]
def make_expr(expr, coeffs, target):
if not coeffs:
try:
return eval(expr), expr
except OverflowError:
return None
except ArithmeticError:
return None
solutions = [make_expr(op.format(expr, coeffs[0]), coeffs[1:], target) for op in operators]
solutions += [make_expr(op.format(coeffs[0], expr), coeffs[1:], target) for op in operators]
solutions = [x for x in solutions if x is not None]
val, expr = min(solutions, key=lambda x: abs(x[0]-target))
return val, expr
def find_best(coeffs, target):
assert(len(coeffs) > 1)
solutions = [make_expr(perm[0], perm[1:], target) for perm in permutations(coeffs)]
solutions = [x for x in solutions if x is not None]
val, expr = min(solutions, key=lambda x: abs(x[0]-target))
return "Closest value: {0}\nExpression: {1}".format(val, expr)
print(find_best(coeffs, target))
To support more operators, just insert them into the list, with {}
's where the arguments go, and surrounded by paretheses. I've added support for extra operators, however since I do not shortcut the iteration when it finds a perfect solution, it can take a very long time for 3+ operators.
Upvotes: 1
Reputation: 46389
The heart of the problem is to decide what format to use to write out the possible calculations, list them, try each one, and select the best.
I'm going to suggest RPN notation because it is simple to work with. I've given you the code to list possible calculations in RPN notation. You still need to do IO and write an RPN calculator. IO is easy. There are lots of examples of RPN calculators online that you can study.
def list_perms (args):
if 0 == len(args):
yield []
else:
x = args[0]
for p in list_perms(args[1:]):
for i in range(0, len(p)+1):
yield p[:i] + [x] + p[i:]
def list_rpn (x, y, z):
ops = ['+', '-', '*', '/', '^', 'r']
for p in list_perms([x, y, z]):
for op1 in ops:
for op2 in ops:
yield p + [op1, op2]
yield p[0:2] + [op1, p[2], op2]
def evaluate (calc):
return 'you have to figure this out'
def find_best (x, y, z, r):
best_val = x+y+z
best_calc = [x, y, z, '+', '+']
for calc in list_rpn(5, 6, 8):
try:
val = evaluate(calc)
if val == r:
return calc
elif abs(val - r) < abs(best_val - r):
best_val = val
best_calc = calc
except Exception:
# Throw exceptions on things like divide by 0, or powers of
# negative numbers that aren't n or 1/n where n is an odd number
pass
return best_calc
# You should also do proper IO here.
print(find_best(5, 2, 9, 24))
Upvotes: 1