#include <iostream>
#include <vector>
#include <algorithm>
#include <chrono>enum MajiangType
{emMJType_Wan   = 1, //万emMJType_Tiao  = 2, //条emMJType_Tong  = 3, //筒emMJType_Zi    = 4, //字emMJType_Hua   = 5  //花
};constexpr char MJ(char m, char n) {return m << 5 | n;
}inline MajiangType Majiang_Type(char m) {return MajiangType(m >> 5);
}inline char Majiang_Value(char m) {return m & 0x1F;
}enum emMJ:char
{emMJ_1Wan = MJ(emMJType_Wan, 1),emMJ_2Wan = MJ(emMJType_Wan, 2),emMJ_3Wan = MJ(emMJType_Wan, 3),emMJ_4Wan = MJ(emMJType_Wan, 4),emMJ_5Wan = MJ(emMJType_Wan, 5),emMJ_6Wan = MJ(emMJType_Wan, 6),emMJ_7Wan = MJ(emMJType_Wan, 7),emMJ_8Wan = MJ(emMJType_Wan, 8),emMJ_9Wan = MJ(emMJType_Wan, 9),emMJ_1Tiao = MJ(emMJType_Tiao, 1),emMJ_2Tiao = MJ(emMJType_Tiao, 2),emMJ_3Tiao = MJ(emMJType_Tiao, 3),emMJ_4Tiao = MJ(emMJType_Tiao, 4),emMJ_5Tiao = MJ(emMJType_Tiao, 5),emMJ_6Tiao = MJ(emMJType_Tiao, 6),emMJ_7Tiao = MJ(emMJType_Tiao, 7),emMJ_8Tiao = MJ(emMJType_Tiao, 8),emMJ_9Tiao = MJ(emMJType_Tiao, 9),emMJ_1Tong = MJ(emMJType_Tong, 1),emMJ_2Tong = MJ(emMJType_Tong, 2),emMJ_3Tong = MJ(emMJType_Tong, 3),emMJ_4Tong = MJ(emMJType_Tong, 4),emMJ_5Tong = MJ(emMJType_Tong, 5),emMJ_6Tong = MJ(emMJType_Tong, 6),emMJ_7Tong = MJ(emMJType_Tong, 7),emMJ_8Tong = MJ(emMJType_Tong, 8),emMJ_9Tong = MJ(emMJType_Tong, 9),//字牌不能形成顺子,所以编码不能连续,而且有的地方有买码规则,字牌也根据除以4的余数被分配到了4个方位emMJ_DongFeng =       MJ(4, 1),//东 1 % 4 = 1emMJ_NanFeng =      MJ(4, 6),//南 6 % 4 = 2emMJ_XiFeng =       MJ(4, 11),//西 11 % 4 = 3emMJ_BeiFeng =        MJ(4, 16),//北 16 % 4 = 0emMJ_HongZhong =  MJ(4, 18),//中 18 % 4 = 2emMJ_FaCai =      MJ(4, 23),//发 23 % 4 = 3emMJ_BaiBan =     MJ(4, 28),//白 28 % 4 = 0//一副中花牌各只有一张emMJ_Mei =    MJ(5, 1),//梅emMJ_Lan = MJ(5, 3),//兰emMJ_Ju =  MJ(5, 5),//菊emMJ_Zhu = MJ(5, 7),//竹emMJ_Chun = MJ(5, 9),//春emMJ_Xia =    MJ(5, 11),//夏emMJ_Qiu =    MJ(5, 13),//秋emMJ_Dong = MJ(5,15)  //冬
};const std::vector<char> all_majiang = {emMJ_1Wan,emMJ_2Wan,emMJ_3Wan,emMJ_4Wan,emMJ_5Wan,emMJ_6Wan,emMJ_7Wan,emMJ_8Wan,emMJ_9Wan,emMJ_1Tiao,emMJ_2Tiao,emMJ_3Tiao,emMJ_4Tiao,emMJ_5Tiao,emMJ_6Tiao,emMJ_7Tiao,emMJ_8Tiao,emMJ_9Tiao,emMJ_1Tong,emMJ_2Tong,emMJ_3Tong,emMJ_4Tong,emMJ_5Tong,emMJ_6Tong,emMJ_7Tong,emMJ_8Tong,emMJ_9Tong,emMJ_DongFeng,emMJ_NanFeng,emMJ_XiFeng,emMJ_BeiFeng,emMJ_BaiBan,emMJ_FaCai,emMJ_HongZhong
};
const std::vector<emMJ> pattern131 = { emMJ_1Wan,emMJ_9Wan,emMJ_1Tiao,emMJ_9Tiao,emMJ_1Tong,emMJ_9Tong,emMJ_DongFeng,emMJ_NanFeng,emMJ_XiFeng,emMJ_BeiFeng,emMJ_HongZhong,emMJ_FaCai,emMJ_BaiBan};//基本和牌类型
bool IsCommonHu(const std::vector<char>& original_pai)
{//前提:牌已经排好序,不含已碰牌和已杠牌,所以牌数应该是3n+2//过程:先找出一对将牌,然后再寻找刻子牌和顺子牌,直到剩余牌为0才表示可和牌,否则不能和牌//记录将牌位置size_t jiang_location = -1;std::vector<char> pai;while (true){auto i = jiang_location + 1;if (i >= original_pai.size()){return false;}pai = original_pai;if (jiang_location != -1){if (pai[i] == pai[jiang_location]){++i;}}//寻找将牌位置,记录将牌第二个,并擦除该两牌jiang_location = -1;for (; i < pai.size() - 1; ++ i){if (pai[i] == pai[i + 1]){jiang_location = i + 1;pai.erase(pai.begin() + i, pai.begin() + i + 2);break;}}if (jiang_location == -1){//没有将牌,不能和牌return false;}//剩下的牌数是3的倍数//从左起第1张牌开始,它必须能组成刻子牌或者顺子牌才能和,否则不能和while (pai.size() >= 3){if (pai[0] == pai[1] && pai[0] == pai[2]){//找到刻子牌并移除pai.erase(pai.begin(), pai.begin() + 3);}else{auto it1 = std::find(pai.begin() + 1,pai.end(), pai[0] + 1);if (it1 != pai.end()){auto it2 = std::find(it1 + 1, pai.end(), pai[0] + 2);if (it2 != pai.end()){//找到顺子牌并移除pai.erase(it2);pai.erase(it1);pai.erase(pai.begin());}else{break;}}else{break;}}}if (pai.empty()){break;}}return true;
}//是否是十三幺牌型
bool Is131Hu(std::vector<char> original_pai)
{if (original_pai.size() != 14){return false;}size_t i = 0;while (i < original_pai.size()-1){if (original_pai[i] == original_pai[i+1]){break;}++i;}if (i == original_pai.size() - 1){return false;}original_pai.erase(original_pai.begin() + i);if (pai.size() != pattern131.size()){return false;}for (size_t i = 0; i < pai.size(); ++i){if (original_pai.[i] != pattern131[i]) {return false;}}return true;
}//是否是小七对牌型
bool Is7pairsHu(const std::vector<char>& pai) {const int pairs = 7;if (pai.size() != 2 * pairs){return false;}int i = 0;for (; i < pairs; ++i){if (pai[2 * i] != pai[2 * i + 1]){break;}}return i == pairs;
}//检查听哪些牌
std::vector<char> Ting(const std::vector<char>& pai)
{//遍历所有牌,依次加入,判断是否能和牌std::vector<char> hupai;for (auto& i : all_majiang){auto temp(pai);temp.push_back(i);std::sort(temp.begin(), temp.end());  //先排序if (Is131Hu(temp) || Is7pairsHu(temp) || IsCommonHu(temp)){hupai.push_back(i);}}return hupai;
}int main()
{std::vector<char> v = { MJ(1,2),MJ(1,2),MJ(2,2),MJ(2,2),MJ(1,3),MJ(3,4),MJ(3,4),MJ(1,4),MJ(1,4),MJ(2,5),MJ(2,5),MJ(1,6),MJ(1,6) };std::vector<char> tingpai;auto start = std::chrono::steady_clock::now();tingpai = Ting(v);std::chrono::nanoseconds ns = std::chrono::steady_clock::now() - start;std::cout << "time:" << ns.count() << std::endl;for (auto& i : tingpai){std::cout << "Result:" << (int)i << std::endl;}system("pause");return 0;
}

