#相比前一个,相同点是采用了递归运算。
#不同点是: 去掉了分数的要求,由于返回结果是算式,所以无需考虑中间过程的显示友好性
#基本思路就是,把每一个数的计算过程,直接用字符记录下来(完全相同的字符)
#因此,创建了一个类,这个类里一个表示数字,一个表示运算过程
#在这个类里,重载了操作符,加减乘除在函数中看起来和一般的运算一样
#重载的“-”操作符,相当于计算差的绝对值,当然,还是要注意相应的字符也要对应
#发现使用递归的方法,运算式非常好得。相比于直接分解,简单多了。
#废话少说,上代码
import random, easygui, copy, os
global solutions
class cardSuitRecord():
def __init__(self,cards=0,record=0):
self.card = cards
self.record = record
def __add__(self, other):
card = self.card + other.card
record = self.record + " + " + other.record
return cardSuitRecord(card, record)
def __sub__(self, other):
if self.card > other.card:
card = self.card - other.card
record = self.record + " - " + other.record
else:
card = other.card - self.card
record = other.record + " - " + self.record
return cardSuitRecord(card, record)
def __mul__(self, other):
card = self.card * other.card
record = self.record + " * " + other.record
return cardSuitRecord(card, record)
def __truediv__(self, other):
card = self.card / other.card
record = self.record + " / " + other.record
return cardSuitRecord(card, record)
def operations(a,b,oper):
if oper==1:
return a+b
if oper==2:
return a-b
if oper==3:
return a*b
if oper==4:
return a/b
if oper==5:
return b/a
def cal(cardSR,answer):
global solutions
number = len(cardSR)
if number == 1 and abs(cardSR[0].card-answer) < 0.00001:
solutions.add(str(cardSR[0].record)+"\n")
#if abs(eval(cardSR[0].record)-answer) > 0.001: #做一次验算,如果有错误则打印出来
# print(record, " " , str(xxxx), cardSuit[0])
return
for i in range(0,number-1):
for j in range (i+1,number):
childSR = copy.deepcopy(cardSR) #制作拷贝,每2个数会制作一个新拷贝
A = copy.deepcopy(childSR[i]) #第一个数
B = copy.deepcopy(childSR[j]) #第二个数
childSR.pop(i) #去掉A。这里用pop比remove要快,pop不需要比较
childSR.pop(j-1) #注意,前面去掉第i个元素后,后面的元素都前移,所以j要减一
for k in range(1,6):
copychildSR = copy.deepcopy(childSR) #制作数列拷贝,每个操作再制造一个新拷贝
if abs(A.card) < 0.00001 and k==5:
continue
if abs(B.card) < 0.00001 and k==4:
continue
C = operations(A,B,k) #计算A和B的和差积商,得到C
if number>2:
C.record = "(" + str(C.record) + ")"
copychildSR.append(C) #C代替了AB,与刚才剩余的项组成下一轮的输入
cal(copychildSR, answer) #下一轮
#############################################################################################
# #
# 主程序 #
# #
#############################################################################################
if __name__ == '__main__':
cardSuit = [] #最终使用的牌组,以分数形式存储
solutions = set() #解答
inputCards=[] #输入的字符型牌组,最初是自动随机生成,用户可以修改
numberSolutions =0 #解的数量
cardSR_A = []
#-------------------------------输入选择游戏类型-------------------------------
softAbout = ' 计算24点的扩展程序。\n' \
' 本程序根据用户输入或随机生成的数串计算得到指定结果(例如24)\n'\
' 您可以自己指定几个数,指定希望结果。\n 本程序将给出所有可能的计算方法。'
easygui.msgbox(msg=softAbout, title = "软件说明")
gameTypeSelection = ['4', '24', '1', '13'] #默认的是24点游戏,4张牌,每张限制1~13之间
inputIllegal = True
while inputIllegal:
gameTypeSelection = easygui.multenterbox(msg = '请选择游戏类型,不改动即为普通的24点游戏。', \
title = '游戏类型选择', \
fields = ['数字个数','目标值(例如24)','数字最小限制','数字最大限制'], \
values=gameTypeSelection)
if gameTypeSelection is None:
os._exit(0)
inputIllegal = False
for item in list(gameTypeSelection):
if item == '' or not item.isdigit():
inputIllegal = True
numberNum = int(gameTypeSelection[0])
answerTarget = int(gameTypeSelection[1])
numberMin = int(gameTypeSelection[2])
numberMax = int(gameTypeSelection[3])
#-------------------------------准备阶段,输入4个数-------------------------------
for i in range(0,numberNum):
inputCards.append(str(random.randint(numberMin,numberMax)))
msgFields = []
for i in range(0,numberNum):
msgFields.append("数字" + str(i))
inputIllegal = True
while inputIllegal:
inputCards = easygui.multenterbox(msg = '计算'+str(answerTarget)+'点游戏\n本程序自动计算'+str(answerTarget)+'点\n请输入'+str(numberNum)+'个数字\n(也可不修改随机生成的数字)', \
title = '计算'+str(answerTarget)+'点', \
fields = msgFields, \
values = inputCards)
if inputCards is None:
os._exit_(0)
inputIllegal = False
for item in list(inputCards):
if item == '' or not item.isdigit() or int(item) < numberMin or int(item)>numberMax:
inputIllegal = True
cardSuit = list(map(int, inputCards))
cardSuit.sort(reverse=True)
for i in range(0,numberNum):
cardSR_A.append(cardSuitRecord(cardSuit[i],str(cardSuit[i])))
#--------------------------最核心的只有一行--------------------
cal(cardSR_A,answerTarget)
#--------------------------显示答案---------------------------------
numberSolutions = len(solutions)
msgmsg = "牌组" + str(cardSuit)+ "计算"+str(answerTarget)+"共有"+str(numberSolutions)+"种答案"
msgtitle = inputCards
easygui.codebox(msg=msgmsg,title=msgtitle, text=solutions)