一道小學推理題

 偶然看到了一道小學推理題,打算用代碼的形式解出來。

from collections import defaultdict
from copy import deepcopy
import itertools

class MathGame:

    def __init__(self, calcinfo, n1, n2, answer, cards="abcdefghijklmn"):
        self.n1 = n1
        self.n2 = n2
        self.answer = answer
        self.cards = cards
        self.calcinfo = MathGame.initcalcinfo(calcinfo, n1, n2, answer)

    @staticmethod
    def initcalcinfo(calcinfo, n1, n2, answer):
        '''
            初始化係數
            輸入:
                n1 = "abc"
                n2 = "cba"
                answer = "bbcb"
            由:
                abc: a * 100 + b * 10 + c
                cba: c * 100 + b * 10 + a
                bbcb: b * 1000 + b * 100 + c * 10 + b
            得:
                101*c -1081*b + 91*a = 0
            返回:
                {'c': 101, 'b': -1081, 'a': 91}
        '''
        for i in range(1, len(n1)+1):
            calcinfo[n1[-i]] += (10**(i-1))
        for i in range(1, len(n2)+1):
            calcinfo[n2[-i]] += (10**(i-1))
        for i in range(1, len(answer)+1):
            calcinfo[answer[-i]] -= (10**(i-1))
        print(calcinfo)
        return calcinfo

    def calc(self):
        return MathGame._calc(self.calcinfo)
    
    @staticmethod
    def _calc(calcinfo, preinfo={}):
        '''
            解方程,遞歸遍歷所有可能性組合
            輸入:
                {'c': 101, 'b': -1081, 'a': 91}
            由:
                101*c -1081*b + 91*a = 0
            得:
                {'a': a, 'b': b, 'c': c}
            返回:
                {'a': 3, 'b': 1, 'c': 8}
        '''
        _calcinfo = deepcopy(calcinfo)
        calctuple = _calcinfo.popitem()
        result = {}
        for i in range(1, 10):
            preinfo[calctuple[0]] = (calctuple[1], i)
            if _calcinfo:
                result.update(MathGame._calc(_calcinfo, preinfo))
            if sum(map(lambda t:t[0]*t[1], preinfo.values())) == 0:
                result.update(list(map(lambda t:(t[0],t[1][1]),preinfo.items())))
        return result

    @staticmethod
    def getassociationinfo(n1, n2, answer):
        '''
            遊戲的解
            輸入:
                n1 = "abc"
                n2 = "cba"
                answer = "bbcb"
            返回:
                {'a': 3, 'b': 1, 'c': 8}
        '''
        calcinfo = defaultdict(lambda : 0)
        calcinfo = MathGame.initcalcinfo(calcinfo, n1, n2, answer)
        return MathGame._calc(calcinfo)

    @staticmethod
    def permutations(n_class=3, n_length=3, cards="abcdefghijklmn"):
        '''
            獲取所有排列
            輸入:
                n_class:卡片種類
                n_length:排列長度
                cards:自定義卡片標籤
            返回:
                生成器
        '''
        b = cards[:n_class]
        restcombinations = itertools.product(b,repeat=n_length-n_class)
        for i in restcombinations:
            permutation = b + "".join(i)
            for j in itertools.permutations(permutation, n_length):
                yield "".join(j)

    @staticmethod
    def product(cards, n_length):
        '''
            笛卡爾積
            輸入:
                s:自定義卡片
                n_length:長度
            返回:
                生成器
        '''
        for n in itertools.product(cards, repeat=n_length):
            yield "".join(n)

    @staticmethod
    def findallassociation(n1_class=3, n1_length=3, n2_length=3, n2_class=3, answer_length=4):
        '''
            找到所有組合
            輸入:
                n1_class:第一行數字的排列種類
                n1_length:第一行數字的排列長度
                n2_class:第二行數字的排列種類
                n2_length:第二行數字的排列長度
                answer_length:答案的排列長度
            返回:
                [
                    {'n1': 'abc', 'n2': 'acb', 'answer': 'bcaa', 'associationinfo': {'a': 9, 'b': 1, 'c': 8}},
                    {'n1': 'abc', 'n2': 'acb', 'answer': 'cbaa', 'associationinfo': {'a': 9, 'b': 8, 'c': 1}},
                    ...
                ]
        '''
        result = []
        for n1 in MathGame.permutations(n1_class, n1_length):
            for n2 in MathGame.permutations(n2_class, n2_length):
                s = "".join((set(list(n1+n2))))
                for answer in MathGame.product(s, answer_length):
                    associationinfo = MathGame.getassociationinfo(n1, n2, answer)
                    if associationinfo:
                        result.append({
                            "n1":n1,
                            "n2":n2,
                            "answer":answer,
                            "associationinfo":associationinfo
                        })
        return result

if __name__ == '__main__':
    n1 = "abc"  
    n2 = "cba"  
    answer  = "bbab"
    print(MathGame.getassociationinfo(n1, n2, answer))
    # print(MathGame.findallassociation(3, 3, 3, 3, 4))

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章