C++实现麻将基本听牌胡牌的算法相关推荐

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

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

  2. swift--广东麻将v2.0(带胡牌、听牌算法和自动打牌功能)

    本程序实现了广东麻将的全部功能:自动摸牌.打牌.碰.杠.听牌.胡牌(其中庄家手动打牌,其它电脑玩家自动打牌),具体功能有: 系统通过骰子确定庄家,然后发牌,最开始从庄家手动打牌. 可以碰,杠,不能吃牌 ...

  3. 带赖子的麻将胡牌算法Java_带赖子的超高效麻将、跑胡子胡牌算法

    文档 github地址 https://github.com/yuanfengyun/qipai/tree/master/doc lua版 https://github.com/yuanfengyun ...

  4. 带赖子的超高效麻将、跑胡子胡牌算法

    腾讯课堂视频讲解:https://ke.qq.com/course/305608?tuin=104cb0e2 文档 github地址 https://github.com/yuanfengyun/qi ...

  5. 棋牌麻将 - 无癞子胡牌算法(第三版)

    基础知识 本文涉及的所有名词均在博文中有说明: http://blog.csdn.net/kunyus/article/details/78644517 测试结果 测试环境: MEM: 4 GB CP ...

  6. 棋牌麻将 - 无癞子胡牌算法

    基础知识 本文涉及的所有名词均在博文中有说明: http://blog.csdn.net/kunyus/article/details/78644517 核心思想 去除杂念: 由于字牌中只只允许出现 ...

  7. 棋牌麻将 - 无癞子胡牌算法(优化)

    基础知识 本文涉及的所有名词均在博文中有说明: http://blog.csdn.net/kunyus/article/details/78644517 核心思想 去伪存真: 满足胡牌的部分, 要么是 ...

  8. 带癞子麻将查表判断胡牌高效率低内存算法

    同事曾问我麻将判定输赢有没有什么高效的方法,他说他随手写的三个癞子的情况下判定要6秒多.我当时只想他是需要循环 34 * 34 * 34(共有 34 种麻将) 次并依次判定输赢,这肯定不是个好方法,后 ...

  9. 代码实现对麻将的听牌分析(判断什么牌能胡)

    文章目录 前言 一.游戏规则 二.分析流程 三.写代码 前言 emmmmm,好久没发文章了上次发还是在上次 hxdm动动你们发财的小手指点点赞鸭,快没动力了,呜呜呜~ 前几天面试,要求做一个类似麻将的 ...

