24点小游戏,抽象成函数就是,输入4个数a b c d,然后输出一个表达式,使得这个表达式的值为24。
考虑到运算符有5个+-*/^,可以放置运算符的位置有3个,则总共有 A 5 3 = 60 A_5^3=60 A53=60种排列方案。
所以,先来一个顺着算的24点
from itertools import product
Op={
'+': lambda a,b : a+b,
'-': lambda a,b : a-b,
'*': lambda a,b : a*b,
'/': lambda a,b : a/b,
'^': lambda a,b : a**b
}
ops = list(Op.keys())
def game24(a,b,c,d):
for o in product(ops,ops,ops):
try: #防止除零错误
val = Op[o[0]](a,b)
val = Op[o[1]](val,c)
val = Op[o[2]](val,d)
except:
continue
if val==24:
return o
return None
测试一下
>>> game24(1,2,3,4)
('+', '+', '*')
>>> game24(1,3,3,4)
('*', '+', '*')
>>> game24(1,3,3,12)
('+', '*', '+')
由于是顺着算的,所以其表达式为
( 1 + 2 + 3 ) × 4 = 24 ( 1 × 3 + 3 ) × 4 = 24 ( 1 + 2 ) × 3 + 12 = 24 (1+2+3)times4=24\ (1times3+3)times4=24\ (1+2)times3+12=24\ (1+2+3)×4=24(1×3+3)×4=24(1+2)×3+12=24
但顺着算终究不太方便,例如下面这种调个顺序就不出结果了
game24(4,3,3,1)
所以接下来为计算添加一括号,添加括号的本质是调整运算次序。比如 a + ( b + c ) + c a+(b+c)+c a+(b+c)+c,其实就是先计算b和c,然后再计算其他部分。由于只有4个元素,所以直接穷举出来也不复杂,4个元素中加入一个括号,则变成三个元素;三个元素再加入一个括号,变成两个元素,接下来就不必加括号了。
这个过程比较复杂,所以先写一个用于测试的小程序,如果输入的4个值可以通过四则混合运算得到24,则输出1,否则输出0。
# 输入为一个列表
def game24(lst):
N = len(lst)-1
for i, op in product(range(N),ops):
try: val = Op[op](*lst[i:i+2])
except: continue
if N > 1:
newLst = lst[:i]+[val]+lst[i+2:]
game24(newLst)
elif val==24:
print("you won",end=" ")
测试一下,结果为
>>> lst = [1,2,3,4] >>> game24(lst) you won you won you won you won you won you won you won you won
是不是感觉都要赢麻了,这是因为1,2,3,4存在多种组合方式完成24点。接下来就是修改这个程序,把赢的方法输出。
由于这个程序是递归式的,所以需要一个参数在递归中不断传递,这个参数的内容为括号的位置和括号中的运算符。
# 输入为一个列表
def game24(lst,para=[]):
N = len(lst)-1
for i, op in product(range(N),ops):
try: val = Op[op](*lst[i:i+2])
except: continue
newPara = para + [i,op]+lst[i:i+2]
newLst = lst[:i]+[val]+lst[i+2:]
if N > 1: game24(newLst, newPara)
elif val==24: print(newPara)
此时,输出的方法大致为
[0, '+', 1, 2, 0, '+', 3, 3, 0, '*', 6, 4]
当然这个段是我自己分的,为了便于理解。第一步计算的是1+2=3;第二步是3+3=6;第三步是6*4。



