Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >我会用Python秒算24点,你呢?

我会用Python秒算24点,你呢?

作者头像
sergiojune
发布于 2019-08-05 06:05:12
发布于 2019-08-05 06:05:12
1.2K00
代码可运行
举报
文章被收录于专栏:日常学python日常学python
运行总次数:0
代码可运行

周末闲来无事,看到隔壁家的老王在和隔壁家的媳妇玩24点,就进屋看了看。发现老王是真不行啊,那不行,这也不行。

就连个24点都玩不过他媳妇,给他媳妇气的,啥都不能满足,这不能,那也不能。

我坐下来和他媳妇玩了两把,那都是无出其右,把把赢!

我要走的时候,他媳妇还挽留我多玩几把,有意思。

为了能让老王在他媳妇面前抬起头来,我决定帮他一把……就用python写了个算24点的玩意,老王对我感激涕零。

什么是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 用法演示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from itertools import permutations

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

结果显示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(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 第一个参数是接收一个课迭代的对象,第二个参数指定每次排列时从课迭代对象中选着几个字符进行排列。也可以不传入第二个参数,那么默认就是可迭代对象的长度。并且返回一个生成器。

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def get_all_data_sequence(data_iter):
    return permutations(data_iter)

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

itertools.product 用法演示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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)

结果显示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
('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参数表示传入序列的重复次数。返回的是一个生成器。

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def get_all_operations_sequence():
    operations = ['+','-','*','/']
    return product(operations,repeat=3)

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

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

itertools.zip_longest() 用法演示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
data = zip_longest([1,2,3,4],['*','-','+'],fillvalue='')
for value in data:
    print(value)

结果显示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(1, '*')
(2, '-')
(3, '+')
(4, '')

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

itertools.chain.form_iterable() 用法演示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
data = zip_longest([1,2,3,4],['*','-','+'],fillvalue='')
data_chain = chain.from_iterable(data)
for value in data_chain:    
    print(value)

结果显示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1
*
2
-
3
+
4

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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种情况。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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))',
    # 三个括号是重复的,就不用罗列出来了
]

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

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

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

END

往期文章回顾

Python爬虫的起点

