This post originated from an RSS feed registered with Python Buzz
by Thomas Guest.
Original Post: 24 Puzzles
Feed Title: Word Aligned: Category Python
Feed URL: http://feeds.feedburner.com/WordAlignedCategoryPython
Feed Description: Dynamic languages in general. Python in particular. The adventures of a space sensitive programmer.
You are given a sequence of four digits, say 1, 2, 3, 4, and your job is to combine them with ordinary arithmetic operations (+, -, ×, and ÷) in any order to make a target number, typically 24. For example, with 1, 2, 3, 4, you can go with ((1+2)+3)×4=24 or with 4×((2×3)×1)=24.
Here’s a solver for such puzzles. It uses itertools to generate possible expressions, fractions to get the arithmetic right, and eval to evaluate expressions. It’s limited to expressions formed from 4 numbers which means I don’t have to programmatically calculate different ways of parenthesising: there are only 5.
# http://blog.plover.com/math/24-puzzle.html
import re
import math
# Use fractions for exact calculations
from fractions import Fraction
# Solve for 4 numbers only!
N = 4
# So these are the only expression templates
# where X is a number and @ is an operation
templates = '''\
((X @ X) @ X) @ X
(X @ (X @ X)) @ X
X @ ((X @ X) @ X)
X @ (X @ (X @ X))
(X @ X) @ (X @ X)'''.splitlines()
import itertools as its
def defrac(s):
return re.compile(r'Fraction\((\d+)\)').sub(r'\1', s)
def evaluate(nums, ops, template):
fracs = ('Fraction(%s)' % n for n in nums)
ops = iter(ops)
expr = ''.join(next(fracs) if c == 'X' else
next(ops) if c == '@' else c
for c in template)
try:
return expr, eval(expr)
except ZeroDivisionError:
return expr, None
def solve(spec, ops):
numbers = re.compile(r'\d+').findall(spec)
assert len(numbers) == N + 1
result = Fraction(numbers.pop())
seqs = its.product(its.permutations(numbers),
its.product(ops, repeat=N-1),
templates)
print(defrac(next((e for e, v in its.starmap(evaluate, seqs)
if v == result),
'Impossible')))
def main():
solve('2,5,6,6 => 17', '+-/*')
solve('3,3,8,8 => 24', '+-/*')
main()