斗地主AI算法——第十三章の主动出牌(2)

上一章我们已经搭好了出牌算法的基本框架,本章主要实现优先处理的三带、飞机等牌型。

首先定义一些基本变量:


 
  1. //暂存最佳的价值
  2. HandCardValue BestHandCardValue;
  3. BestHandCardValue.NeedRound = 20;
  4. BestHandCardValue.SumValue = MinCardsValue;
  5. //我们认为不出牌的话会让对手一个轮次,即加一轮(权值减少7)便于后续的对比参考。
  6. BestHandCardValue.NeedRound += 1;
  7. //暂存最佳的组合
  8. CardGroupData BestCardGroup;
  9. //带出去的牌
  10. int tmp_1 = 0;
  11. int tmp_2 = 0;
  12. int tmp_3 = 0;
  13. int tmp_4 = 0;

因为枚举了牌型,所以实际和被动出牌逻辑都差不多,且没有nMaxCard的限制,所以我们要从3开始遍历。且上一章我们提到,不考虑炸弹拆分的情况。故value_aHandCardList[i]不能等于4。


 
  1. for ( int i = 3; i < 16; i++)
  2. {
  3. //2.0版本策略主动出牌不拆分炸弹,朕自己从来就不打四带二,因为浪
  4. if (clsHandCardData.value_aHandCardList[i] != 4)
  5. {
  6. //出三带一
  7. if (clsHandCardData.value_aHandCardList[i] > 2)
  8. {
  9. clsHandCardData.value_aHandCardList[i] -= 3;
  10. for ( int j = 3; j < 18; j++)
  11. {
  12. if (clsHandCardData.value_aHandCardList[j] > 0 )
  13. {
  14. clsHandCardData.value_aHandCardList[j] -= 1;
  15. clsHandCardData.nHandCardCount -= 4;
  16. HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
  17. clsHandCardData.value_aHandCardList[j] += 1;
  18. clsHandCardData.nHandCardCount += 4;
  19. //选取总权值-轮次*7值最高的策略 因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正
  20. if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))
  21. {
  22. BestHandCardValue = tmpHandCardValue;
  23. BestCardGroup = get_GroupData(cgTHREE_TAKE_ONE, i, 4);
  24. tmp_1 = j;
  25. }
  26. }
  27. }
  28. clsHandCardData.value_aHandCardList[i] += 3;
  29. }
  30. //出三带二
  31. if (clsHandCardData.value_aHandCardList[i] > 2)
  32. {
  33. for ( int j = 3; j < 16; j++)
  34. {
  35. clsHandCardData.value_aHandCardList[i] -= 3;
  36. if (clsHandCardData.value_aHandCardList[j] > 1)
  37. {
  38. clsHandCardData.value_aHandCardList[j] -= 2;
  39. clsHandCardData.nHandCardCount -= 5;
  40. HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
  41. clsHandCardData.value_aHandCardList[j] += 2;
  42. clsHandCardData.nHandCardCount += 5;
  43. //选取总权值-轮次*7值最高的策略 因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正
  44. if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))
  45. {
  46. BestHandCardValue = tmpHandCardValue;
  47. BestCardGroup = get_GroupData(cgTHREE_TAKE_TWO, i, 5);
  48. tmp_1 = j;
  49. }
  50. }
  51. clsHandCardData.value_aHandCardList[i] += 3;
  52. }
  53. }
  54. //出四带二单
  55. if (clsHandCardData.value_aHandCardList[i] > 3)
  56. {
  57. //2.0版本策略主动出牌不拆分炸弹,朕自己从来就不打四带二,因为浪
  58. }
  59. //出四带二对
  60. if (clsHandCardData.value_aHandCardList[i] > 3)
  61. {
  62. //2.0版本策略主动出牌不拆分炸弹,朕自己从来就不打四带二,因为浪
  63. }
  64. //出三带一单连
  65. if (clsHandCardData.value_aHandCardList[i] > 2)
  66. {
  67. int prov = 0;
  68. for ( int j = i; j < 15; j++)
  69. {
  70. if (clsHandCardData.value_aHandCardList[j] > 2)
  71. {
  72. prov++;
  73. }
  74. else
  75. {
  76. break;
  77. }
  78. /*本来想做全排列选取带出的牌然后枚举出最高价值的,但考虑到当飞机长度也就是在2-4之间
  79. 所以干脆做三个分支处理算了*/
  80. //为两连飞机
  81. if (prov == 2)
  82. {
  83. for ( int k = i; k <= j; k++)
  84. {
  85. clsHandCardData.value_aHandCardList[k] -= 3;
  86. }
  87. clsHandCardData.nHandCardCount -= prov * 4;
  88. for ( int tmp1 = 3; tmp1 < 18; tmp1++)
  89. {
  90. if (clsHandCardData.value_aHandCardList[tmp1] > 0 )
  91. {
  92. clsHandCardData.value_aHandCardList[tmp1] -= 1;
  93. for ( int tmp2 = tmp1; tmp2 < 18; tmp2++)
  94. {
  95. if (clsHandCardData.value_aHandCardList[tmp2] > 0 )
  96. {
  97. clsHandCardData.value_aHandCardList[tmp2] -= 1;
  98. HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
  99. if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))
  100. {
  101. BestHandCardValue = tmpHandCardValue;
  102. BestCardGroup = get_GroupData(cgTHREE_TAKE_ONE_LINE, j, prov * 4);
  103. tmp_1 = tmp1;
  104. tmp_2 = tmp2;
  105. }
  106. clsHandCardData.value_aHandCardList[tmp2] += 1;
  107. }
  108. }
  109. clsHandCardData.value_aHandCardList[tmp1] += 1;
  110. }
  111. }
  112. for ( int k = i; k <= j; k++)
  113. {
  114. clsHandCardData.value_aHandCardList[k] += 3;
  115. }
  116. clsHandCardData.nHandCardCount += prov * 4;
  117. }
  118. //为三连飞机
  119. if (prov == 3)
  120. {
  121. for ( int k = i; k <= j; k++)
  122. {
  123. clsHandCardData.value_aHandCardList[k] -= 3;
  124. }
  125. clsHandCardData.nHandCardCount -= prov * 4;
  126. for ( int tmp1 = 3; tmp1 < 18; tmp1++)
  127. {
  128. if (clsHandCardData.value_aHandCardList[tmp1] > 0 )
  129. {
  130. clsHandCardData.value_aHandCardList[tmp1] -= 1;
  131. for ( int tmp2 = tmp1; tmp2 < 18; tmp2++)
  132. {
  133. if (clsHandCardData.value_aHandCardList[tmp2] > 0 )
  134. {
  135. clsHandCardData.value_aHandCardList[tmp2] -= 1;
  136. for ( int tmp3 = tmp2; tmp3 < 18; tmp3++)
  137. {
  138. if (clsHandCardData.value_aHandCardList[tmp3] > 0 )
  139. {
  140. clsHandCardData.value_aHandCardList[tmp3] -= 1;
  141. HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
  142. if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))
  143. {
  144. BestHandCardValue = tmpHandCardValue;
  145. BestCardGroup = get_GroupData(cgTHREE_TAKE_ONE_LINE, j, prov * 4);
  146. tmp_1 = tmp1;
  147. tmp_2 = tmp2;
  148. tmp_3 = tmp3;
  149. }
  150. clsHandCardData.value_aHandCardList[tmp3] += 1;
  151. }
  152. }
  153. clsHandCardData.value_aHandCardList[tmp2] += 1;
  154. }
  155. }
  156. clsHandCardData.value_aHandCardList[tmp1] += 1;
  157. }
  158. }
  159. for ( int k = i; k <= j; k++)
  160. {
  161. clsHandCardData.value_aHandCardList[k] += 3;
  162. }
  163. clsHandCardData.nHandCardCount += prov * 4;
  164. }
  165. //为四连飞机
  166. if (prov == 4)
  167. {
  168. for ( int k = i; k <= j; k++)
  169. {
  170. clsHandCardData.value_aHandCardList[k] -= 3;
  171. }
  172. clsHandCardData.nHandCardCount -= prov * 4;
  173. for ( int tmp1 = 3; tmp1 < 18; tmp1++)
  174. {
  175. if (clsHandCardData.value_aHandCardList[tmp1] > 0 )
  176. {
  177. clsHandCardData.value_aHandCardList[tmp1] -= 1;
  178. for ( int tmp2 = tmp1; tmp2 < 18; tmp2++)
  179. {
  180. if (clsHandCardData.value_aHandCardList[tmp2] > 0 )
  181. {
  182. clsHandCardData.value_aHandCardList[tmp2] -= 1;
  183. for ( int tmp3 = tmp2; tmp3 < 18; tmp3++)
  184. {
  185. if (clsHandCardData.value_aHandCardList[tmp3] > 0 )
  186. {
  187. clsHandCardData.value_aHandCardList[tmp3] -= 1;
  188. for ( int tmp4 = tmp3; tmp4 < 18; tmp4++)
  189. {
  190. if (clsHandCardData.value_aHandCardList[tmp4] > 0 )
  191. {
  192. clsHandCardData.value_aHandCardList[tmp4] -= 1;
  193. HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
  194. if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))
  195. {
  196. BestHandCardValue = tmpHandCardValue;
  197. BestCardGroup = get_GroupData(cgTHREE_TAKE_ONE_LINE, j, prov * 4);
  198. tmp_1 = tmp1;
  199. tmp_2 = tmp2;
  200. tmp_3 = tmp3;
  201. tmp_4 = tmp4;
  202. }
  203. clsHandCardData.value_aHandCardList[tmp4] += 1;
  204. }
  205. }
  206. clsHandCardData.value_aHandCardList[tmp3] += 1;
  207. }
  208. }
  209. clsHandCardData.value_aHandCardList[tmp2] += 1;
  210. }
  211. }
  212. clsHandCardData.value_aHandCardList[tmp1] += 1;
  213. }
  214. }
  215. for ( int k = i; k <= j; k++)
  216. {
  217. clsHandCardData.value_aHandCardList[k] += 3;
  218. }
  219. clsHandCardData.nHandCardCount += prov * 4;
  220. }
  221. //若prov==5,则是地主可以直接出去,在剪枝部分已经处理
  222. }
  223. }
  224. //出三带一双连
  225. if (clsHandCardData.value_aHandCardList[i] > 2)
  226. {
  227. int prov = 0;
  228. for ( int j = i; j < 15; j++)
  229. {
  230. if (clsHandCardData.value_aHandCardList[j] > 2 )
  231. {
  232. prov++;
  233. }
  234. else
  235. {
  236. break;
  237. }
  238. /*本来想做全排列选取带出的牌然后枚举出最高价值的,但考虑到当飞机长度也就是在2-4之间
  239. 所以干脆做三个分支处理算了*/
  240. //为两连飞机
  241. if (prov == 2)
  242. {
  243. for ( int k = i; k <= j; k++)
  244. {
  245. clsHandCardData.value_aHandCardList[k] -= 3;
  246. }
  247. clsHandCardData.nHandCardCount -= prov * 5;
  248. for ( int tmp1 = 3; tmp1 < 16; tmp1++)
  249. {
  250. if (clsHandCardData.value_aHandCardList[tmp1] > 1 )
  251. {
  252. clsHandCardData.value_aHandCardList[tmp1] -= 2;
  253. for ( int tmp2 = tmp1; tmp2 < 16; tmp2++)
  254. {
  255. if (clsHandCardData.value_aHandCardList[tmp2] > 1 )
  256. {
  257. clsHandCardData.value_aHandCardList[tmp2] -= 2;
  258. HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
  259. if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))
  260. {
  261. BestHandCardValue = tmpHandCardValue;
  262. BestCardGroup = get_GroupData(cgTHREE_TAKE_TWO_LINE, j, prov * 5);
  263. tmp_1 = tmp1;
  264. tmp_2 = tmp2;
  265. }
  266. clsHandCardData.value_aHandCardList[tmp2] += 2;
  267. }
  268. }
  269. clsHandCardData.value_aHandCardList[tmp1] += 2;
  270. }
  271. }
  272. for ( int k = i; k <= j; k++)
  273. {
  274. clsHandCardData.value_aHandCardList[k] += 3;
  275. }
  276. clsHandCardData.nHandCardCount += prov * 5;
  277. }
  278. //为三连飞机
  279. if (prov == 3)
  280. {
  281. for ( int k = i; k <= j; k++)
  282. {
  283. clsHandCardData.value_aHandCardList[k] -= 3;
  284. }
  285. clsHandCardData.nHandCardCount -= prov * 5;
  286. for ( int tmp1 = 3; tmp1 < 16; tmp1++)
  287. {
  288. if (clsHandCardData.value_aHandCardList[tmp1] > 1 )
  289. {
  290. clsHandCardData.value_aHandCardList[tmp1] -= 2;
  291. for ( int tmp2 = tmp1; tmp2 < 16; tmp2++)
  292. {
  293. if (clsHandCardData.value_aHandCardList[tmp2] > 1 )
  294. {
  295. clsHandCardData.value_aHandCardList[tmp2] -= 2;
  296. for ( int tmp3 = tmp2; tmp3 < 16; tmp3++)
  297. {
  298. if (clsHandCardData.value_aHandCardList[tmp3] > 1 )
  299. {
  300. clsHandCardData.value_aHandCardList[tmp3] -= 2;
  301. HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
  302. if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))
  303. {
  304. BestHandCardValue = tmpHandCardValue;
  305. BestCardGroup = get_GroupData(cgTHREE_TAKE_TWO_LINE, j, prov * 5);
  306. tmp_1 = tmp1;
  307. tmp_2 = tmp2;
  308. tmp_3 = tmp3;
  309. }
  310. clsHandCardData.value_aHandCardList[tmp3] += 2;
  311. }
  312. }
  313. clsHandCardData.value_aHandCardList[tmp2] += 2;
  314. }
  315. }
  316. clsHandCardData.value_aHandCardList[tmp1] += 2;
  317. }
  318. }
  319. for ( int k = i; k <= j; k++)
  320. {
  321. clsHandCardData.value_aHandCardList[k] += 3;
  322. }
  323. clsHandCardData.nHandCardCount += prov * 5;
  324. }
  325. //若prov==4,则是地主可以直接出去,在剪枝部分已经处理
  326. }
  327. }
  328. }
  329. }