最新文章

  1. 一个虚拟键盘的简单思路
  2. WeakHahMap,HashMap和(垃圾回收)Gc
  3. 初识html语言,初识 “HTML”
  4. python框架django面试问别人什么问你_django面试会问什么
  5. android透明视频教程,安卓透明教程(Android transparent tutorial).doc
  6. python测试开发django-8.windows系统安装mysql8教程
  7. 用户空间访问I2C设备驱动
  8. ASP.NET 页生命周期
  9. linux清理磁盘空间的脚本,在Ubuntu和Linux Mint上释放空间的7种简单方法
  10. JQuery Ajax 解析
  11. 如何通过ngnix将网站访问改为https
  12. vb从入门到精通_益智 | 用VB编程开发的围棋游戏!
  13. python编写web漏洞扫描器_Python脚本实现Web漏洞扫描工具
  14. MATLAB图像处理
  15. C/C++ 内部收益率
  16. 【第六篇】Qt学习与使用---在qt中打印PDF文件(不是生成PDF)
  17. TPshop项目-功能测试(1)
  18. 【算法】递归(recursion)+经典例题个人分析
  19. 亚马逊邮件关联 关联原因?邮件
  20. 说说qwerty、dvorak、colemak三种键盘布局

热门文章

  1. 习题 6.5 有n个人围成一圈,顺序排号。从第1个人开始报数(从1~3报数),凡报到3的人退出圈子,问最后留下的人原来排在第几号。
  2. c++的内存管理(raii->shart_ptr->垃圾回收)
  3. Winform运行后,界面尺寸与设计时不一样
  4. 小牛叔讲Python第8章:集合大家一起的快乐
  5. 温度滞回程序C语言,间隙式粘滞阻尼器温度变化对滞回性能影响的研究
  6. 动画专业考一级计算机选什么语种,学校和专业如何选择?学连接32个国家的金牌语种,做国家稀缺的复合型人才!...
  7. Mixly第三方库开发的两种方法——U8g2库二次开发
  8. linux修改组群名字,Linux用户和组 - 回忆斑斑驳驳的个人空间 - OSCHINA - 中文开源技术交流社区...
  9. MOS管基本认识(快速入门)
  10. Java is Pass-by-Value, Dammit!