淘客熙熙

主题:【原创】用计算机求解一个儿时的游戏 -- Highway

共:💬39 🌺28 新:
全看树展主题 · 分页首页 上页
/ 3
下页 末页
家园 【原创】用计算机求解一个儿时的游戏

昨天在河里瞎逛的时候,看看面壁网友的一个回帖

哈,我也问个算法。。。,是在问一个算法的问题,问题是“前些天算两个7两个4(+-*/),怎么让它等于24,便想写个code: 任意给4个数,输出是否等于24,如果等于,给出怎么得到的结果。”

看了这个问题,使我马上联想起小时候常玩的一个游戏。大概在二三年级的时候(注意不是大二大三大时候),常和小朋友们在一起用扑克牌玩一种心算游戏。一般是4个人玩(2个人也成),一开始每个人分一摞扑克牌。然后每轮一人出一张牌放在中间。这时候大家开始心算。谁第一个找到算法,这四张扑克牌就归谁。到最后谁手里的扑克牌最多,谁就是赢家。

点看全图

外链图片需谨慎,可能会被源头改

那时候我们只会四则运算。所以规则很简单,就是四张扑克牌都要用到,但是每张牌只能用一次。不管是加减乘除怎么组合,能得到24就算赢。

这个游戏是谁发明的我不知道,为什么选择24也从来没有问起。事实上这个游戏设计有问题,很多情况下大家想不出答案,只能把自己出的扑克牌收回,重新再来。

那时候我们玩得时候,有大一些的孩子在旁边看我们玩(比如说谁的哥哥姐姐什么的)。有时候我们小孩子们想不出来,大孩子们可能会用一些“高级”的算法来解决问题,比如说用乘方,或是开根号什么的。

问题是当我们大家都想不出来答案的时候,可能我们是对的,这4张扑克牌无解。也可能我们是错的,我们还没有穷尽所有的组合。现在计算机这么牛,能帮着解决一下这个问题嘛?我想这可能就是面壁朋友要问得那个问题。

Highway不才,是吃计算机饭的。看到这个帖子后有些技痒。于是乎坐在那里开始发呆(所谓的思考)。想了好一阵子,基本路线大概有个眉目了以后,开始动手。手边正好有Java的IDE,于是决定用Java来写写看。

写了一阵子,又测试了几个case,一个小游戏算是基本成形了。当然这个游戏只是Proof of concept类的演示,连个图形界面也没有(寒碜啊)。

游戏是这样玩的:你在Dos Console上给出4个数字(1到13,代表A到K),然后一敲回车,计算机就开始寻

找答案。找到的话,就在屏幕上给出答案(很多时候有多种解),找不到的话,就实话实说“Sorry, I can’t find one!”.

点看全图

外链图片需谨慎,可能会被源头改

我现在的这个小游戏很粗糙,很多地方都不是很合理,比如说计算机给出的多种答案其实是一回事。因为有些括号是多余的,A+B-C+D和B+A+D-C也只是交换了一些顺序而已。我现在的算法不具备甄别这些的能力。

我的游戏算法大概是这样的:

1) 任意给四个1-13之间的数字

2) 求出所有的排列来。4个数字的组合上限是24,如果数字有重复,排列自然就会减少,这样可以减少一些计算。

3) 把加减乘除运算符加进去,列出所有可能的计算表达式(优先级也要考虑)

4) 对每个表达式进行求解,如果是24,那么这个表达式就是一个答案。

从计算机程序的角度来讲,我现在这个程序不太合格,有几个地方是hard-coded(优先级算法上有些投机取巧)。对加减法和乘法的交换率视而不见(及A+B = B+A, A*B=B*A),造成很多重复的计算。如果有人出钱让我把这小游戏写成一个产品的话,那么正儿八经程序应该是这样的。

1) 允许扑克牌张数为1-N, 求解的答案可以是24,也可以是任何整数。用户可以自己制定游戏规则。

2) 算法可以是简单的加减乘除,也可以是更广义上的所有binary运算,比如说取余数,乘方,或者是计算机上常用的shift(<< >> >>>)等等。用户可以自由选择定制。