这个循环结束后,若有好的选择,则BestCardGroup会保留出牌的类型,在循环外进行出牌处理。


 
  1. if (BestCardGroup.cgType == cgTHREE_TAKE_ONE)
  2. {
  3. clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);
  4. clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);
  5. clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);
  6. clsHandCardData.value_nPutCardList.push_back(tmp_1);
  7. clsHandCardData.uctPutCardType = BestCardGroup;
  8. return;
  9. }
  10. else if (BestCardGroup.cgType == cgTHREE_TAKE_TWO)
  11. {
  12. clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);
  13. clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);
  14. clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);
  15. clsHandCardData.value_nPutCardList.push_back(tmp_1);
  16. clsHandCardData.value_nPutCardList.push_back(tmp_1);
  17. clsHandCardData.uctPutCardType = BestCardGroup;
  18. return;
  19. }
  20. else if (BestCardGroup.cgType == cgTHREE_TAKE_ONE_LINE)
  21. {
  22. for ( int j = BestCardGroup.nMaxCard - (BestCardGroup.nCount / 4) + 1; j <= BestCardGroup.nMaxCard; j++)
  23. {
  24. clsHandCardData.value_nPutCardList.push_back(j);
  25. clsHandCardData.value_nPutCardList.push_back(j);
  26. clsHandCardData.value_nPutCardList.push_back(j);
  27. }
  28. if (BestCardGroup.nCount / 4 == 2)
  29. {
  30. clsHandCardData.value_nPutCardList.push_back(tmp_1);
  31. clsHandCardData.value_nPutCardList.push_back(tmp_2);
  32. }
  33. if (BestCardGroup.nCount / 4 == 3)
  34. {
  35. clsHandCardData.value_nPutCardList.push_back(tmp_1);
  36. clsHandCardData.value_nPutCardList.push_back(tmp_2);
  37. clsHandCardData.value_nPutCardList.push_back(tmp_3);
  38. }
  39. if (BestCardGroup.nCount / 4 == 4)
  40. {
  41. clsHandCardData.value_nPutCardList.push_back(tmp_1);
  42. clsHandCardData.value_nPutCardList.push_back(tmp_2);
  43. clsHandCardData.value_nPutCardList.push_back(tmp_3);
  44. clsHandCardData.value_nPutCardList.push_back(tmp_4);
  45. }
  46. clsHandCardData.uctPutCardType = BestCardGroup;
  47. return;
  48. }
  49. else if (BestCardGroup.cgType == cgTHREE_TAKE_TWO_LINE)
  50. {
  51. for ( int j = BestCardGroup.nMaxCard - (BestCardGroup.nCount / 5) + 1; j <= BestCardGroup.nMaxCard; j++)
  52. {
  53. clsHandCardData.value_nPutCardList.push_back(j);
  54. clsHandCardData.value_nPutCardList.push_back(j);
  55. clsHandCardData.value_nPutCardList.push_back(j);
  56. }
  57. if (BestCardGroup.nCount / 5 == 2)
  58. {
  59. clsHandCardData.value_nPutCardList.push_back(tmp_1);
  60. clsHandCardData.value_nPutCardList.push_back(tmp_1);
  61. clsHandCardData.value_nPutCardList.push_back(tmp_2);
  62. clsHandCardData.value_nPutCardList.push_back(tmp_2);
  63. }
  64. if (BestCardGroup.nCount / 5 == 3)
  65. {
  66. clsHandCardData.value_nPutCardList.push_back(tmp_1);
  67. clsHandCardData.value_nPutCardList.push_back(tmp_1);
  68. clsHandCardData.value_nPutCardList.push_back(tmp_2);
  69. clsHandCardData.value_nPutCardList.push_back(tmp_2);
  70. clsHandCardData.value_nPutCardList.push_back(tmp_3);
  71. clsHandCardData.value_nPutCardList.push_back(tmp_3);
  72. }
  73. clsHandCardData.uctPutCardType = BestCardGroup;
  74. return;
  75. }

因为回溯遍历部分与被动出牌完全一样,这里就不再赘述。飞机在出牌阶段的处理比较麻烦,要根据牌数进行判断是几连飞机。


下一章,我们将实现打出当前最小值牌部分。

敬请关注下一章:斗地主AI算法——第十四章の主动出牌(3)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值