Quantcast
Channel: Planet Python
Viewing all articles
Browse latest Browse all 22463

Thomas Guest: 24 Puzzles

$
0
0

On The Universe of Discourse Mark Dominus discusses the classic 24 Puzzle:

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()


Viewing all articles
Browse latest Browse all 22463

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>