上篇博客传送门http://blog.csdn.net/sm9sun/article/details/65448140

上文中已经实现了基本胡法的算法,本章加入“癞子玩法”的判胡逻辑

对于癞子的处理方式无非就两种:

一,以枚举的方式使癞子转换为其他牌型进行进一步判断

二,在计算判胡时出现位置空缺时使用癞子进行补位

前者的优势是准确度相对容易把控,并且逻辑清晰。坏处是时间消耗较高,因为是指数级别,当出现3个癞子时(4个癞子直接判胡)需要大量的运算。

后者的优势是时间消耗可能会好一些,注意是可能!因为如果在补位是加入癞子,会极大的影响剪枝。因为你不确定当前非胡状态是否可能通过多个癞子进行补救

但是如果傻傻的将34个牌型逐次遍历一边无疑显得很low逼。。于是我们在枚举前构造一个满足癞子任命的序列(比如说 如果你没有一二三万,那么你肯定是不会把癞子当成一万的)

function  GetAppointList(arr,Hun,AppoinList){/*#define  0~8     万#define  9~17    饼#define  18~26   条#define  27      东#define  28      南#define  29      西#define  30      北#define  31      中#define  32      发#define  33      白*/for(i=0;i<34;++i){if (i > 26)              //风牌{if (arr[i] > 0) {AppoinList.push(i);}}else if (i == 0 || i == 9 || i == 18)              //一,当有本身或者同时有二三时{if (arr[i] > 0 || (arr[i + 1] > 0 && arr[i + 2] > 0)) {AppoinList.push(i);}}else if (i == 8 || i == 17 || i == 26) {if (arr[i] > 0 || (arr[i - 1] > 0 && arr[i - 2] > 0))   //九,当有本身或者同时有二三时{AppoinList.push(i);}}else if (i == 1 || i == 10 || i == 19) {if (arr[i] > 0 || (arr[i - 1] > 0 && arr[i + 1] > 0) || (arr[i + 1] > 0 && arr[i + 2] > 0))   //二,当有本身或者同时有一三或者有三四时{AppoinList.push(i);}}else if (i == 7 || i == 16 || i == 25) {if (arr[i] > 0 || (arr[i - 1] > 0 && arr[i + 1] > 0) || (arr[i - 1] > 0 && arr[i - 2] > 0))   //八,当有本身或者同时有七九或者有六七时{AppoinList.push(i);}}else {if (arr[i] > 0 || (arr[i - 1] > 0 && arr[i + 1] > 0) || (arr[i - 1] > 0 && arr[i - 2] > 0) || (arr[i + 1] > 0 && arr[i + 2] > 0))   //其他中间牌{AppoinList.push(i);}}}
}

这样相对来说会减少大量的循环次数。

然后再说外面,之前的判胡函数,由于加入4癞子直接胡,所以在顶层进行判断,以免后续递归重复计算

相应的基本判胡与七小对判胡放进下一步函数处理

function CanHuPai(arr,Hun){if(arr[Hun]==4){return true;}else{var AppoinList=new Array();GetAppointList(arr, Hun,AppoinList);           //混牌可以任命的序列return HunAppoint(arr,Hun,arr[Hun],AppoinList);}}

如果不是4癞子,则先求出可以任命的序列,然后进入癞子任命方法。

而且在判胡递归算法中,要加入牌大于4情况的处理,比如说4个一样的牌 胡赖子这种

在function CanHuPai_3N_recursive中加入:

    if (arr[P] > 4)  //混牌特殊处理{arr[P]-=3;ret = CanHuPai_3N_recursive(arr, count - 3, P);arr[P]+=3;return ret;}

在function CanHuPai_norm(arr)中加入:

 else if (arr[i] > 4){arr[i] -= 2;ret = CanHuPai_3N_recursive(arr, count - 2, 0);arr[i] += 2;if (ret){return ret;}}

最后就是癞子任命方法的实现了,首先当癞子数为0时,调用原有的判胡算法进行判胡,如果有癞子,则使一个癞子成为某个牌,然后再递归调用。

function  HunAppoint(arr,Hun,HunCount,AppoinList)

arr为牌型状态数组,Hun为癞子ID,HunCount为未处理癞子个数  AppoinList为可以任命序列

这里可能有人会问,你的AppoinList难道不用刷新吗?  比如说 你有两个癞子,有一个孤独的一万, 你可以用两个癞子作为一二三万呀?

而你的序列不刷新,之前构造序列时判断也是必须当二三同时存在时才可以将一打入序列,这会不会有问题?

其实如果出现两个癞子与一个常牌组成一个组合的时候,我们可以只认为其算为3*该常牌,比如说我把他按照三个一万算,照样可以满足条件。

所以构造序列不存在两个癞子与一个常牌组成顺子的情况。

代码如下

/*
混牌任命牌型函数
若无混牌,则通过麻将判胡算法判胡
若有,则枚举可任命的牌序列,进行下一层递归*/
function  HunAppoint(arr,Hun,HunCount,AppoinList) {//  process.stdout.write(AppoinList+'\n');var ret=false;if (HunCount == 0) {if (CanHuPai__7pair(arr)) {return true;}else if (CanHuPai_norm(arr)) {return true;}else {return false;}}else {for(var i=0;i< AppoinList.length;++i) {arr[AppoinList[i]]++;arr[Hun]--;ret = HunAppoint(arr, Hun, HunCount - 1, AppoinList, special);arr[AppoinList[i]]--;arr[Hun]++;if (ret) {return true;}}}return ret;
}

这里我要吐槽下,之前我用foreach来迭代AppoinList数组的,毕竟个人感觉arr[AppoinList[i]]可读性不是很好。。。

但是在foreach里用return竟然还会继续循环!!!!!!

例如:

[1, 2, 3, 4].forEach(function(e){
    console.log(e);
    if(e === 3) return;
})

照样输出1234

在这里浪费了大量的时间,我还以为我算法有问题= =

其应该算是一个独立的函数栈吧, return 只是从最里面的那个回调函数 return,不能从 forEach return

我也是日了狗了。

最后测试一下

input:

  arr[0]+=3;arr[1+9]+=1;arr[3+9]+=1;arr[4+9]+=1;arr[5+9]+=0;arr[6+9]+=1;arr[8+9]+=3;arr[29]+=2arr[28]+=1

output

0,11,14,28,29
true
2017-03-24T08:47:42.399Z 2017-03-24T08:47:42.515Z 116

0(一万)是癞子,输出表示,可以胡一万,二饼,五饼,西风,南风。

应该是正确的。

后续的优化处理帖

http://blog.csdn.net/sm9sun/article/details/77774722

node.js——麻将算法(二)赖子玩法相关推荐

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

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

  2. node.js——麻将算法(六)简易版麻将出牌AI1.0

    普通麻将的出牌AI如果不是要求特别高的话,其实蛮容易实现的,毕竟大多数人打牌都只是看自己的手牌. 所以作为简易版的AI,出牌的策略只要奔着胡牌去就可以了.我们能想到的就是把相邻或相同的牌凑到一起,把单 ...

  3. node.js——麻将算法(七)简易版麻将出牌AI2.0

    *文本为上一篇博客http://blog.csdn.net/sm9sun/article/details/77898734的部分追加优化 上一篇博客已经实现了基本的出牌逻辑,大部分情况能够给出正确的策 ...

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

    回想三月份刚接触棋牌时写过一些麻将的算法,转眼间半年过去了,回顾下曾经的代码,写的还真是蛮low的 http://blog.csdn.net/sm9sun/article/details/654481 ...

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

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

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

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

  7. python拼图游戏代码的理解_有意思的JS(1)拼图游戏 玩法介绍及其代码实现

    我是你们的索儿呀,很幸运我的文章能与你相见,愿萌新能直观的感受到Javascript的趣味性,愿有一定基础者有所收获,愿大佬不吝赐教 拼图游戏是一张图片分为若干块,打乱次序,将其中一块变为空白块,其只 ...

  8. 跑胡子胡牌算法(带赖子、基于回溯算法)

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

  9. Node.js文件操作二

    前面的博客 Node.js文件操作一中主要是对文件的读写操作,其实还有文件这块还有一些其他操作. 一.验证文件path是否正确(系统是如下定义的) fs.exists = function(path, ...

最新文章

  1. 使用NVelocity自动生成Favorite收藏夹的导航页面
  2. css知识点笔记-常见特性
  3. 【转】玩转git分支
  4. oracle exp执行失败,Oracle EXP-EXP-00091的错误原因及处理方法
  5. openresty 日志输出的处理
  6. 即时通讯软件几个主要下载分类
  7. 节点主动可信监控机制
  8. 让我们用 SQL 开发一个图形数据库吧
  9. android 5播放flash插件下载地址,Flash Player安卓版
  10. vue HTML内使用触底加载
  11. 枸杞功效多,这样吃效果翻倍
  12. git 配置ssh 秘钥
  13. 利用python写福字【支付宝五福活动大概率出敬业福】
  14. gitlab修改附件上传文件大小限制
  15. 神思二代身份证读卡器Demo的C++版本
  16. hbw-utils - 关于guava和jdk的compare方法
  17. 安装w3af时已经安装retire却提示没有安装的问题
  18. android http zlib,利用zlib库对HTTP收到的gzip数据解压
  19. PLC数据采集网关有哪些作用,PLC数据采集网关如何正确进行使用?
  20. 屏幕录像专家CamStudio

热门文章

  1. define定义的函数如何引用_「C与指针心得」25.预处理器-宏函数
  2. mysql cursor 嵌套_MYSQL 存储过程多游标嵌套遍历
  3. STM32那点事之构建工程模板
  4. DMA双缓冲传输意义
  5. 3-1numpy基本操作
  6. [Unity] 战斗系统学习 11:Buff 框架 1
  7. Mybatis(12)事务原理和自动提交设置
  8. ps拖拽组的时候,不卡 - 软件设置篇
  9. css实现发光的input输入框
  10. RiPro小八子主题V1.5.5美化版+优惠码折扣+工单系统+任务系统