本章实现了上一章提到的检查当前是否只是一手牌函数ins_SurCardsType


  1. /*
  2. 检查剩余的牌是否只是一手牌

  3. 是: 返回手牌类型数据
  4. 不是:返回错误类型(cgERROR)
  5. */
  6. CardGroupData ins_SurCardsType(int arr[]);




输入很简单,就是一个状态数组。输出是手牌类型结构



  1. //牌型组合数据结构
  2. struct CardGroupData
  3. {
  4. //枚举类型
  5. CardGroupType cgType=cgERROR;
  6. //该牌的价值
  7. int nValue=0;
  8. //含牌的个数
  9. int nCount=0;
  10. //牌中决定大小的牌值,用于对比
  11. int nMaxCard=0;

  12. };




其中  cgType通过枚举获取,nValue计算规则参考第四章权值定义,nCount可以通过引入数组算出,nMaxCard是用于比大小的那个牌值。


首先我们要计算出剩余手牌个数,因为这样便于快速筛选分支。


  1. int nCount = 0;
  2. for (int i = 3; i < 18; i++)
  3. {
  4. nCount += arr[i];
  5. }

  6. CardGroupData retCardGroupData;
  7. retCardGroupData.nCount = nCount;



以单牌为例,若该牌型满足单牌,则nCount==1,然后我们再找出那张牌。



  1. //单牌类型
  2. if (nCount == 1)
  3. {
  4. //用于验证的变量
  5. int prov = 0;
  6. int SumValue = 0;
  7. for (int i = 3; i < 18; i++)
  8. {
  9. if (arr[i] == 1)
  10. {
  11. SumValue = i - 10;
  12. prov++;
  13. retCardGroupData.nMaxCard = i;
  14. }
  15. }
  16. if (prov == 1)
  17. {
  18. retCardGroupData.cgType = cgSINGLE;
  19. retCardGroupData.nValue= SumValue;
  20. return retCardGroupData;
  21. }
  22. }




对牌,三牌,炸弹同理。


三带一的话需要设置两个验证变量,例如三带一单


  1. if (nCount == 4)
  2. {
  3. //用于验证的变量
  4. int prov1 = 0;
  5. int prov2 = 0;
  6. int SumValue = 0;
  7. for (int i = 3; i < 18; i++)
  8. {
  9. if (arr[i] == 3)
  10. {
  11. SumValue = i - 10;
  12. prov1++;
  13. retCardGroupData.nMaxCard = i;

  14. }
  15. if (arr[i] == 1)
  16. {
  17. prov2++;
  18. }

  19. }
  20. if (prov1 == 1 && prov2 == 1)
  21. {
  22. retCardGroupData.cgType = cgTHREE_TAKE_ONE;
  23. retCardGroupData.nValue = SumValue;
  24. return retCardGroupData;
  25. }
  26. }



