24点是指从去除大小王后的52张扑克牌中任取 4 张,通过「加、减、乘、除」四则运算得到 24。是一个历史悠久的趣味小游戏。
《数据化管理》书中在测试数据敏感度章节提到一个细节“每天上下班的路上,盯着公交车外看到的汽车尾部牌照玩24点”,去练运算能力。根据排列组合知识可以算出:在1-10的数字中任选4个,有C(13,4)=715种情况(因为数字可以重复,如[5,5,5,5],故不是直接从10个数中取4个的组合),从1-13中任选4个是C(16,4)=1820种情况,经过大佬门的枚举和推导,只考虑加减乘除,715种情况中,有566种有解,也就是79.16%的概率,而从1~13中选的1820种情况中是1362种情况下能算出24点,概率为74.83% 。
给定序列算出24点
最近自己也在练24点的计算,需要随机生成4个数的组合,并且在需要有答案,看这题有哪些做法能算出24点,于是就打算用Python来实现生成4个随机数以及求给定序列的24点计算方法。可以选择在4个数之间的3个空格中枚举各种符号的情况,并且考虑括号,还有一种思路是“降数法”:4个数经过一步运算“降维”成3个数,再变成2个数,最后得到1个数,如果得到24说明这种组合成立。后一种需要的判断更少些,于是选择实现这一思路。
代码的大致流程如下:
1),对给定的4个数进行排列,得到A(4,4)=4!=24种排列,对这24种情况执行:
2),前2个数实现第一步计算,合并成1个数,生成一个3个数的新序列;
3),对这3个数做排列,同样前2个做四则运算,3个数合并成2个;
4),最后两个数的排列为[a,b]和[b,a],分别做加减乘除运算,变成一个数;
5),如果最后生成的数是24,则记录这种计算方式;否则继续对下一个排列重复上面2~4。
得到一个序列的全排列的递归方法在之前的一个Ann全排列文章有具体讲解,这里不赘述。
最后求24点计算方法的代码如下:
1 | #枚举列表lst的全排列 |
我们拿几个实例来进行测试,输入结果如下:
这种实现还是有些粗暴,没有很好地进行各种情况的去重,例如2×7+6+4和2×7+4+6是一种情况,对交换律和括号的去重实现可以参考 如何不重复地枚举 24 点算式?(上) - 王赟 Maigo。
给24点小程序加上GUI
基于上面写的代码我们可以求任意4个数算24的所有情况,加上随机数生成平时就不缺24点的练习了,为了更好用,我们再加上GUI。为了兼容性,这里选择用内置的tkinter去实现GUI。
整体流程如下:
导入tk库,创建主窗体->添加控件->处理交互->进入主事件循环
交互的逻辑还是“降数法”的思路。
整体的界面如下图:
代码比较长,主要分为了生成各种按钮并设置坐标放在合适的位置,编写按钮按下的回调函数两个部分。部分代码如下:
1 | root=tk.Tk() |
运行效果如下:
代码改一下可以变成命令行下的交互版本:
1 |
|
换个环境,Ubuntu下的效果:
最后GUI版的脚本可以导出为exe文件,其他人也可以方便的使用,通过pyindatller
可以快速打包py脚本为exe文件。
Python打包为exe普遍文件会比较大(还是C#在这方面更有优势),我这边导出的结果是8.3MB,可以接受,用内置库的好处。写小型程序用tkinter是够用的。
公众号蛰虫始航后台回复 24点可下载文中代码。