【原创】一个纸牌游戏引发的思考
本文适合入门级技术男阅读,大牛请绕过。
一、背景:近期,在研究区块链技术。发现了一种以太坊的代币GTC,其落地的项目以游戏为主,看了下目前官方APP上的小游戏,感觉不好玩,或者是自己不太喜欢玩。
怎么办啊?自己写呗。反正闲着也是闲着,动动手防止手生了。于是把多年以前用.NET写的一个纸牌游戏找了出来,移植到了ANDROID系统上。就有了下文。
二、游戏规则
先上图,没图你说个……
游戏规则很简单:每次首发五张牌,玩家可以选择换一次牌,换了牌后,当五张牌中出现一对(7以上的牌),即可得分,两对、三条、顺子、同花、葫芦(Full House)、四条、同花小顺、同花大顺这几个牌型,玩家都赢分,所得分为押注的1、2、3、5、10、15、20、50、100、200倍分数。大小飞机(大小王)可以当成任意牌。
什么?很熟悉?没错,以前在街机游戏室都见过,规则和德州扑克差不多。经典的游戏,属于80后的回忆。呵呵。
三、关键代码解析
有兴趣?那好,听我慢慢说。
牌面显示很简单,就是对应1-54张牌的序号,可以把这个问题抽象为就是1-54个数字,这还不简单?54个数字啊,只有54个数字!!
3.1怎么识别花色和牌面?
首先我们编排的时候,就按一定的顺序,如数字1表示方块A,2表示方块2……,13表示方块K,14表示梅花A,……,26表示梅花K,27表示红心A……52表示黑桃K,53表示小飞机(小王),54表示大飞机(大王)。
根据这个,写个函数:用待检测数整除于14,结果为0就是方块,1就是梅花,2就是红心,3就是黑桃。待检测数除于13,余数就是牌面的数字,因为牌面是从1开始排序,所以余数为0时,就把它当成13,即“K”点。例如:
17整除14等于1,就表示梅花;17除于13,余4,所以17表示的是梅花4。
26整除14等于1,就表示梅花;26除于13,余0,0就要当成13,所以26表示的是梅花K。
44整除14等于3,就表示黑桃;44除于13,余5,所以44表示的是黑桃5。
理解了吗?不理解可以自己找副牌,按顺序排好,多琢磨琢磨。原理是这个原理,具体实现的代码有多种上多样,直接上我写的代码吧:
3.2怎样模拟“洗牌”?
我们用一个int型的数组存放着54个数,那洗牌就是对这个数组进行一个随机的乱序。这个实现就是很多种方式了,我是这样做的。
代码超短,每次循环产生两个0-54的随机数,再把这两个数对应的数组值进行交换。一共循环54*3=162次。为什么要循环这个数呢?下文另表。
3.3怎样判断属于什么牌型?
从最大牌型依次向下判断,看属于什么牌型。最先判断是不是“五条”,是的话就返回。不是的话就看是不是“同花大顺”,……上代码:
例如:判断是否是”5条”,先把这5个数通过whatscards函数(详见3.1)返回这五张牌分别对应的花色和牌面数值,牌面数值是否一样就行。再考虑有大小王的情况就行了。
例如:判断是否是”同花顺”, 先把这5个数通过whatscards函数(详见3.1)返回这五张牌分别对应的花色和牌面数值,代表花色的数字一样,这五张牌就是同花色。代表牌面的数字进行排序后,顺序排列就表示是“顺子”,两个条件同时满足就是”同花顺”
3.4发牌时的动画效果怎么实现?
使用个定时器,每隔一定时间显示牌的正反面。
四、问题引入
这里开始正文部分。是的,刚才那些只是开篇简单介绍。经过简单的游戏测试后,发现了问题:
经统计,开出“大牌”的机率较高,如下图所示:
分析原因,是“洗牌”的环节不合理,不能达到一种合理的值。当然,只测试几十次上百次的数据是远远不够的。我们要模拟大量的数据去测试,先后模拟了几次,每次进行10万次开牌统计,统计结果的占比基本恒定,我们以最后一次的结果为例进行简单分析:
统计结果如下:
显然,倍数的设定和出现的次数有矛盾,“杀牌”只占到了32%,明显程序设定有问题,下面我们利用统计学进行调整参数。
我们测试的随机数分别从54*1=54,至54*200=10800,一共测试了200组,每组10万次数据,发现其结果在随机数为54*3=164次以后就已经基本恒定,所以选择了这个“3”大循环为参数。这就是3.2里提到的答案。
当然,从玩家的角度,这个结果已经可以满足游戏的需求,但从数学的角度,这不是我们理想的结果。一是玩家的分数在不断上升,这让开发者无动力去继续以后的维护和更新(商业角度考量),二是倍率与机率不成正比,所以我们还得继续改进游戏的设定。
测试一:模拟10万次发牌,统计前五张牌中,各张牌出现的机率,结果如下:
每张牌出现的机率基本一样,“洗牌程序”没有问题。但是,这种游戏规则中,大小王是特殊牌,它出现的机率与最终的结果有直接的关系。我们来进行第二个测试。
测试二:抽出大小王后,模拟30万次开牌,统计各种牌型的可能性。结果如下:
这个结果显示玩家输的机率达到48.21%,有点接近游戏的结果了。但暴露了两个问题,一是30万次都不会出现一次同花大顺,那这个牌是有问题的,要检查程序。二是full House比同花和顺子都容易出,这种设定肯定不合理。百度了下,德州扑克的玩法就是这样的顺序。这个规则肯定要改。
经检查,程序代码没有问题,把测试次数加到500万次时,开出了10次同花大顺。OK,第二个问题,把牌倍率的顺序调整一下,如下:
最后,就是大小王的问题,把这两张大小王加一个出现概率,简单处理如下:
草草结束吧,本来是想用机器学习的方法来,来设置的一些参数的,但在本文中只是用到了统计来人工调整。精力和时间的原因,感觉写得很累,暂时先这样吧,希望大家见谅。如果支持我的小伙伴多的话,会考虑继续完善代码并开源(反正代码也没加混淆和加固,有兴趣的小伙伴可以拟出源码供参考。)
APK下载链接: https://pan.baidu.com/s/1ZKqPJq_8KpNPpXgplclVpw&qrfrom=1&qrtype=apk
(记住,在手机上要用浏览器打开,微信打开会要求登录)
有问题和意见建议可发邮件和我交流。
有大家支持的话,下个程序考虑写个“炸金花”游戏,打算尝试使用机器学习的方法,通过玩家大量的下注数据,分析玩家底牌大小,用“机器学习”来识别“打假”。
等会儿,区块链、GTC什么的,没有下文了?呵呵,以后再说吧。^_^!