最近了解了下python的itertools模块,感觉挺强大的。写了个简单的24点计算器做练习。思路很简单,对于一个24点的计算过程,一定可以通过调整顺序和加括号表现为4个操作数3个操作符这样的形式。因此只要枚举出加减乘除中所有三个操作符的集合,再和待计算的四个数字混合在一起,将这7个元素全排列就可以得到共120960总可能的序列。最后通过对这个序列按照后缀表达式进行计算,即可找到24点的可行解。代码如下:
# -*- coding: utf-8 -*-
import itertools
import random
# 洗牌
def shuffle(n, m=-1):
if m == -1:m = n
l = range(n)
for i in range(len(l)-1):
x = random.randint(i, len(l)-1)
l[x], l[i] = l[i], l[x]
if i == m-1:break
return [l[idx] for idx in range(n) if idx >= 0 and idx < m]
# 生成4张牌
def Get4Card():
card = [1,2,3,4,5,6,7,8,9,10,10,10,10] * 4
cardidxs = shuffle(52, 4)
return [card[idx] for idx in cardidxs]
def GenAllExpr(card_4, ops_iter):
allexpr = []
try:
while True :
l = list(ops_iter.next()) + card_4
its = itertools.permutations(l, len(l))
try :
while True :
yield its.next()
except StopIteration :
pass
except StopIteration:
pass
def CalcRes(expr, isprint=False):
opmap = {'+':lambda a,b:a+b, '-':lambda a,b:a-b, '*':lambda a,b:a*b,
'/':lambda a,b:a/(b+0.0)}
expr_stack = []
while expr:
t = expr.pop(0)
if type(t) == int : expr_stack.append(t)
else :
if len(expr_stack) < 2 : return False
else :
a = expr_stack.pop()
b = expr_stack.pop()
if isprint:
print a, t, b, '=', opmap[t](a,b)
try:
expr_stack.append(opmap[t](a,b))
except ZeroDivisionError:
return False
return expr_stack[0]
if __name__ == "__main__":
card = Get4Card()
print card
ops = itertools.combinations_with_replacement('+-*/', 3) #一个24点的计算公式可以表达成3个操作符的形式
allexpr = GenAllExpr(card, ops) #数和操作符混合,得到所有可能序列
for expr in allexpr :
res = CalcRes(list(expr))
if res and res == 24 :
CalcRes(list(expr), True) #输出计算过程
print "Success"
break