A challenge from the Mensa Puzzle Calendar

Mark McEahern marklists at mceahern.com
Thu Oct 3 16:04:49 EDT 2002


> I wrote (IMHO) a very nice piece of python code to solve this for me,
> and then generalized it a bit: What if the first digit (7) is not
> given?  How many unique solutions do we get and what are they? (I
> included those numbers that started with 0 for consistency.)
> 
> I'm a puzzle kind of guy, so I thought some of you might be, too.
> I'd be very curious to see the kind of solutions people come up with.
> My solution ended up being a total of 19 lines of code, including a
> print statement to give me a nice formatted output for each solution,
> resembling the initial problem from the calendar.
> 
> OK, folks.  The gauntlet is down.  Have at it!
> 
> (NOTE: I realize this is not really a Python thingy, but more of an
> algorithm design thingy, but nonetheless, fun.)

Nice puzzle.  This is my first stab.  It could easily be more general.

#!/usr/bin/env python

"""

In the following multiplication statement, all digits 0-9 are used and
are represented with X:

     7XX
      XX
   -----
   XXXXX

Solutions:  try all possible combinations?  Think of it as a string like
this:

  7XXXXXXXXX

You then have a function:

def solve_equation(equation, string):
    ...

"""

from __future__ import generators

def solve_equation(equation, x, replace="X", replacewith="123456890"):
    # There are hints here of how to generalize this further.
    # To generalize, don't assume first digit is the one we don't fiddle.
    supplied_digit = x[0]
    # seq = x[1:]
    # assert len(seq) == len(replacewith)
    for i in permIter(replacewith):
        p = str(supplied_digit) + str(i)
        if eval(equation):
            yield p

def permIter(seq):
    """Given some sequence 'seq', returns an iterator that gives
    all permutations of that sequence.

    Source: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/105962

    """
    ## Base case
    if len(seq) == 1:
        yield(seq[0])
        raise StopIteration

    ## Inductive case
    for i in range(len(seq)):
        element_slice = seq[i:i+1]
        rest_iter = permIter(seq[:i] + seq[i+1:])
        for rest in rest_iter:
            yield(element_slice + rest)
    raise StopIteration


a = "7XX"
b = "XX"
c = "XXXXX"

equation = "int(p[0:3]) * int(p[3:5]) == int(p[5:10])"

for p in solve_equation(equation, a+b+c):
    print p




More information about the Python-list mailing list