回想三月份刚接触棋牌时写过一些麻将的算法,转眼间半年过去了,回顾下曾经的代码,写的还真是蛮low的

http://blog.csdn.net/sm9sun/article/details/65448140  以前无赖子判胡算法

针对于半年前写的算法,CanHuPai_norm函数第一步就是剔除对子(即将牌),由于是将全部牌数组整体考虑,所以每个大于等于2的牌都有可能成为将牌。为了优化筛选,我做了针对于不同个数的剪枝判断:(Cancutpair_2 Cancutpair_3 Cancutpair_4)。但其实我们可以在此之前把手牌分成若干组,牌连续的为一组。满足条件的组合牌数包含(3N,3N+2)其中唯一的3N+2组就存在将牌,看过上述帖子大家应该可以理解3N张牌判胡是很简单的,而3N+2需要枚举所有可以剔除的将牌然后再进行3N判胡,这样我们分组后,3N+2的内个小组可供选择的就很少了,这样会极大的优化此部分逻辑处理时间。

代码:

    var groups = [];var group = {arr: [],count:0};for (var i = 0; i < arr.length;i++){      if (arr[i] > 0) {group.arr.push(arr[i]);group.count += arr[i];}if (i > 26 || arr[i + 1] == 0||i%9==8)//风或9或不连续{if (group.count > 0) {groups.push({ arr: group.arr.concat(), count: group.count});group.arr = [];group.count = 0;}          }      }console.log('groups:', JSON.stringify(groups));

当i>26是风牌,当风牌或到9或连续牌中断,我们将其视为一组,例如:

我们看111311这个组合是唯一的3N+2,那么其一定包含将牌,所以我们很快就可以定位到是将牌4

同时,30,31,32是风派,所以被分割成单独的小组,其个数count是1,很显然,若存在count为1的组,此牌是不能胡的。

当我们将牌分完组后,就可以根据每小组的牌数量count进行分支处理了,此时group里的arr只代表连续牌的个数,其具体是什么牌已经不重要了。

    var haspair = false;for (var i = 0; i < groups.length;i++){var group = groups[i];if (group.count % 3 == 1){return false;}else if(group.count % 3 == 0){if (!allow_0({ arr: group.arr.concat(), count: group.count })){return false;}}else if (group.count % 3 == 2 && !haspair){if (!allow_2({ arr: group.arr.concat(), count: group.count })) {return false;}haspair = true;}else {return false;}}return haspair;

如果是3N+1的数量,直接返回false,如果3N+2有多个或没有,也返回false。在打牌过程中, 分支的顺序是按照牌数出现几率调整的,一局牌平均下来每次抓牌后出现单张的概率最高,其实是3N组合,而将牌一般只是单独的一个对,所以放在最后。

所以经过上述的处理,我们allow_2里实际已经没多少>=2的牌了,也没什么优化的必要了,我们可以枚举所有可能大于2的牌,然后剔除调用allow_0再回溯即可:

var allow_2 = function (group) {for (var i = 0; i < group.arr.length;i++){if (group.arr[i] >= 2){group.arr[i] -= 2;group.count -=2;var ret = allow_0({ arr: group.arr.concat(), count: group.count });group.arr[i] += 2;group.count += 2;if (ret){return ret;}}}return false;};

最后就是3N判断的方法allow_0了,和之前算法的 CanHuPai_3N_recursive函数类似,不过由于在之前分割的时候已经做了处理,所以就省去了很多边缘判断。

var allow_0 = function (group) {for (var i = 0; i < group.arr.length; i++){var c = group.arr[i] %= 3;if (i > group.arr.length-3&&c!=0)//最后两张牌{return false;}switch (c){case 0: break;case 1: {if (group.arr[i + 1] >= 1 && group.arr[i + 2] >= 1) {group.arr[i + 1] -= 1;group.arr[i + 2] -= 1;}else {return false;}break;}case 2: {if (group.arr[i + 1] >= 2 && group.arr[i + 2] >= 2){group.arr[i + 1] -= 2;group.arr[i + 2] -= 2;}else{return false;}break;}}}return true;};

注:当一组只剩最后两种牌后,证明其之前的牌均已处理完毕,那么此时这两种牌必然是3N个数,我们经常见到的牌就是两张连续的牌(因为他处于听牌阶段)

所以在函数的开始判断i > group.arr.length-3&&c!=0作为剪枝效果还是蛮不错的。

至于3N牌判胡算法网上有很多种,其实效率相差不大,因为都是遍历一遍(On)。例如将剔除的方案打个表:

    [3] = 3, [4] = 3,[31] = 30, [32] = 30, [33] = 33, [34] = 33, [44] = 33,[111] = 111, [112] = 111, [113] = 111, [114] = 114,[122] = 111, [123] = 111, [124] = 111,[133] = 111, [134] = 111,[141] = 141, [142] = 141, [143] = 141, [144] = 144,[222] = 222, [223] = 222, [224] = 222,[233] = 222, [234] = 222,[244] = 222,[311] = 300, [312] = 300, [313] = 300, [314] = 300,[322] = 300, [323] = 300, [324] = 300,[331] = 330, [332] = 330, [333] = 333, [334] = 333,[341] = 330, [342] = 330, [343] = 330, [344] = 333,[411] = 411, [412] = 411, [413] = 411, [414] = 414,[422] = 411, [423] = 411, [424] = 411,[433] = 411, [434] = 411,[441] = 441, [442] = 441, [443] = 441, [444] = 444

大家仔细观察会发现:

一:4开头的处理方式等同于1开头,因为其就等于把4先剔除3个变成1,即我上述代码中的var c = group.arr[i] %= 3;同理,3开头的也一样

二:1开头的一定会扣除111,2开头的一定会扣除222,因为其不够3张牌嘛。3开头的我们可以按0算,即扣除300,因为扣除333等同于扣除三次300

测试截图:

最后一提,这种算法由于不考虑本身是什么牌,所以一些特殊的玩法例如红黑风等要求就很难处理。且只适合用于打牌过程中计算判胡,胡之后的番数牌型结算也需另加计算

node.js——麻将算法(四)胡牌算法的一些优化处理方案(无赖子版)相关推荐

  1. 麻将算法之 ------ 胡牌算法

    麻将数据牌集合 private int[] cardDataArray ={0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, //万子 1 2 ...

  2. 麻将普通胡牌算法JS版(含癞子,非轮训)

    记录一下麻将的通用胡牌算法实现,只要满足X*ABC + Y*DDD + EE 即可胡牌. 在这里先分析一下最简单的胡牌思路:先找出所有可能的将牌,若除去两张将牌之外的所有牌都能成刻或顺,则可胡牌. 将 ...

  3. 包含癞子的麻将胡牌算法

    记录一下麻将的通用胡牌算法实现,只要满足M x ABC + N x DDD + EE 即可胡牌. 在这里先分析一下最简单的胡牌思路:先找出所有可能的将牌,若除去两张将牌之外的所有牌都能成扑,则可胡牌. ...

  4. 麻将胡牌算法,带癞子

    貌似去年去面试一家公司,问了麻将的算法.虽然之前做过广东麻将,但是胡牌算法在服务端,就没有在意. 现在在网上搜了一些算法试了试 = =! 麻将普通的胡牌就是刻子+顺子+将.癞子可以充当任意一张牌. 参 ...

  5. 高效查表判断胡牌算法的lua版本

    来源于日本论坛的一套用于麻将的判断胡牌算法,运用查表方式实现.原文链接(http://hp.vector.co.jp/authors/VA046927/mjscore/mjalgorism.html) ...

  6. node.js——麻将算法(五)胡牌算法的一些优化处理方案(有赖子版)

    以前有赖子判胡算法 http://blog.csdn.net/sm9sun/article/details/65632646 以前的帖子说明了处理赖子的两种方案:枚举代替及插空补缺,并最终选择了枚举遍 ...

  7. node.js——麻将算法(三)胡牌相关明牌

    最近在做一款叫做"卡五星"的三人麻将,来自湖北,麻将里只有筒和条(没有万)以及中发白这些牌. 其他的特殊功能暂且不提,其中有一个需求是玩家听牌后需要将与胡牌有关系的牌显示出来给其他 ...

  8. node.js——麻将算法(一)基本判胡

    首先带来的就是麻将胡牌.听牌的算法,不过大家都知道,麻将各个地方的规则都不同,所以相关算法也需要作出一定的调整. 先简单说一下本次demo的规则要求把. 1.不计番,也就是没那么多胡法,最后胡了就行. ...

  9. 麻将通用胡牌算法详解(拆解法)

    1.背景 前几天刚好有项目需要胡牌算法,查阅资料后,大部分胡牌算法的博客都是只讲原理,实现太过简单,且没有给出测试用例.然后就有了下面的这个胡牌算法,我将从算法原理和算法实现两部分展开,想直接用的,直 ...

  10. 麻将胡牌算法——C#

    这里只介绍普通的麻将胡牌算法,也就是7个对子或者 1个对子+3*N; N = 三个顺子或者三个一样的 ,其中字牌(东南西北中发白)不能算顺子. 首先对于每张牌 它有牌的的数字 1-9,牌的种类 (万条 ...

最新文章

  1. datatable 前台和后台数据格式
  2. java程序中出现两个class,Java中Class类中两个值得注意的进行类型动态转换的方法...
  3. 2019-11-09 正定矩阵的一些常见概念
  4. 【转载】MySQL索引背后的数据结构及算法原理
  5. glDrawElements参数在新旧版本传最后一个参数的不同
  6. mysql 唯一记录_mysql选择唯一记录
  7. Strategy 策略模式
  8. 10无法更新系统_华为EMUI系统或停留安卓11,无法更新
  9. java 获取发布后的路径问题_Java中的路径问题实例分析
  10. php function函数用法,js的function函数是什么?js中function的用法
  11. import java.util_importjava.util.*;classKeyMaster{publi..._考试资料网
  12. visio画图复制粘贴到word_visio复制粘贴到word中
  13. 模块化的ESP8266小电视设计与制作
  14. 超像素池化全监督语义分割
  15. OpenWrt固件编译、软件包Ipk的编译详解
  16. Latex 图像、表格标题(题注)加脚注
  17. Spire.pdf Pdf添加图片,无水印
  18. vue.js中使用甘特图(gantt-elastic)的使用
  19. 卓有成效的管理者-时间管理篇
  20. 自动化测试工程师,自动化测试项目老是误报?怎么解决?(详细总结)

热门文章

  1. c语言条件编译include,7.1编译与预处理-include-c学习 | 时刻需
  2. python中import星_【已解决】Python中递归import导入:ImportError: cannot import name
  3. nginx修改默认端口
  4. k8s创建Deployment报错:missing required field “selector“ in io.k8s.api.apps.v1.DeploymentSpec
  5. PyCharm配置Docker
  6. php中mimes函数,wordpress函数check_upload_mimes()用法示例
  7. phpcms内容页 ( $inputtime ) 去掉发布时间的时分秒 - 代码篇
  8. 用手刻出计算机系统,一种计算机模拟手工雕刻制版的方法
  9. html引入png不显示透明北京,解决在网页上显示PNG图片底色不透明的方法
  10. 唱好铁血丹心谐音正规_长沙正规的音乐高考培训学校