3) 加上美观的界面。如果用户解除了一个有难度的题目后,一定要有养眼的MM(切切)弹出。如果一个非常简单的题目也做不出来的话,可以适当的嘲笑羞辱一下(嘿嘿

如果把这些情况都想到了,那么穷尽法可能性能上就会有些问题,比如说是玩8张牌,允许复杂算法的大游戏,那么组合很可能就会上亿。如果是玩20张牌的超大游戏,你计算机 可能3天也算不出来)。那么这时候算法就要优化,要有些智能,及早排除那些“压根就没谱”的表达式。据说当初深蓝大战国际象棋大师的时候,就有些“投机”。当卡斯帕罗夫走出一步棋的时候,深蓝会利用“常识”首先排除一些荒唐的走法,同时利用卡斯帕罗夫历史上胜负的记录优先选择一些方案。当然即使是这抄近道儿,要估算出十几步以后的情况,出现的组合数量还是触目惊心的,计算机之大非深蓝这种超级计算机才可能完成。

好了,就说到这里吧!

关键词(Tags): #Java#Game#Poke
家园 不懂算法

不过好几年前玩的手机里就有这个java游戏:24点,当自己无解是手机会给出正解。

家园 之所以选24这个数,也许是因为4张牌较为容易得到24

毕竟只能是四则运算,那种小数,开方什么的高级货不算的。24是个偶数而且可以被3整除,同样的数字有12,36等,我猜3张牌算12,5张牌算36不错。就4张牌而言,算出24也许是4张牌的排列组合中最多的。一点愚见。

家园 呵呵,那个帖子我回过的

一般说来算24只用四则运算,不过即使这样也有很多很tricky的解,比如你的第一个case:7,7,4,4实际是有解的。我先不说答案,有兴趣消磨时间的同学可以想想。

另外解的同构性判断是个很复杂的问题,在组合搜索中,这种判断往往比寻找解的算法还要难。比较简单的处理办法可能是找到一个解就返回,不去追求多个解。

搜索树的修剪也是门大学问,如何优先发展有希望的分支,正是AI中的A*算法的核心问题。

花!

家园 7 * (4 - 4/7) = 24
家园 我猜可能是除不尽的时候小数截断的问题

似乎Highway的算法原则上没问题,我猜可能是4/7这种除不尽的时候截断保留小数了,所以后来再X7的时候就和24差一点点。

都花!

恭喜:意外获得【西西河通宝】一枚

谢谢:作者意外获得【西西河通宝】一枚

鲜花已经成功送出

PS. Highway叫Jinsong,hehe

家园 哈哈,你这么一说我又看了一下我的code,真的是有个bug

fix了一下,给出了两个答案(7,7,4,4四张牌)

Please input 4 numbers here, like "7, 8, 11, 9"
4, 4, 7, 7
The solution is: (4 - (4 / 7)) * 7
The solution is: 7 * (4 - (4 / 7))

仔细一看,其实是一种算法。我现在基于String表达式的算法甄别不出来。简单的fix就是把这些表达式标准化一下,这样形似的算法就会“合并”起来。

刚才把取余数算法加了进来,答案有多了一些,变成了

The solution is: (4 * 7) - (4 % 7)
The solution is: ((4 % 7) * 7) - 4
The solution is: 7 * (4 - (4 / 7))
The solution is: (7 * 4) - (4 % 7)
The solution is: (4 - (4 / 7)) * 7
The solution is: (7 * (4 % 7)) - 4

如果把乘方加进来,好多问题变得更有趣了。

家园 double rounding error的问题我想到了,问题

不是出在那里。是计算组合的情况我遗漏一些。

BTW,眼力不错。不过那是Vista login的user name,未必是我的名字,再说我用的也许是别人的计算机呢。你这个算法有“问题”。哈哈

家园 hehe, 花上
家园 你是说乘方?

如果把乘法加进来,好多问题变得更有趣了

家园 1 3 4 6有没有解?
家园 类似的还有5 5 5 1
家园 运行了一把我的程序,结果是

The solution is: 6 / (1 - (3 / 4))

牛掰不?

家园 计算了一下

如果只是四则运算,答案是

The solution is: (5 - (1 / 5)) * 5

The solution is: 5 * (5 - (1 / 5))

如果可以用取余数,那么多一个答案

The solution is: (5 * 5) - (1 % 5)

如果还可以用乘方,那么又多一个

The solution is: (5 * 5) - (1 ^ 5)

家园 can you...

can you give me your code in C here?

全看树展主题 · 分页首页 上页
/ 3
下页 末页


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河