Python秒算24点实现及原理详解


Posted in Python onJuly 29, 2019

什么是24点

我们先来约定下老王和他媳妇玩的24点规则:给定4个任意数字(0-9),然后通过+,-,*,/,将这4个数字计算出24。

小时候玩的都是这个规则,长大了才有根号,才有各种莫名其妙的高级算法,不好玩了,因为我不会。

可能有人会觉得很简单,但是真的简单吗?

比如:

8,3,3,3
7,3,3,3
你能一眼看出来答案吗?好像真的可以……

大致思路

这样想,将四个数字进行全排列,在他们之间添加运算符号。

运算符我们需要进行排列组合,因为只有四个数字,所以只需要三个运算符,而且算法符可能会重复,比如三个都是+。

再遍历四个数字的全排列,对每一组数字而言,遍历所有组合的操作符。最后将数字和操作符进行拼接运算,就可以得到最终结果了。

演示环境

操作系统:windows10

python版本:python 3.7

代码编辑器:pycharm 2018.2

使用模块:math,itertools, collections.abc

具体代码

1、首先我们对所有数字进行去全排列,这里我们使用 itertools.permutations 来帮助我们完成。

iertools.permutations 用法演示

from itertools import permutations

data_list = permutations([1,2,3,4],2)
for data in data_list:
print(data)

结果显示

(1, 2)
(1, 3)
(1, 4)
(2, 1)
(2, 3)
(2, 4)
(3, 1)
(3, 2)
(3, 4)
(4, 1)
(4, 2)
(4, 3)

permutations 第一个参数是接收一个课迭代的对象,第二个参数指定每次排列时从课迭代对象中选着几个字符进行排列。也可以不传入第二个参数,那么默认就是可迭代对象的长度。并且返回一个生成器。

所以我们需要对所有数字进行全排列,就可以像下面这样写:

def get_all_data_sequence(data_iter):
 return permutations(data_iter)

2、然后我们需要拿到所有的操作运算符的所有组合方式。这里我们就会使用 itertools.product 函数了。

itertools.product 用法演示

from itertools import product

sequence1 = product('ABCD','xy')
sequence2 = product([0,1],repeat=3)

for sequence in sequence1:
 print(sequence)

print('-'*30)

for sequence in sequence2:
 print(sequence)

结果显示

('A','x')
('A','y')
('B','x')
('B','y')
('C','x')
('C','y')
('D','x')
('D','y')
------------------------------
(0, 0, 0)
(0, 0, 1)
(0, 1, 0)
(0, 1, 1)
(1, 0, 0)
(1, 0, 1)
(1, 1, 0)
(1, 1, 1)

itertools.product,返回传入所有序列中笛卡尔积的元祖,repeat参数表示传入序列的重复次数。返回的是一个生成器。

那么获取所有的操作运算符就可以通过这个函数来获取了

def get_all_operations_sequence():
 operations = ['+','-','*','/']
 return product(operations,repeat=3)

3、现在我们已经拿到了所有可能组合的操作符和数字了,接下来就需要对他们进行拼接了。然后执行运算。

这一步操作我们会用到 itertools.zip_longest() 和 itertools.chain.form_iterable() 函数。

itertools.zip_longest() 用法演示

data = zip_longest([1,2,3,4],['*','-','+'],fillvalue='')
for value in data:
 print(value)

结果显示

(1, '*')
(2, '-')
(3, '+')
(4, '')

zip_longest() 其实和 python 内置的 zip() 函数用法差不多,只是 zip_longest 是以最长的一个序列为基准,缺失值就使用 fillvalue 参数的值进行填充

itertools.chain.form_iterable() 用法演示

data = zip_longest([1,2,3,4],['*','-','+'],fillvalue='')
data_chain = chain.from_iterable(data)
for value in data_chain: 
 print(value)

结果显示

1
*
2
-
3
+
4

这里的data是什么样的大家知道了吧,然后我们将data传入 chain.form_iterable() 中,它就能将里面的值依次拿出来。

了解了这两个函数之后,那么我们就可以开始拼接数字和操作运算符了。