如何让你写的爬虫速度像坐火箭一样快【并发请求】

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 日常学python 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
让Python算24点,一点也不难!
昨天做了一个聊天客户端,今天我们来玩一个游戏放松一下,这个游戏就是众所周知的24点!
不可言诉的深渊
2019/07/26
1.4K0
Python 模块:itertools
在某些情况下,我们通常需要对序列进行一些复杂的操作,比如从序列中选出一部分元素做排列,组合,笛卡尔积等。如果自己实现这个操作未免太繁琐了,而且还会占用大量的空间,这个时候我们可以求助于 Python 模块——itertools。这个模块总共有 3 部分——无穷迭代器,根据最短输入序列的长度停止的迭代器,排列组合迭代器。
不可言诉的深渊
2019/07/26
7750
Python笔记:itertools库简介
至于其他的函数,坦率地说我倒是基本都没怎么用过,不过这次既然打算写了,就一次性把这些都写了吧。
codename_cys
2021/03/27
6280
Python3标准库built-in、
Python3中实现了很多生成器函数,本篇主要介绍built-in、itertools、functools模块中的生成器。
py3study
2020/01/02
1.5K0
Python标准库itertools中函数精要
1、count() >>> import itertools >>> x = itertools.count(3) >>> x count(3) >>> for i in range(10): print(next(x), end=',') 3,4,5,6,7,8,9,10,11,12, >>> x = itertools.count(3,5) >>> x count(3, 5) >>> for i in range(10): print(next(x), end=',') 3,8,13,18,23,28,
Python小屋屋主
2018/04/16
8290
Python版24点游戏
24点游戏是指随机选取4张扑克牌(不包括大小王),然后通过四则运算来构造表达式,如果表达式的值恰好等于24就赢一次。下面的代码定义了一个函数用来测试随机给定的4个数是否符合24点游戏规则,如果符合就输出所有可能的表达式。 from random import randint from itertools import permutations #4个数字和2个运算符可能组成的表达式形式 exps = ('((%s %s %s) %s %s) %s %s', '(%s %s %s) %s (%
Python小屋屋主
2018/04/16
7420
python中 itertools模块的使用方法
accumulate(iterable: Iterable, func: None, initial:None)
Python学习者
2023/04/08
1.8K0
进阶的运维开发(二)- 迭代器和生成器
python迭代器于平常的可迭代对象相比,拥有占用字节少等优点,往往在处理大量可迭代对象的时候应该优先考虑迭代器实现,如下面的例子:
奔跑的骆驼
2020/01/29
6820
Python标准库笔记(10) — itertools模块
目录[-] itertools 用于更高效地创建迭代器的函数工具。 itertools 提供的功能受Clojure,Haskell,APL和SML等函数式编程语言的类似功能的启发。它们的目的是快速有效地使用内存,并且将它们关联在一起以表示更复杂的基于迭代的算法。 基于迭代器的代码比使用列表的代码提供了更好的内存消耗特性。因为直到数据需要使用时才从迭代器中生成,所有数据不需要同时存储在内存中。这种 “惰性” 的处理模式可以减少大型数据集的交换和其他副作用,从而提高性能。 除了 itertools 中
jhao104
2018/06/19
1.9K0
Python高效编程之itertools模块详解
在打印内容字节数较小时,全部载入内存后,再打印,没有问题。可是,如果现在有成千上百万条车辆行驶轨迹,叫你分析出其中每个客户的出行规律,堵车情况等,假如是在单机上处理这件事。
小草AI
2019/11/07
6310
24点解法
24点游戏是小时候很喜欢玩的游戏,给出4个数,通过加、减、乘、除完成运算,最终得到结果为24。比如数字1、3、5和9,可以通过3 * 5 + 9 * 1 得到结果24。本篇文章将通过Java程序来实现对给定数字的求解。
孟君
2020/03/06
7050
python 迭代器、生成器、yield、iter
只要 Python 函数的定义体中有 yield 关键字,该函数就是生成器函数 调用生成器函数时,会返回一个生成器对象
Michael阿明
2021/09/06
1.1K0
《流畅的Python》第十四章学习笔记
__next__:返回下一个可用的元素,如果没有元素了抛出StopIteration异常
zx钟
2021/03/10
6340
《流畅的Python》第十四章学习笔记
【Python入门第十三讲】可迭代对象(Iterable)、迭代器(Iterator)和生成器(Generator)
在 Python 中,可迭代对象(Iterable)、迭代器(Iterator)和生成器(Generator)是处理数据集合和处理大数据时常用的概念和工具。
不惑
2024/02/08
1.8K0
【Python入门第十三讲】可迭代对象(Iterable)、迭代器(Iterator)和生成器(Generator)
Python暴力激活成功教程密码
上面的代码会从0-9这些数字中选取三个,形成全排列,并返回一个以三个元素为一组的列表,然后我们通过一个列表推导式,将每个元组中的三个元素拼接在一起。
全栈程序员站长
2022/09/23
3930
Python暴力激活成功教程密码
用python算24点游戏
国庆假天天躺尸,也没啥动力写文章,就把以前写的24点游戏的代码整理一下算了。24点游戏基本每个人都玩过,这里尝试用python给出在n个数情况下,24点游戏所有可能的结果,首先对游戏规则进行说明
量化小白
2019/08/29
3.7K1
用python算24点游戏
详解cannot import name ‘izip‘ from ‘itertools‘
在Python中,itertools模块是一个非常有用的工具,它提供了许多迭代器函数,用于高效地处理迭代操作。然而,有时你可能会遇到一个错误,即cannot import name 'izip' from 'itertools'。在本篇文章中,我们将详细解释这个错误的原因,并提供一些解决方案。
大盘鸡拌面
2024/01/31
3350
Python基础(九) | time random collections itertools标准库详解
(2)time.perf_counter()   随意选取一个时间点,记录现在时间到该时间点的间隔秒数,记录sleep
timerring
2022/10/06
6600
Python基础(九) | time random collections itertools标准库详解
40个你可能不知道的Python的特点和技巧
1、拆箱 >>> a, b, c = 1, 2, 3 >>> a, b, c (1, 2, 3) >>> a, b, c = [1, 2, 3] >>> a, b, c (1, 2, 3) >>> a, b, c = (2 * i + 1 for i in range(3)) >>> a, b, c (1, 3, 5) >>> a, (b, c), d = [1, (2, 3), 4] >>> a 1 >>> b 2 >>> c 3 >>> d 4     2、使用拆箱进行变量交换 >>> a, b = 1
Java学习123
2018/05/16
6800
流畅的 Python 第二版(GPT 重译)(九)
迭代对于数据处理是基础的:程序将计算应用于数据系列,从像素到核苷酸。如果数据不适合内存,我们需要惰性地获取项目——一次一个,并按需获取。这就是迭代器的作用。本章展示了迭代器设计模式是如何内置到 Python 语言中的,因此您永远不需要手动编写它。
ApacheCN_飞龙
2024/03/21
3430
流畅的 Python 第二版(GPT 重译)(九)
相关推荐
让Python算24点,一点也不难!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验