当前位置:   article > 正文

python 实现经典24点_python 24点算法

python 24点算法

一,概述

24点:任意给定四个整数,用加、减、乘、除以及适当的括号连接,无论顺序,使计算结果为24,也可能根本就无解。如何用程序简单实现找到算式是程序初学者关注的问题,百度上可以搜到许多这样的文章,有递归法、回溯法、穷举法。但穷举法最为简单、易于理解。

二,算法

穷举法就是把四个数字的所有运算式进行尝试计算,要设法把所有排列一点不差地穷举出,

一、是四个整数位置的排列,用0,1,2,3表示位置,排列是不能重复的,所以有P(4,4)种情况,即4!=4*3*2*1=24种;

二、是三个运算符的变化,每个运算符为+-*/ ,可以相同,所以,有4*4*4=64种;

三、三个运算符的优先级,就是括号位置的变化,可能性为P(3,3)-1=6-1=5种;

所以,表达式的可能性为:24*64*5=7680种

首先,对第一点进行说明,当用户输入的数值穿在重复值时,实际的有效数值组合是少于24的,如输入为6\6\6\6(即四个数值相同)则对于这种情况,只有一种数值组合顺序;如输入为6\6\6\1(即三个数值相同),则对于这种情况,只有4种数值组合顺序,...在python的语法体系中,set()函数可以很方便的排除重复项,因此,可以先采用穷举法给出所有的数值顺序可能,再用set()函数排除重复项,而在本文中,设置的程序数据格式为集合类型

其次,针对第三点,运算符有优先级,一般是用括号表示。我们可以规定运算符的优先级来代替括号。设四个数字为a、b、c、d,运算符为①、②、③,表达式为a ① b ② c ③ d。 这3个运算符的运算顺序有3!=6种,分别是:

1.①②③    2.①③②    3.②①③    4.②③①    5.③①②    6.③②①

等价的表达式分别是:

1.((a①b②)c③)d          2.(a①b)②(c③d)            3.(a①(b②c))③d

4.a①((b②c)③d)        5.(a①b)②(c③d)            6. a①(b②(c③d))

显然,2和5是相同的,因此只考虑5种情况。这样,括号的问题就解决了。

另外,为了用户体验和程序的稳定性,采用了用户输入数据有效性核查机制和程序倒计时退出机制

程序代码

