麻将Ai的出牌逻辑
来源:互联网 发布:借贷软件排行 编辑:程序博客网 时间:2024/06/11 22:13
写了一个测试版的麻将游戏,涉及机器人出牌和胡牌这些东西,想做个笔记,记录一下。
- 机器人出牌
- 分析牌型
- 主要逻辑源码
- 附图
机器人出牌
机器人的基础AI有三个基础准则:
- 有杠先杠
- 有碰就碰
- 有番打番
梳理下大概的出牌逻辑框架
一共分为两大步骤
分析牌型
这里主要做的是,把同花色中不满足条件的挑选出来,放入一个数组里。
出牌分析
根据已有的可打的数组牌,根据场上的情况,做一些调整,然后打出相对比较好的牌。
分析牌型
隔两张的单牌 (112 5 8899)
四连顺 - 孤 (0 2345 0)
隔一张的单排 (123 5 78)
顺子的余牌 (1123,5667)
(112,334,566)
返回所有非刻非顺的牌
主要逻辑源码
do { // 有杠先杠 { for (unsigned char i = 0, s = 0; i < MAX_INDEX; ++i) { s = pmj->index(i); if (s == 4) { // 检测若在听牌的情况下,如果杠了 是否还能听牌, 杠了是不是牌型会变的更差 int i = 0; *out_card = SRAnalysis::switchToCardData(s); *out_card_count = 4; return WIK_GANG; } } } // 有单独的风牌则打风牌 { std::vector<int> vec_index; for (int idx = 0; (idx = pmj->getFanPaiOne(idx)) != -1; ++idx) { vec_index.push_back(idx); } if (!vec_index.empty()) { int i = rand() % vec_index.size(); int temp = vec_index.at(i); // 快速切牌判断 for (int i = 0; i < 4; ++i) { if (mahjong_[i] == nullptr && i == (int)direction_) continue; // 风有好几张,先打别人能碰的,以达到快速切牌的效果 for (auto idx : vec_index) { if (2 <= mahjong_[i]->have(SRAnalysis::switchToCardData(idx))) { temp = idx; } } } *out_card = SRAnalysis::switchToCardData(temp); *out_card_count = 1; break; } } // 分析花牌 { // 获得牌型 unsigned char card_index[MAX_INDEX] = {}; for (int i = 0; i < MAX_INDEX; ++i) card_index[i] = pmj->index(i); // 开始分析 { std::vector<int> vec_index; // 牌型解析 { int huapai_weight = 0; for (int i = 0; i < 3; ++i) { // 存放下标的数组 unsigned char temp_card_index[MAX_COUNT] = {}; char temp_count = 0; // 分析当前区间的花牌 int temp_weight = SRAnalysis::analysisHuaPai(&card_index[i * 9], &card_index[i * 9 + 9], temp_card_index, &temp_count); // 先分析最高出牌权重的麻将 if (temp_weight > huapai_weight) { huapai_weight = temp_weight; vec_index.clear(); } // 将花牌的下标存入容器 for (int n = 0; n < temp_count; ++n) vec_index.push_back((temp_card_index[n] + i * 9)); } } // 分析最佳出牌 { if (!vec_index.empty()) { int temp_i = rand() % vec_index.size(); int temp_index = vec_index.at(temp_i); // 转移连牌 如 12 34 此类 std::vector<int> vec_shun_index; { for (int i = 0; i < vec_index.size(); ++i) { // 若下标[i+1] 与 下标 [i] 相邻,则转移 if (i != 0 && vec_index.at(i - 1) + 1 == vec_index.at(i) && (vec_index.at(i - 1) % 9 > vec_index.at(i) % 9)) { vec_shun_index.push_back(vec_index.at(i)); vec_shun_index.push_back(vec_index.at(i - 1)); auto iter = vec_index.begin(); iter += (i - 1); iter = vec_index.erase(iter); vec_index.erase(iter); } } // 默认出 12 34 顺牌 if (!vec_shun_index.empty()) { temp_index = vec_shun_index.at(rand() % vec_shun_index.size()); } } // 转移将牌 std::vector<int> vec_double_index; { for (auto iter = vec_index.begin(); iter != vec_index.end();) { if (2 <= pmj->index(*iter)) { vec_double_index.push_back(*iter); iter = vec_index.erase(iter); } else { ++iter; } } // 若将牌不是唯一且,没有散顺可出,则默认出将牌 if (vec_double_index.size() > 1 && vec_shun_index.empty()) temp_index = vec_double_index.at( rand() % vec_double_index.size()); } // 如果还有单牌,则默认出单牌 if (!vec_index.empty()) { temp_index = vec_index.at( rand() % vec_index.size()); } // 判断快速切牌 if (roundNumber_ <= 6 && roundNumber_ >= 0) { // 快速切牌判断 int sign_index = 0; for (int i = (int)enDirection::South; i <= (int)enDirection::East; ++i) { if (mahjong_[i] == nullptr || i == (int)direction_) continue; // 查看玩家拥有的牌型 for (auto idx : vec_index) { if (2 == mahjong_[i]->have( SRAnalysis::switchToCardData(idx))) { sign_index = idx; } } } // 判断是否有附和切牌标准的牌型 if (sign_index != 0 && temp_index != sign_index) { (*out_card) = SRAnalysis::switchToCardData(sign_index); (*out_card_count) = 1; break; } } // end 快速切牌判断结束 // 遍历检查幺九牌型 for (auto x : vec_index) { const int& temp = x % 9; if (temp <= 1 || temp >= 7) { temp_index = x; break; } } (*out_card) = SRAnalysis::switchToCardData(temp_index); (*out_card_count) = 1; break; } } } } return -1; } while (false);
附图
阅读全文
0 0
- 麻将Ai的出牌逻辑
- 麻将惹出的赔了夫人又折兵
- node.js——麻将算法(六)简易版麻将出牌AI1.0
- node.js——麻将算法(七)简易版麻将出牌AI2.0
- 麻将AI算法(下)
- 麻将的胡牌算法
- 麻将胡牌的算法
- 斗地主游戏AI出牌
- 麻将游戏数据结构和AI算法
- 麻将游戏结构与AI算法
- 麻将听牌的算法(java)
- 带百搭的麻将胡牌判断算法
- 麻将游戏的听牌算法
- 麻将胡牌算法的Java实现
- Java实现的麻将胡牌算法
- 麻将出牌时检测孤立的牌
- 惊!Facebook的AI机器人发展出了自己的语言,AI要觉醒吗?
- 斗地主智能(AI)出牌算法
- Elasticsearch索引迁移的三种方式
- 高德地图----逆向地理编码(将经度纬度转换地址)
- 自动化测试(python+selenium)入门(二)
- 解决点击EditText不弹出键盘,但现实光标闪烁的问题
- List使用add方法添加数据时的覆盖问题
- 麻将Ai的出牌逻辑
- 使用akka框架编写RPC框架
- markdown编辑器
- CSDN_Blog开通
- 手动杆
- nyoj32 组合数
- Tarjan缩环的好方法
- java单列模式---双重检校性--举哥
- 调试win系统下部署在tomcat的应用