三带一对



  1. if (nCount == 5)
  2. {
  3. //用于验证的变量
  4. int prov1 = 0;
  5. int prov2 = 0;
  6. int SumValue = 0;
  7. for (int i = 3; i < 16; i++)
  8. {
  9. if (arr[i] == 3)
  10. {
  11. SumValue = i - 10;
  12. prov1++;
  13. retCardGroupData.nMaxCard = i;

  14. }
  15. if (arr[i] == 2)
  16. {
  17. prov2++;

  18. }
  19. }




这里我们看,循环改为3~15,因为三牌、对牌是不包括王的。


四带二同理,不过四带二要考虑到带出去的那两张牌型是不是相同


  1. if (nCount == 6)
  2. {
  3. //用于验证的变量
  4. int prov1 = 0;
  5. int prov2 = 0;
  6. int SumValue = 0;
  7. for (int i = 3; i < 18; i++)
  8. {
  9. if (arr[i] == 4)
  10. {
  11. SumValue = (i - 3) / 2;
  12. prov1++;
  13. retCardGroupData.nMaxCard = i;

  14. }
  15. if (arr[i] == 1|| arr[i] == 2)
  16. {
  17. prov2+= arr[i];
  18. }
  19. }

  20. if (prov1 == 1 && prov2 == 2)
  21. {
  22. retCardGroupData.cgType = cgFOUR_TAKE_ONE;
  23. retCardGroupData.nValue = SumValue;
  24. return retCardGroupData;
  25. }
  26. }



判断顺子的话用一个变量记录长度,若当前i值等于0并且之前存在i大于0的情况下,即这个长度就是顺子的长度


例如单连:


  1. if (nCount >= 5)
  2. {
  3. //用于验证的变量
  4. int prov = 0;
  5. int SumValue = 0;
  6. int i;
  7. for (i = 3; i < 15; i++)
  8. {
  9. if (arr[i] == 1)
  10. {
  11. prov++;
  12. }
  13. else
  14. {
  15. if (prov != 0)
  16. {
  17. break;
  18. }

  19. }
  20. }
  21. SumValue = i - 10;

  22. if (prov == nCount)
  23. {
  24. retCardGroupData.nMaxCard = i-1;
  25. retCardGroupData.cgType = cgSINGLE_LINE;
  26. retCardGroupData.nValue = SumValue;
  27. return retCardGroupData;
  28. }
  29. }




王炸就更好判断了,直接判断arr[17]和arr[16]就好了



下面贴出完整代码:



  1. /*
  2. 检查剩余的牌是否只是一手牌

  3. 是: 返回手牌类型数据
  4. 不是:返回错误类型(cgERROR)
  5. */
  6. CardGroupData ins_SurCardsType(int arr[])
  7. {

  8. int nCount = 0;
  9. for (int i = 3; i < 18; i++)
  10. {
  11. nCount += arr[i];
  12. }

  13. CardGroupData retCardGroupData;
  14. retCardGroupData.nCount = nCount;


  15. //单牌类型
  16. if (nCount == 1)
  17. {
  18. //用于验证的变量
  19. int prov = 0;
  20. int SumValue = 0;
  21. for (int i = 3; i < 18; i++)
  22. {
  23. if (arr[i] == 1)
  24. {
  25. SumValue = i - 10;
  26. prov++;
  27. retCardGroupData.nMaxCard = i;
  28. }
  29. }
  30. if (prov == 1)
  31. {
  32. retCardGroupData.cgType = cgSINGLE;
  33. retCardGroupData.nValue= SumValue;
  34. return retCardGroupData;
  35. }
  36. }
  37. //对牌类型
  38. if (nCount == 2)
  39. {
  40. //用于验证的变量
  41. int prov = 0;
  42. int SumValue = 0;
  43. int i = 0;
  44. for (i = 3; i < 16; i++)
  45. {
  46. if (arr[i] == 2)
  47. {
  48. SumValue = i - 10;
  49. prov++;
  50. retCardGroupData.nMaxCard = i;
  51. }
  52. }
  53. if (prov == 1)
  54. {
  55. retCardGroupData.cgType = cgDOUBLE;
  56. retCardGroupData.nValue = SumValue;
  57. return retCardGroupData;
  58. }
  59. }
  60. //三条类型
  61. if (nCount == 3)
  62. {
  63. //用于验证的变量
  64. int prov = 0;
  65. int SumValue = 0;
  66. int i = 0;
  67. for (i = 3; i < 16; i++)
  68. {
  69. if (arr[i] == 3)
  70. {
  71. SumValue = i - 10;
  72. prov++;
  73. retCardGroupData.nMaxCard = i;
  74. }
  75. }
  76. if (prov == 1)
  77. {
  78. retCardGroupData.cgType = cgTHREE;
  79. retCardGroupData.nValue = SumValue;
  80. return retCardGroupData;
  81. }
  82. }
  83. //三带一单
  84. if (nCount == 4)
  85. {
  86. //用于验证的变量
  87. int prov1 = 0;
  88. int prov2 = 0;
  89. int SumValue = 0;
  90. for (int i = 3; i < 18; i++)
  91. {
  92. if (arr[i] == 3)
  93. {
  94. SumValue = i - 10;
  95. prov1++;
  96. retCardGroupData.nMaxCard = i;

  97. }
  98. if (arr[i] == 1)
  99. {
  100. prov2++;
  101. }

  102. }
  103. if (prov1 == 1 && prov2 == 1)
  104. {
  105. retCardGroupData.cgType = cgTHREE_TAKE_ONE;
  106. retCardGroupData.nValue = SumValue;
  107. return retCardGroupData;
  108. }
  109. }
  110. //三带一对
  111. if (nCount == 5)
  112. {
  113. //用于验证的变量
  114. int prov1 = 0;
  115. int prov2 = 0;
  116. int SumValue = 0;
  117. for (int i = 3; i < 16; i++)
  118. {
  119. if (arr[i] == 3)
  120. {
  121. SumValue = i - 10;
  122. prov1++;
  123. retCardGroupData.nMaxCard = i;

  124. }
  125. if (arr[i] == 2)
  126. {
  127. prov2++;

  128. }
  129. }
  130. if (prov1 == 1 && prov2 == 1)
  131. {
  132. retCardGroupData.cgType = cgTHREE_TAKE_TWO;
  133. retCardGroupData.nValue = SumValue;
  134. return retCardGroupData;
  135. }
  136. }
  137. //四带两单
  138. if (nCount == 6)
  139. {
  140. //用于验证的变量
  141. int prov1 = 0;
  142. int prov2 = 0;
  143. int SumValue = 0;
  144. for (int i = 3; i < 18; i++)
  145. {
  146. if (arr[i] == 4)
  147. {
  148. SumValue = (i - 3) / 2;
  149. prov1++;
  150. retCardGroupData.nMaxCard = i;

  151. }
  152. if (arr[i] == 1|| arr[i] == 2)
  153. {
  154. prov2+= arr[i];
  155. }
  156. }

  157. if (prov1 == 1 && prov2 == 2)
  158. {
  159. retCardGroupData.cgType = cgFOUR_TAKE_ONE;
  160. retCardGroupData.nValue = SumValue;
  161. return retCardGroupData;
  162. }
  163. }
  164. //四带两对
  165. if (nCount == 8)
  166. {
  167. //用于验证的变量
  168. int prov1 = 0;
  169. int prov2 = 0;
  170. int SumValue = 0;
  171. for (int i = 3; i < 16; i++)
  172. {
  173. if (arr[i] == 4)
  174. {
  175. SumValue = (i - 3) / 2;

  176. prov1++;
  177. retCardGroupData.nMaxCard = i;
  178. }
  179. if (arr[i] == 2|| arr[i] == 4)
  180. {
  181. prov2+= arr[i]/2;

  182. }
  183. }
  184. //注意这里prov2==4因为四牌也是两个对
  185. if (prov1 == 1 && prov2 == 4)
  186. {
  187. retCardGroupData.cgType = cgFOUR_TAKE_TWO;
  188. retCardGroupData.nValue = SumValue;
  189. return retCardGroupData;
  190. }
  191. }
  192. //炸弹类型
  193. if (nCount == 4)
  194. {
  195. //用于验证的变量
  196. int prov = 0;
  197. int SumValue = 0;
  198. for (int i = 3; i < 16; i++)
  199. {
  200. if (arr[i] == 4)
  201. {
  202. SumValue += i - 3 + 7;
  203. prov++;
  204. retCardGroupData.nMaxCard = i;
  205. }
  206. }
  207. if (prov == 1)
  208. {
  209. retCardGroupData.cgType = cgBOMB_CARD;
  210. retCardGroupData.nValue = SumValue;
  211. return retCardGroupData;
  212. }
  213. }
  214. //王炸类型
  215. if (nCount == 2)
  216. {
  217. int SumValue = 0;
  218. if (arr[17] > 0 && arr[16] > 0)
  219. {
  220. SumValue = 20;
  221. retCardGroupData.nMaxCard = 17;
  222. retCardGroupData.cgType = cgKING_CARD;
  223. retCardGroupData.nValue = SumValue;
  224. return retCardGroupData;
  225. }
  226. }
  227. //单连类型
  228. if (nCount >= 5)
  229. {
  230. //用于验证的变量
  231. int prov = 0;
  232. int SumValue = 0;
  233. int i;
  234. for (i = 3; i < 15; i++)
  235. {
  236. if (arr[i] == 1)
  237. {
  238. prov++;
  239. }
  240. else
  241. {
  242. if (prov != 0)
  243. {
  244. break;
  245. }

  246. }
  247. }
  248. SumValue = i - 10;

  249. if (prov == nCount)
  250. {
  251. retCardGroupData.nMaxCard = i-1;
  252. retCardGroupData.cgType = cgSINGLE_LINE;
  253. retCardGroupData.nValue = SumValue;
  254. return retCardGroupData;
  255. }
  256. }
  257. //对连类型
  258. if (nCount >= 6)
  259. {
  260. //用于验证的变量
  261. int prov = 0;
  262. int SumValue = 0;
  263. int i;
  264. for (i = 3; i < 15; i++)
  265. {
  266. if (arr[i] == 2)
  267. {
  268. prov++;
  269. }
  270. else
  271. {
  272. if (prov != 0)
  273. {
  274. break;
  275. }

  276. }
  277. }
  278. SumValue = i - 10;

  279. if (prov * 2 == nCount)
  280. {
  281. retCardGroupData.nMaxCard = i - 1;
  282. retCardGroupData.cgType = cgDOUBLE_LINE;
  283. retCardGroupData.nValue = SumValue;
  284. return retCardGroupData;
  285. }
  286. }
  287. //三连类型
  288. if (nCount >= 6)
  289. {
  290. //用于验证的变量
  291. int prov = 0;

  292. int SumValue = 0;
  293. int i;
  294. for (i = 3; i < 15; i++)
  295. {
  296. if (arr[i] == 3)
  297. {
  298. prov++;
  299. }
  300. else
  301. {
  302. if (prov != 0)
  303. {
  304. break;
  305. }

  306. }
  307. }
  308. SumValue = (i - 3) / 2;

  309. if (prov * 3 == nCount)
  310. {
  311. retCardGroupData.nMaxCard = i - 1;
  312. retCardGroupData.cgType = cgTHREE_LINE;
  313. retCardGroupData.nValue = SumValue;
  314. return retCardGroupData;
  315. }
  316. }
  317. //三带一连类型
  318. if (nCount >= 8)
  319. {
  320. //用于验证的变量
  321. int prov1 = 0;
  322. int SumValue = 0;
  323. int i, j;
  324. for (i = 3; i < 15; i++)
  325. {
  326. if (arr[i] >= 3)
  327. {
  328. prov1++;
  329. }
  330. else
  331. {
  332. if (prov1 != 0)
  333. {
  334. break;
  335. }

  336. }
  337. }
  338. SumValue = (i - 3)/2;
  339. if (prov1 * 4 == nCount)
  340. {
  341. retCardGroupData.nMaxCard = i - 1;
  342. retCardGroupData.cgType = cgTHREE_TAKE_ONE_LINE;
  343. retCardGroupData.nValue = SumValue;
  344. return retCardGroupData;
  345. }

  346. }
  347. //三带二连类型
  348. if (nCount >= 10)
  349. {
  350. //用于验证的变量
  351. int prov1 = 0;
  352. int prov2 = 0;
  353. int SumValue = 0;
  354. int i, j;
  355. for (i = 3; i < 15; i++)
  356. {
  357. if (arr[i] == 3)
  358. {
  359. prov1++;
  360. }
  361. else
  362. {
  363. if (prov1 != 0)
  364. {
  365. break;
  366. }
  367. }
  368. }
  369. for (j = 3; j < 16; j++)
  370. {
  371. if (arr[j] == 2|| arr[j] == 4)
  372. {
  373. prov2+= arr[j]/2;
  374. }
  375. }
  376. SumValue = (i - 3) / 2;
  377. if (prov1 == prov2&&prov1 * 5 == nCount)
  378. {
  379. retCardGroupData.nMaxCard = i - 1;
  380. retCardGroupData.cgType = cgTHREE_TAKE_TWO_LINE;
  381. retCardGroupData.nValue = SumValue;
  382. return retCardGroupData;
  383. }
  384. }

  385. retCardGroupData.cgType = cgERROR;
  386. return retCardGroupData;
  387. }

  388. /*
  389. 检查剩余的牌是否只是一手牌(vector重载)

  390. 是: 返回手牌类型数据
  391. 不是:返回错误类型(cgERROR)
  392. */
  393. CardGroupData ins_SurCardsType(vector<int>list)
  394. {
  395. int arr[18];
  396. memset(arr, 0, sizeof(arr));
  397. for (vector<int>::iterator iter = list.begin(); iter != list.end(); iter++)
  398. {
  399. arr[*iter]++;
  400. }
  401. return ins_SurCardsType(arr);
  402. }




怎么样,这么多牌型枚举是不是很头疼?放心吧,接下来的主动出牌算法、被动出牌算法的枚举会更头疼!

斗地主AI算法——第六章の牌型判断_i++

所以~从下一章开始我们就要讲出牌的策略了,首先是被动出牌。