参考代码如下(基于python3.x)

  1. #二十四点
  2. import os
  3. from time import sleep
  4. from time import perf_counter
  5. global Goal,MaxAllowRetryNum,Count
  6. Goal,MaxAllowRetryNum,Count=24,3,0
  7. #输出程序相关信息
  8. def ptintInfo():
  9. print('''" 经典 24 点 "'''.center(72,"="))
  10. print(" 请用户输入四个正整数值 ".center(64,"-"))
  11. print(" 单个数值提供三试错机会。若机会用完,程序倒计时5秒退出 ".center(50, "-"))
  12. print(" 将输出所有的24点方案,并对方案进行计数 ".center(58,"-"))
  13. print(" 若无方案,程序退出,输出0 ".center(65, "-"))
  14. def printSatistics(times):
  15. print("一共有{}种方案".format(Count))
  16. print("共耗时{:.3f}ms".format(times*1000))
  17. #得到四个用户输入值
  18. def getNumbers():
  19. a=getOneNumber("一")
  20. b=getOneNumber("二")
  21. c=getOneNumber("三")
  22. d=getOneNumber("四")
  23. print("输入的数值为:"+a+','+b+','+c+','+d)
  24. return a+' '+b+' '+c+' '+d
  25. #得到单个用户输入值
  26. #单个提供三次试错机会,(不包括第一次输入)
  27. #试错机会用完后,程序倒计时五秒强制退出
  28. def getOneNumber(temp):
  29. global MaxAllowRetryNum
  30. for tryies in range(MaxAllowRetryNum+1):
  31. num=input("请输入第{}个值:".format(temp))
  32. try:
  33. num=int(eval(num))
  34. if num > 0:
  35. break
  36. else:
  37. print("请核对输入信息,还剩余{}次机会".format(MaxAllowRetryNum-tryies))
  38. except:
  39. print("请核对输入信息,还剩余{}次机会".format(MaxAllowRetryNum-tryies))
  40. if tryies == MaxAllowRetryNum:
  41. for i in range(5):
  42. print("\r所有次数已用完,程序将在{}秒后退出".format(5-i))
  43. sleep(1)
  44. print("\n")
  45. os._exit(0)
  46. return str(num)
  47. #穷举所有的数值列表
  48. #共4!=24种
  49. def getNumList(numbers):
  50. items=numbers.split()
  51. #四重循环遍历穷举所有的数值组合
  52. #data_list = []
  53. # for i in range(4):
  54. # for j in range(4):
  55. # if i!=j:
  56. # for p in range(4):
  57. # if p!=i and p!=j:
  58. # for q in range(4):
  59. # if q!=i and q!=j and q!=p:
  60. # data_list.append(items[i]+' '+items[j]+' '+items[p]+' '+items[q])
  61. data_list = [(items[i]+' '+items[j]+' '+items[p]+' '+items[q]) for i in range(4) for j in range(4) for p in range(4) for q in range(4) if (i != j) &(i != p) &(i != q) &(j != p) &(j != q) &(p != q)]
  62. #使用set方法排除冗余的数字组合
  63. #当输入的数字中存在重复数字,则4!=24种排序方案会存在重复,必须排除
  64. return set(data_list)
  65. #穷举所有的操作符列表
  66. #共4x4x4=64种
  67. def getOplist(ops):
  68. # op_list_orgin=ops
  69. # op_list=[]
  70. #三重循环遍历穷举
  71. # for i in range(4):
  72. # for j in range(4):
  73. # for p in range(4):
  74. # item=str(op_list_orgin[i])+' '+str(op_list_orgin[j])+' '+str(op_list_orgin[p])
  75. # op_list.append(item)
  76. op_list=[ops[i]+' '+ops[j]+' '+ops[p] for i in range(4) for j in range(4) for p in range(4)]
  77. return op_list
  78. #计算24点
  79. def Cal(num_list,opt_list):
  80. for numlist in num_list:
  81. nums=numlist.split()
  82. for oplist in opt_list:
  83. ops=oplist.split()
  84. Cal24(nums,ops)
  85. #对单种运算符顺序和单种数字顺序进行组合运算
  86. def Cal24(nums,op):
  87. global Goal,Count
  88. #第一种情况 ((num0 op0 num1)op1 num2)op2 num3
  89. try:
  90. if round(eval("(("+nums[0]+op[0]+nums[1]+")"+op[1]+nums[2]+")"+op[2]+nums[3]),5) == Goal:
  91. Count+=1
  92. print("(({}{}{}){}{}){}{}={}".format(\
  93. nums[0], op[0], nums[1], op[1], nums[2], op[2], nums[3], Goal))
  94. except:
  95. pass
  96. #第二种情况 (num0 op0 num1) op1 (num2 op2 num3)
  97. try:
  98. if round(eval("("+nums[0]+op[0]+nums[1]+")"+op[1]+"("+nums[2]+op[2]+nums[3]+")"), 5) == Goal:
  99. Count += 1
  100. print("({}{}{}){}({}{}{})={}".format(\
  101. nums[0], op[0], nums[1], op[1], nums[2], op[2], nums[3], Goal))
  102. except:
  103. pass
  104. #第三种情况 ( num0 op0 ( num1 op1 num2 )) op2 num3
  105. try:
  106. if round(eval("("+nums[0]+op[0]+"("+nums[1]+op[1]+nums[2]+"))"+op[2]+nums[3]), 5) == Goal:
  107. Count += 1
  108. print("({}{}({}{}{})){}{}={}".format(\
  109. nums[0], op[0], nums[1], op[1], nums[2], op[2], nums[3], Goal))
  110. except:
  111. pass
  112. #第四种情况 num0 op0 (( num1 op1 num2 ) op2 num3 )
  113. try:
  114. if round(eval(nums[0]+op[0]+"(("+nums[1]+op[1]+nums[2]+")"+op[2]+nums[3]+")"), 5) == Goal:
  115. Count += 1
  116. print("{}{}(({}{}{}){}{})={}".format(\
  117. nums[0], op[0], nums[1], op[1], nums[2], op[2], nums[3], Goal))
  118. except:
  119. pass
  120. #第五种情况 num0 op0 ( num1 op1 ( num2 op2 num3 ))
  121. try:
  122. if round(eval(nums[0]+op[0]+"("+nums[1]+op[1]+"("+nums[2]+op[2]+nums[3]+"))"), 5) == Goal:
  123. Count += 1
  124. print("{}{}({}{}({}{}{}))={}".format(\
  125. nums[0], op[0], nums[1], op[1], nums[2], op[2], nums[3], Goal))
  126. except:
  127. pass
  128. if __name__ == '__main__':
  129. ptintInfo()
  130. numbers=getNumbers()
  131. start=perf_counter()
  132. num_list=getNumList(numbers)
  133. opt_list=getOplist('+-*/')
  134. Cal(num_list,opt_list)
  135. printSatistics(perf_counter()-start)

当输入为5\6\7\8,输出截图为:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/64310
推荐阅读
相关标签
  

闽ICP备14008679号