斗地主AI算法——第五章の总值计算

本章算是比较重点的一章,前一章已经对各个牌型做出了价值定义,本章主要实现计算手牌总价值模块函数。

根据之前的思路,我们设定一下输入输出:

输入:手牌数据类(主要用手牌个数nHandCardCount以及手牌状态数组clsHandCardData.value_aHandCardList)

输出:手牌价值结构 HandCardValue

 

先处理剪枝部分,如果剩下的手牌是一手牌,我们即直接返回该牌型的价值,这个下一章会写出,我们先假设存在这个函数ins_SurCardsType。

其返回值设计:若是一手牌,返回牌型,若不是一手牌,返回错误牌型。

 

[cpp] view plain copy
 
  1. CardGroupData uctCardGroupData = ins_SurCardsType(clsHandCardData.value_aHandCardList);  
  2. //如果能一次性出去且没有炸弹,因为有炸弹的话权值可能会更大  
  3. if (uctCardGroupData.cgType != cgERROR&& !HasBoom(clsHandCardData.value_aHandCardList))  
  4. {  
  5.     uctHandCardValue.SumValue = uctCardGroupData.nValue;  
  6.     uctHandCardValue.NeedRound = 1;  
  7.     return uctHandCardValue;  
  8. }  

 

若不是一手牌的情况,我们通过get_PutCardList函数(后续几章会写出实现方法)获取最佳的出牌策略 进行出牌,

 

 

[cpp] view plain copy
 
  1. /*只是获取出牌的序列,即clsHandCardData.value_nPutCardList及clsHandCardData.uctPutCardType 
  2.     其他成员均无改变,也不会调用出牌函数,get_PutCardList返回最优方案*/  
  3.     get_PutCardList_2(clsHandCardData);  
  4.   
  5.     //要保存当前的clsHandCardData.value_nPutCardList及clsHandCardData.uctPutCardType用于回溯  
  6.     CardGroupData NowPutCardType = clsHandCardData.uctPutCardType;  
  7.     vector<int> NowPutCardList = clsHandCardData.value_nPutCardList;  
  8.   
  9.     if (clsHandCardData.uctPutCardType.cgType == cgERROR)  
  10.     {  
  11.         cout << "PutCardType ERROR!" << endl;  
  12.     }  

 

 

 

获取完出牌序列后,打出这些牌(只改变value_aHandCardList数组),再计算剩余的牌总价值。

 

 

[cpp] view plain copy
 
  1. for (vector<int>::iterator iter = NowPutCardList.begin();  
  2.         iter != NowPutCardList.end(); iter++)  
  3.     {  
  4.         clsHandCardData.value_aHandCardList[*iter]--;  
  5.     }  
  6.     clsHandCardData.nHandCardCount -= NowPutCardType.nCount;  
  7.     //---回溯↑  
  8.     HandCardValue tmp_SurValue = get_HandCardValue(clsHandCardData);//递归剩余牌价值  
  9.               
  10.     //---回溯↓      
  11.     for (vector<int>::iterator iter = NowPutCardList.begin();  
  12.         iter != NowPutCardList.end(); iter++)  
  13.     {  
  14.         clsHandCardData.value_aHandCardList[*iter]++;  
  15.     }  
  16.     clsHandCardData.nHandCardCount += NowPutCardType.nCount;  
  17.     //---回溯↑  
  18.   
  19.     uctHandCardValue.SumValue = NowPutCardType.nValue + tmp_SurValue.SumValue;  
  20.     uctHandCardValue.NeedRound = tmp_SurValue.NeedRound + 1;  



 

 

最后将返回的价值与当前打出的牌价值相加即时该阶段手牌总价值。

 

 

下面给出完整代码

 

