小町算(もどき)

W-ZERO3Python Windows CE portを使って書いた。
うろ覚えで書いたらルールが微妙に違ってたけどまあいいや。

# -*- coding: utf-8 -*-

def solve_komachi(answer, *terms):
    for e in iter_komachi(terms):
        try:
            if e() == answer:
                yield e
        except ArithmeticError, e:
            pass

def iter_komachi(terms):
    n = len(terms)
    if n > 0:
        if n == 1:
            yield terms[0]
        else:
            for i in xrange(1, len(terms)):
                lhs = terms[:i]
                rhs = terms[i:]
                for l in iter_komachi(lhs):
                    for r in iter_komachi(rhs):
                        for op in operators:
                            yield expr(op, l, r)

class operator(object):
    def __init__(self, symbol, precedence, exchangeable, func):
        self.symbol       = symbol
        self.precedence   = precedence
        self.exchangeable = exchangeable
        self.func         = func

    def __call__(self, lhs, rhs):
        return self.func(lhs, rhs)

    def __repr__(self):
        return self.symbol

operators = [
    operator('+', 1, True,  lambda lhs, rhs: lhs + rhs),
    operator('-', 1, False, lambda lhs, rhs: lhs - rhs),
    operator('*', 2, True,  lambda lhs, rhs: lhs * rhs),
    operator('/', 2, False, lambda lhs, rhs: float(lhs) / rhs),
]

class expr(object):
    def __init__(self, op, lhs, rhs):
        self.op  = op
        self.lhs = lhs
        self.rhs = rhs

    def eval(self):
        lhs = self.lhs
        rhs = self.rhs
        if callable(lhs): lhs = lhs()
        if callable(rhs): rhs = rhs()
        return self.op(lhs, rhs)

    def __str__(self):
        op  = self.op
        lhs = self.lhs
        if isinstance(lhs, expr) and \
           lhs.op.precedence < op.precedence:
            lhs = "(%s)" % lhs
        rhs = self.rhs
        if isinstance(rhs, expr) and \
           (op.precedence > rhs.op.precedence or \
            ((op.precedence == rhs.op.precedence) and \
             (not op.exchangeable))):
            rhs = "(%s)" % rhs
        return "%s %s %s" % (lhs, op, rhs)

    __call__ = eval

def main(answer, *terms):
    tbl = {}
    for e in solve_komachi(answer, *terms):
        s = "%s = %d" % (e, answer)
        if not tbl.has_key(s):
            print s
            tbl[s] = True

if __name__ == '__main__':
    import sys
    main(*map(int, sys.argv[1:]))

実行例:

$ python komachi.py 10 1 2 3 4
1 + 2 + 3 + 4 = 10
1 * (2 * 3 + 4) = 10
1 * 2 * 3 + 4 = 10