def calculate(self):
 '''
 计算值,返回对应的表达式和值
 :return: 
 ''' 
 for data_sequence in get_all_data_sequence():  
  operation_sequences = get_all_operation_sequence()  
  for operation_sequence in operation_sequences:   
   value = zip_longest(data_sequence, operation_sequence, 
  fillvalue='')   
   value_chain = chain.from_iterable(value)   
   calculate_str = ''   
   # 对得到的字符进行拼接成为表达式 calculate_str
   for _ in value_chain:    
    calculate_str += _   
   try:
    result = eval(calculate_str
   # 处理被除数可能为零的情况,然后就直接跳过这次循环
   except ZeroDivisionError:
    continue
   if math.isclose(result, 24):     
    return calculate_str,result
 return None,None

代码分析

1、eval() 函数,接受一个字符串,能让这个字符串当成 python 代码运行,返回运行的结果。

2、math.isclose():为什么这里需要使用 math.isclose() ,而不是直接使用==运算符呢?这是因为最后算出来的表达式可能有精度问题,例如23.9...或者24.0...等数字,所以我们就需要使用math.isclose()函数来帮助我们判断两个数字是否相等了,这个函数就有一个精度范围。这样出现上面情况的时候,我们也能匹配得到条件了。

我们运行代码,然后测试代码是否能达到我们的需求。

首先我们测试1,2,3,4四个数字,

程序出来了结果 1*2*3*4 24

看来好像我们写的代码是正确的

我们再来测试一组数据8,8,3,3.

嗯?我们并没有得到结果?这四个数字不能运算出24吗?

8 / ( 3 - 8 / 3 ) 这样组合可以吧,为什么没有算出来这种结果呢?

这是因为我们没有考虑括号的原因。括号是可以改变运算优先级的。所以我们得把括号考虑进去。

那么想一下括号最多可以有几个呢?怎样给我们的表达式添加括号呢?

在4个数字的运算中,括号最多只能有三个。

并且,在这里,我们使用一种简单的方法添加括号,我们把所有可能出现括号的情况全部罗列出来,然后在将得到的运算表达式拼接进去。

可能大家会觉得罗列出所有括号出现的情况不现实,因为有很多情况

其实不然,当我们去罗列的时候,你就会发现,只有11种情况。

FORM_STRS = [
 # 数字 运算符 数字 运算符 数字 运算符 数字
 # 一个括号 的情况
 '(%s %s %s) %s %s %s %s',
 '(%s %s %s %s %s) %s %s',
 '(%s %s %s %s %s %s %s)',
 '%s %s (%s %s %s) %s %s',
 '%s %s (%s %s %s %s %s)',
 '%s %s %s %s (%s %s %s)',
 # 两个括号 的情况
 '(%s %s %s) %s (%s %s %s)',
 '( (%s %s %s) %s %s) %s %s',
 '( %s %s (%s %s %s)) %s %s',
 '%s %s ((%s %s %s) %s %s)',
 '%s %s (%s %s (%s %s %s))',
 # 三个括号是重复的,就不用罗列出来了
]

然后我们对得到的表达式在进行遍历拼接,然后我们再运算表达式。

这样我们就能得出正确的结果了

代码写完了,终于可以开始和媳妇,哦不,老王家的媳妇玩起来了

代码已全部上传至Github

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python构造函数及解构函数介绍
Feb 26 Python
python实现根据月份和日期得到星座的方法
Mar 27 Python
解决Python print 输出文本显示 gbk 编码错误问题
Jul 13 Python
tensorflow入门:tfrecord 和tf.data.TFRecordDataset的使用
Jan 20 Python
在python里创建一个任务(Task)实例
Apr 25 Python
踩坑:pytorch中eval模式下结果远差于train模式介绍
Jun 23 Python
opencv 阈值分割的具体使用
Jul 08 Python
Python 实现3种回归模型(Linear Regression,Lasso,Ridge)的示例
Oct 15 Python
Python numpy大矩阵运算内存不足如何解决
Nov 19 Python
Django用内置方法实现简单搜索功能的方法
Dec 18 Python
python源文件的字符编码知识点详解
Mar 04 Python
十个Python自动化常用操作,即拿即用
May 10 Python
django之状态保持-使用redis存储session的例子
Jul 28 #Python
django 通过URL访问上传的文件方法
Jul 28 #Python
django使用admin站点上传图片的实例
Jul 28 #Python
Python中变量的输入输出实例代码详解
Jul 28 #Python
对django中foreignkey的简单使用详解
Jul 28 #Python
解决django 新增加用户信息出现错误的问题
Jul 28 #Python
Django使用Channels实现WebSocket的方法
Jul 28 #Python
You might like
手把手教你使用DedeCms的采集的图文教程
2007/03/11 PHP
php使用session二维数组实例
2014/11/06 PHP
深入讲解PHP Session及如何保持其不过期的方法
2015/08/18 PHP
php实现图片以base64显示的方法
2016/10/13 PHP
php把字符串指定字符分割成数组的方法
2018/03/12 PHP
javascript 动态调整图片尺寸实现代码
2009/12/28 Javascript
jquery 读取页面load get post ajax 四种方式代码写法
2011/04/02 Javascript
最佳6款用于移动网站开发的jQuery 图片滑块插件小结
2012/07/20 Javascript
jquery插件制作 图片走廊 gallery
2012/08/17 Javascript
用iframe实现不刷新整个页面上传图片的实例
2016/11/18 Javascript
vue双向数据绑定知识点总结
2018/04/18 Javascript
karma+webpack搭建vue单元测试环境的方法示例
2018/05/24 Javascript
2019 年编写现代 JavaScript 代码的5个小技巧(小结)
2019/01/15 Javascript
ES6 如何改变JS内置行为的代理与反射
2019/02/11 Javascript
Layui数据表格跳转到指定页的实现方法
2019/09/05 Javascript
jQuery实现数字华容道小游戏(实例代码)
2020/01/16 jQuery
从Node.js事件触发器到Vue自定义事件的深入讲解
2020/06/26 Javascript
[06:13]DOTA2进化论(修改版)
2013/10/08 DOTA
python实现2014火车票查询代码分享
2014/01/10 Python
python基础教程之lambda表达式使用方法
2014/02/12 Python
python判断一个集合是否包含了另外一个集合中所有项的方法
2015/06/30 Python
详解Python 数据库 (sqlite3)应用
2016/12/07 Python
Python生成词云的实现代码
2020/01/14 Python
用于ETL的Python数据转换工具详解
2020/07/21 Python
Clarks鞋美国官网:全球领军鞋履品牌
2017/05/13 全球购物
英国电子产品购物网站:Tech in the basket
2019/11/08 全球购物
公司领导推荐信
2013/11/12 职场文书
《夏夜多美》教学反思
2014/02/17 职场文书
公司门卫岗位职责
2014/03/15 职场文书
倡议书格式
2014/04/14 职场文书
铣床操作工岗位职责
2014/06/13 职场文书
初中数学教学反思范文
2016/02/17 职场文书
小学三年级语文教学反思
2016/03/03 职场文书
利用html+css实现菜单栏缓慢下拉效果的示例代码
2021/03/30 HTML / CSS
Go语言读取txt文档的操作方法
2022/01/22 Golang
带你了解Java中的ForkJoin
2022/04/28 Java/Android