[cpp] view plain copy
 
  1. /* 
  2. 通过回溯dp的方式获取手牌价值 
  3. 与get_PutCardList作为交替递归调用 
  4. 返回:价值结构体HandCardValue 
  5. 权值的计算规则参考头文件评分逻辑思维 
  6. */  
  7.   
  8. HandCardValue get_HandCardValue(HandCardData &clsHandCardData)  
  9. {  
  10.   
  11.     //首先清空出牌队列,因为剪枝时是不调用get_PutCardList的  
  12.     clsHandCardData.ClearPutCardList();  
  13.   
  14.     HandCardValue uctHandCardValue;  
  15.     //出完牌了,其实这种情况只限于手中剩下四带二且被动出牌的情况,因为四带二剪枝做了特殊处理。  
  16.     if (clsHandCardData.nHandCardCount == 0)  
  17.     {  
  18.         uctHandCardValue.SumValue = 0;  
  19.         uctHandCardValue.NeedRound = 0;  
  20.         return uctHandCardValue;  
  21.     }  
  22.     //————以下为剪枝:判断是否可以一手出完牌  
  23.     CardGroupData uctCardGroupData = ins_SurCardsType(clsHandCardData.value_aHandCardList);  
  24.     //————不到万不得已我们都不会出四带二,都尽量保炸弹  
  25.     if (uctCardGroupData.cgType != cgERROR&&uctCardGroupData.cgType != cgFOUR_TAKE_ONE&&uctCardGroupData.cgType != cgFOUR_TAKE_TWO)  
  26.     {  
  27.         uctHandCardValue.SumValue = uctCardGroupData.nValue;  
  28.         uctHandCardValue.NeedRound = 1;  
  29.         return uctHandCardValue;  
  30.     }  
  31.   
  32.     //非剪枝操作,即非一手能出完的牌  
  33.   
  34.     /*只是获取出牌的序列,即clsHandCardData.value_nPutCardList及clsHandCardData.uctPutCardType 
  35.     其他成员均无改变,也不会调用出牌函数,get_PutCardList返回最优方案*/  
  36.     get_PutCardList_2(clsHandCardData);  
  37.   
  38.     //要保存当前的clsHandCardData.value_nPutCardList及clsHandCardData.uctPutCardType用于回溯  
  39.     CardGroupData NowPutCardType = clsHandCardData.uctPutCardType;  
  40.     vector<int> NowPutCardList = clsHandCardData.value_nPutCardList;  
  41.   
  42.     if (clsHandCardData.uctPutCardType.cgType == cgERROR)  
  43.     {  
  44.         cout << "PutCardType ERROR!" << endl;  
  45.     }  
  46.   
  47.   
  48.   
  49.     //---回溯↓  
  50.     for (vector<int>::iterator iter = NowPutCardList.begin();  
  51.         iter != NowPutCardList.end(); iter++)  
  52.     {  
  53.         clsHandCardData.value_aHandCardList[*iter]--;  
  54.     }  
  55.     clsHandCardData.nHandCardCount -= NowPutCardType.nCount;  
  56.     //---回溯↑  
  57.     HandCardValue tmp_SurValue = get_HandCardValue(clsHandCardData);//递归剩余牌价值  
  58.               
  59.     //---回溯↓      
  60.     for (vector<int>::iterator iter = NowPutCardList.begin();  
  61.         iter != NowPutCardList.end(); iter++)  
  62.     {  
  63.         clsHandCardData.value_aHandCardList[*iter]++;  
  64.     }  
  65.     clsHandCardData.nHandCardCount += NowPutCardType.nCount;  
  66.     //---回溯↑  
  67.   
  68.     uctHandCardValue.SumValue = NowPutCardType.nValue + tmp_SurValue.SumValue;  
  69.     uctHandCardValue.NeedRound = tmp_SurValue.NeedRound + 1;  
  70.       
  71.   
  72.   
  73.   
  74.   
  75.     return uctHandCardValue;  
  76.   
  77. }  



 

 

注:当前出牌策略是2.0版本,所以是get_PutCardList_2,后续还会写出更多的版本,敬请期待。

 

如果你之前了解回溯算法的话,那么应该很好理解上述代码,若没有接触过回溯,可以看我以前的博客http://blog.csdn.net/sm9sun/article/details/53244484

 

总值计算的模块就算完成了,其实并没有太多东西,除了一个回溯递归以外就是里面调用了两个函数ins_SurCardsType判断是否是一手牌以及get_PutCardList出牌逻辑。那么下一章我们便要实现这个ins_SurCardsType函数。

 

敬请关注下一章:斗地主AI算法——第六章の牌型判断

posted on   &大飞  阅读(456)  评论(0编辑  收藏  举报

编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示