记录一下麻将的通用胡牌算法实现,只要满足X*ABC + Y*DDD + EE 即可胡牌。

在这里先分析一下最简单的胡牌思路:先找出所有可能的将牌,若除去两张将牌之外的所有牌都能成刻或顺,则可胡牌。

将牌就是公式里唯一的对子即是EE、顺子ABC或者刻子DDD。

将牌的查找:遍历每张手牌,若有两张以上相同牌就能作将,或者用一张癞子凑也可。

接下来就只要判断一副牌是否成扑,伪码如下:

function isShunKe=(牌){ // 这里约定传入的牌是有序的、张数是3的倍数  if(没牌){  return true;  }  if(若第一张是顺子中的一张){  if(isShunKe(去掉该顺子剩下的牌)){  return true;  }  }  if(若第一张是刻子中的一张){  if(isShunKe(去掉该刻子剩下的牌)){  return true;  }  }  return false;
}

只要思路清晰了算法就很简单,为什么只考虑第一张牌?其实函数内部递归调用了每张牌都会计算到的,除非没牌了。下面给出详细代码:

function isShunKe(cards, laiziCount){  if (cards.length === 0){  return true;  }  // 若第一张是顺子中的一张  for (var first = cards[0] - 2; first <= cards[0]; first++) {  if(first % 10 > 7 || (laiziCount === 0 && first < cards[0])) {   // 顺子第一张牌不会大于7点、无赖子情况下顺子第一张只能用手上的牌  continue;  }  var shunCount = 0;  for (var i=0;i<3;i++) {  if (cards.indexOf(first + i) >= 0) {  shunCount++;  }  }  if (shunCount === 3 || shunCount + laiziCount >= 3) {  // 找到包含第一张牌的顺子  var puCards = cards.slice();  var puLaizi = laiziCount;  for (var i=0; i<3; i++) {  var deletePos = puCards.indexOf(first + i);  if (deletePos >= 0) {  puCards.splice(deletePos, 1);  }  else {  puLaizi--;  }  }  if (isShunKe(puCards, puLaizi)) {  // 剩下的牌成扑  return true;  }  }  }  // 若第一张是刻子中的一张  var keziCount = 1;  var keziCard = cards[0];  if (cards[1] === keziCard) {  keziCount++;  }  if (cards[2] === keziCard) {  keziCount++;  }  if (keziCount === 3 || keziCount + laiziCount >= 3) {  var puCards = cards.slice();  var puLaizi = laiziCount;  for (var i = 0; i < 3; i++) {  var deletePos = puCards.indexOf(keziCard);  if (deletePos >= 0) {  puCards.splice(deletePos, 1);  }  else {  puLaizi--;  }  }  if (isShunKe(puCards, puLaizi)) {  return true;  }  }  return false;
}   

下面是判断胡牌的函数:

function canHuLaizi(cards, laiziCount) {  if ((cards.length + laiziCount + 1) % 3 != 0) {  // 若牌张数不是2、5、8、11、14则不能胡  return false;  }  // 排序方便胡牌判断  cards.sort(function(a, b) {  return a - b;  })  // 依次删除一对牌做将,其余牌全部成扑则可胡  for (var i = 0; i < cards.length; i++) {  if (i > 0 && cards[i] == cards[i - 1]){  // 和上一次是同样的牌,避免重复计算  continue;   }  if ((i + 1 < cards.length && cards[i] == cards[i + 1]) || laiziCount > 0) {  // 找到对子、或是用一张癞子拼出的对子  var puCards = cards.slice();  var puLaizi = laiziCount;  puCards.splice(i, 1);  if (puCards[i] == cards[i]) {  puCards.splice(i, 1);  }  else {  puLaizi--;  }  // 删去对子判断剩下的牌是否成扑  if (isShunKe(puCards, puLaizi)) {  return true;  }  }  }  if (laiziCount >= 2 && isShunKe(cards, laiziCount - 2)) {  // 两个癞子做将牌特殊判定处理  return true;  }  return false;
}  

这里做一下两个输入参数的说明:

  1. cards:手牌数组,不超过14张牌,每张牌由整数表示如下
  2. 数字 {01 ~ 09} 表示  {1 ~ 9} 筒

    数字 {11 ~ 19} 表示  {1 ~ 9} 条

    数字 {21 ~ 29} 表示  {1 ~ 9} 万

    数字 {31 33 35 37 } 表示风 { 东 南 西 北 }    // 为什么间隔两个数字记录一个,就是为了防止将自拍在自己算过程中组成顺子

    数字 {41 43 45} 表示箭 {中 發 白}

  3. laiziCount:癞子数量,用整数表示

有关算法代码重构,这里有个小技巧:

使用随机生成的牌型数据,将新版本代码与老版本代码对比,当运算结果不一样时候可以快速的找出bug,也可以循环大量输入统计耗时比较效率。

通过这个手段解决了一些小问题,最终跑1000万次牌型输出结果一致,就可以安心的替换了。

麻将普通胡牌算法JS版(含癞子,非轮训)相关推荐

  1. 跑胡子c语言算法,跑胡子胡牌算法Java版(带赖子、基于回溯算法)

    跑胡子规则 跑胡子,小写"一"到"十"各4张共40张,大写"壹"到"拾"各4张共40张. 砌牌:跑胡子为3人同玩,庄家砌 ...

  2. 麻将胡牌算法lua 不支持癞子

    --[[ file:game\lualib\mahjongHelper.lua desc:麻将辅助 + 胡牌 + 听牌 算法 auto:Carol Luo ]] local ipairs = ipai ...

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

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

  4. 麻将 胡牌 算法(任意癞子)

    分享一个麻将胡牌算法,支持多癞子,自己对麻将胡牌的理解写的一套快速识别胡牌逻辑,核心逻辑500行代码,仅对同条万进行处理,字花牌不包含在内,易理解,1M次随机胡牌牌型大概3秒左右.原创分享,我的算法也 ...

  5. erlang实现麻将胡牌以及癞子胡牌算法

    判断胡牌 麻将胡牌其实是按照nAAA + mABC + DD的套路,算法判断也很好实现,找出DD,然后剩下的牌都能形成AAA或者ABC即可胡牌.本文只介绍麻将普通胡牌的算法,该算法经过验证可判断除特殊 ...

  6. 麻将胡牌算法的一种设计及其分析

    马勇波  陈欣庆 (解放军理工大学工程兵工程学院研究生二队,南京 210007)       摘  要  文章通过一个二维数组定义麻将的数据结构,并在此基础上设计了一种判断麻将是否胡牌的算法,该算法主 ...

  7. 麻将胡牌算法带癞子 python实现

    姐姐:你去帮我和闺蜜打麻将? 学霸哥哥:可是我不会打麻将呀! 姐姐:你不是学霸吗?我教你一个麻将公式,我闺蜜可是单身哟! 学霸哥哥:什么公式? 姐姐:麻将胡牌公式: AAA*M+ABC*N+BB,WM ...

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

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

  9. 麻将高效鬼牌胡牌算法(C++版)

    最近做的一个麻将里面有双鬼牌的玩法,即为8张鬼牌,第一反应是采用N重循环把鬼牌变成一张张牌去遍历是否能胡牌,实际测试在5张牌鬼牌的情况得出结果就需要差不多5,6分钟. 因此自己做了一套用凑牌的方式去判 ...

最新文章

  1. urllib.parse包学习
  2. flask貌似html文件里只能用flask指定的路径格式,css文件里则可用相对路径
  3. openssl https 单向认证连接成功示例
  4. kafka架构、亿级数据如何优化GC
  5. K8S+Docker理论与实践深度集成
  6. Win7系统打开摄像头提示“请检查装置连接状况”怎么办
  7. combobox异步加载 easyui_如何解决多条数据加载easyui-combobox样式反应慢的问题
  8. 【Java】《Java面向对象编程的三大特性》阅读笔记
  9. centos用php上传文件,WBB - Centos下PHP无法Curl模拟Post上传文件的问题
  10. PDE2 three fundamental examples
  11. java生成一条唯一的邀请码_根据用户id生成一个唯一邀请码
  12. 什么原数据更容易平稳_判定数据序列平稳与否的方法都有哪些,什么是平稳序列...
  13. Android中的Apk的加固(加壳)原理解析和实现
  14. springboot实现条形码_java生成条形码(多种条码类型生成)
  15. IDEA如何设置author头注解
  16. 在Xubuntu上安装中文输入法
  17. 用户行为分析zhi应用分析模型
  18. 牛逼!java只能输入数字的正则
  19. 《深入理解计算机系统》
  20. vue中warning_使用vue的i18n 出现很多warning提示

热门文章

  1. HTML5 学习总结
  2. 学习IOS开发第一天——必备工具书和开发工具
  3. 【python】将单通道图像转换为3通道图像
  4. steam 相同元素相加_7500美元的存储型XSS漏洞(steam客户端)
  5. mysql存储过程查询结果分页并返回总记录数
  6. 【3D建模干货】国外建模大师精心总结,成为建模高手的必备技巧
  7. Spring Boot 整合Redis 包含Java操作Redis哨兵 作者:哇塞大嘴好帥(哇塞大嘴好帅)
  8. jQuery_01入门
  9. HJLF-E1 DC220V【反时限电流继电器】
  10. Java下载Excel的模板文件