偶然看到了一道小学推理题,打算用代码的形式解出来。
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))
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):
question = {
"n1":n1,
"n2":n2,
"answer":answer
}
if not issamestruct(question, *result):
associationinfo = MathGame.getassociationinfo(n1, n2, answer)
if associationinfo:
question["associationinfo"] = associationinfo
result.append(question)
return result
def issamestruct(question, *questionlist):
'''
判断是否同构
输入:
{'n1': 'abc', 'n2': 'acb', 'answer': 'cba'}
{'n1': 'bca', 'n2': 'bac', 'answer': 'acb'}
返回:
True
'''
question1 = question
n1 = question1["n1"]
n2 = question1["n2"]
answer = question1["answer"]
for question2 in questionlist:
_n1 = question2["n1"]
_n2 = question2["n2"]
_answer = question2["answer"]
if _issamestruct(n1, n2, answer, _n1, _n2, _answer) or _issamestruct(n1, n2, answer, _n2, _n1, _answer):
return True
return False
def _issamestruct(n1, n2, answer, _n1, _n2, _answer):
d = {}
tempanswer = ""
for i, v in enumerate(n1):
d[v] = _n1[i]
for i, v in enumerate(n2):
d[v] = _n2[i]
for i, v in enumerate(answer):
tempanswer += d.get(v, "NAN")
return tempanswer == _answer
if __name__ == '__main__':
n1 = "abc"
n2 = "cba"
answer = "bbab"
MathGame.getassociationinfo(n1, n2, answer)
# print(MathGame.findallassociation(3, 3, 3, 3, 4))