偶然看到了一道小學推理題,打算用代碼的形式解出來。
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))