lingyizhong.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. import java.util.ArrayList;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import java.util.stream.IntStream;
  5. public class CanHu {
  6. /**
  7. * 牌数组,索引=牌id,值=牌数量
  8. */
  9. int[] paiArr;
  10. /**
  11. * 剩余牌的数量,只有全部拆完才算胡
  12. */
  13. int lastNum;
  14. /**
  15. * 是否自摸
  16. */
  17. boolean isZiMo;
  18. /**
  19. * 进牌id
  20. */
  21. int fromPaiId;
  22. /**
  23. * 对子的类型
  24. */
  25. public static final int SHUNZI = 1, HUNDUN = 2, KAN = 3, TI = 4, DUIZI = 5, S2710 = 6;
  26. /**
  27. * 占的二进制位数
  28. */
  29. public static final int bitType = 3, bitPai = 5;
  30. /**
  31. * 占的二进制字节
  32. */
  33. public static final int byteType = 0x7, bytePai = 0x1F;//16进制分别代表7和31
  34. /**
  35. * 保存所有可以胡的牌型
  36. */
  37. List<Long> duiList = new ArrayList<Long>();
  38. /**
  39. * 所有可以胡牌型用到的癞子保存在这里
  40. */
  41. List<Integer> laiZiList = new ArrayList<Integer>();
  42. /**
  43. * 牌对应的id,字牌:小一=1...小十=10,大壹=11...大拾=20,王(癞子)=21
  44. */
  45. public static final int MAX_PAI_CNT = 22;
  46. public static final int WANG = 21;
  47. public static final int DA_SHI = 20;
  48. public static final int XIAO_YI = 1;
  49. public CanHu(int[] paiArr, int fromPaiId, boolean isZiMo) {
  50. this.paiArr = paiArr;
  51. this.fromPaiId = fromPaiId;
  52. this.isZiMo = isZiMo;
  53. lastNum = IntStream.of(paiArr).sum();
  54. }
  55. public void takeOffAll() {
  56. long dui = 0;
  57. // 手里有3张以上相同的不可以拆
  58. for (int i = XIAO_YI; i <= DA_SHI; i++) {
  59. if (paiArr[i] >= 3 && i != fromPaiId) {
  60. dui = pushDui(dui, i, paiArr[i] == 3 ? KAN : TI);
  61. lastNum -= paiArr[i];
  62. paiArr[i] = 0;
  63. }
  64. }
  65. takeOffAll(XIAO_YI, dui);
  66. }
  67. public void takeOffAll(int paiId, long dui) {
  68. System.out.println("takeOffAll参数 lastNum "+lastNum+" dui "+dui+" paiId "+paiId);
  69. // 剩余3张以内的 0是拆完了可以胡 1不能胡 2刚好是个将就可以胡
  70. if (lastNum < 3) {
  71. if (lastNum == 0) {
  72. // 能胡
  73. System.out.println("这种方式能胡 "+dui);
  74. duiList.add(dui);
  75. // 保存癞子代替的牌
  76. int laizi = 0;
  77. for (int i = XIAO_YI; i <= DA_SHI; i++) {
  78. for (int j = paiArr[i]; j < 0; j++) {
  79. laizi = laizi << bitPai | i;
  80. }
  81. }
  82. laiZiList.add(laizi);
  83. } else if (lastNum == 2) {
  84. // 剩余2张能否做将
  85. takeOffJiang(dui);
  86. }
  87. return;
  88. }
  89. for (int i = paiId; i <= DA_SHI; i++) {
  90. System.out.println("????===111 "+" i "+i+" dui "+dui);
  91. // 4张相同的
  92. takeOffSame(i, 4, TI, dui);
  93. System.out.println("????===111 "+" i "+i+" dui "+dui);
  94. // 3张相同的
  95. takeOffSame(i, 3, KAN, dui);
  96. System.out.println("????===111 "+" i "+i+" dui "+dui);
  97. // 2710
  98. takeOff2710(i, dui);
  99. System.out.println("????===111 "+" i "+i+" dui "+dui);
  100. // 拆顺子
  101. takeOff123(i, dui);
  102. System.out.println("????===111 "+" i "+i+" dui "+dui);
  103. // 拆混对
  104. takeOffHunDui(i, dui);
  105. System.out.println("????===111 "+" i "+i+" dui "+dui);
  106. }
  107. }
  108. public void takeOffJiang(long dui) {
  109. System.out.println("拆分将,剩余2张能否做将 dui "+dui);
  110. int wangNum = paiArr[WANG];
  111. int paiNum = 2 - wangNum;
  112. paiArr[WANG] = 0;
  113. for (int i = XIAO_YI; i <= DA_SHI; i++) {
  114. if (paiArr[i] == paiNum) {
  115. paiArr[i] -= 2;
  116. lastNum -= 2;
  117. takeOffAll(MAX_PAI_CNT, pushDui(dui, i, DUIZI));
  118. paiArr[i] += 2;
  119. lastNum += 2;
  120. }
  121. }
  122. paiArr[WANG] += wangNum;
  123. }
  124. public void takeOffSame(int i, int cnt, int type, long dui) {
  125. System.out.println("拆分相同的, "+" i "+i+" cnt "+cnt+" type "+type+" dui "+dui);
  126. if (paiArr[i] + paiArr[WANG] >= cnt) {
  127. int needWang = cnt - paiArr[i];
  128. if (needWang > 0) {
  129. paiArr[WANG] -= needWang;
  130. }
  131. paiArr[i] -= cnt;
  132. lastNum -= cnt;
  133. takeOffAll(i, pushDui(dui, i, type));
  134. lastNum += cnt;
  135. paiArr[i] += cnt;
  136. if (needWang > 0) {
  137. paiArr[WANG] += needWang;
  138. }
  139. }
  140. }
  141. public void takeOff123(int i, long dui) {
  142. System.out.println("拆分普通顺子 "+" i "+i+" dui "+dui);
  143. // 处理边界的问题,9 10 11变成顺子的问题
  144. int border = (i - 1) % 10;
  145. if (border > 7) {
  146. return;
  147. }
  148. int i1 = i + 1;
  149. int i2 = i + 2;
  150. takeOffSingle(i, i1, i2, SHUNZI, dui);
  151. }
  152. public void takeOff2710(int i, long dui) {
  153. // 只有是2的时候才组合2710
  154. if (i % 10 != 2) {
  155. return;
  156. }
  157. int i1 = i + 5;
  158. int i2 = i + 8;
  159. System.out.println("takeOff2710 "+" i "+i+" i1 "+i1+" i2 "+i2+" S2710 "+S2710+" dui "+dui);
  160. takeOffSingle(i, i1, i2, S2710, dui);
  161. }
  162. public void takeOffSingle(int i, int i1, int i2, int type, long dui) {
  163. int needWang = 0;
  164. if (paiArr[i] < 1)
  165. needWang++;
  166. if (paiArr[i1] < 1)
  167. needWang++;
  168. if (paiArr[i2] < 1)
  169. needWang++;
  170. System.out.println("takeOffSingle111 "+" needWang "+needWang+" this.paiArr[this.WANG] "+paiArr[WANG]+" WANG "+this.WANG+" dui "+dui+" i "+i+" i1 "+i1+" i2 "+i2);
  171. if (paiArr[WANG] >= needWang) {
  172. paiArr[WANG] -= needWang;
  173. paiArr[i]--;
  174. paiArr[i1]--;
  175. paiArr[i2]--;
  176. lastNum -= 3;
  177. System.out.println("takeOffSingle222 "+" needWang "+needWang+" this.paiArr[this.WANG] "+paiArr[WANG]+" this.WANG "+WANG+" dui "+dui+" i "+i+" type "+type);
  178. takeOffAll(i, pushDui(dui, i, type));
  179. lastNum += 3;
  180. paiArr[i]++;
  181. paiArr[i1]++;
  182. paiArr[i2]++;
  183. paiArr[WANG] += needWang;
  184. }
  185. }
  186. public void takeOffHunDui(int i, int relatePai, long dui) {
  187. System.out.println("拆分混对(绞牌)222 "+" i "+i+" relatePai "+relatePai+" dui "+dui);
  188. paiArr[i] -= 2;
  189. paiArr[relatePai]--;
  190. lastNum -= 3;
  191. takeOffAll(i, pushDui(dui, i, HUNDUN));
  192. lastNum += 3;
  193. paiArr[i] += 2;
  194. paiArr[relatePai]++;
  195. }
  196. public void takeOffHunDui(int i, long dui) {
  197. System.out.println("拆分混对(绞牌) "+" i "+i+" dui "+dui);
  198. int relatePai = i > 10 ? i - 10 : i + 10;
  199. if (paiArr[i] >= 1 && paiArr[relatePai] >= 1) {
  200. if (paiArr[i] >= 2) {
  201. takeOffHunDui(i, relatePai, dui);
  202. } else if (paiArr[WANG] >= 1) {
  203. paiArr[WANG]--;
  204. takeOffHunDui(i, relatePai, dui);
  205. paiArr[WANG]++;
  206. }
  207. }
  208. }
  209. public static long pushDui(long dui, int paiId, int type) {
  210. // return (dui << bitType | type) << bitPai | paiId;
  211. System.out.println("pushDui "+" dui "+dui+" paiId " + paiId+" type " + type+" bitType "+bitType+" bitPai "+bitPai);
  212. String typeStr = ""+type+"(";
  213. if(type == 1) typeStr += "顺子";
  214. else if(type == 2) typeStr += "混对";
  215. else if(type == 3) typeStr += "坎";
  216. else if(type == 4) typeStr += "提";
  217. else if(type == 5) typeStr += "对子";
  218. else if(type == 6) typeStr += "27十";
  219. typeStr += ")";
  220. long res = (dui << bitType | type) << bitPai | paiId;
  221. System.out.println("pushDui res "+res+" dui "+dui+" paiId "+paiId+" type "+typeStr+" bitType "+bitType+" bitPai "+bitPai);
  222. return res;
  223. }
  224. public static List<Integer> popDui(long dui) {
  225. int paiId = (int) (dui & bytePai);
  226. int type = (int) (dui >>> bitPai & byteType);
  227. System.out.println("popDui000 dui "+dui+" bitPai "+bitPai+" bytePai "+bytePai+" byteType "+byteType);
  228. System.out.println("popDui111 type "+type+" paiId "+paiId);
  229. switch (type) {
  230. case TI:
  231. return Arrays.asList(paiId, paiId, paiId, paiId);
  232. case KAN:
  233. return Arrays.asList(paiId, paiId, paiId);
  234. case SHUNZI:
  235. return Arrays.asList(paiId, paiId + 1, paiId + 2);
  236. case S2710:
  237. return Arrays.asList(paiId, paiId + 5, paiId + 8);
  238. case HUNDUN:
  239. int relatePai = paiId > 10 ? paiId - 10 : paiId + 10;
  240. return Arrays.asList(paiId, paiId, relatePai);
  241. case DUIZI:
  242. return Arrays.asList(paiId, paiId);
  243. }
  244. return Arrays.asList();
  245. }
  246. public static void main(String[] args) {
  247. // int arr[]={0, 0, 2, 0, 4, 0, 0, 3, 0, 0, 0, 4, 2, 0, 0, 0, 0, 1, 0, 1, 1, 3};
  248. // int map[]= {0, 0, 0, 0, 0, 0, 1, 1, 3, 1, 0, 0, 0, 0, 1, 0, 3, 0, 1, 0, 2, 2};
  249. // int[] map1={1,1,1,21,21};
  250. // int[] map1={14,11,1,10,11,14,21,10,3,16,21,21,16,2,14,11,7,16};
  251. // int[] map1={1,2,3,3,3,13,3,4,5};
  252. // int[] map1={1,2,3,3,3,13};
  253. // int[] map1={15,15,21,21,21};
  254. // int[] map1={6,6,6,8,9,10};
  255. // int[] map1={9,9,9,9,6,6,11,12,13,18,19,20,21,21,21,21};
  256. // int[] map1 = { 1, 2, 3, 4, 11, 12, 13, 14, 14 ,21,21,21};
  257. // int[] map1 = { 1, 2, 3, 4, 1, 4, 11, 12, 13, 14, 11, 14 };
  258. // int[] map1 = { 7, 5, 17, 14, 20, 1, 21, 3, 20, 21, 3, 15, 19, 1, 18, 5, 12, 6, 21, 21, 16 };
  259. // int[] map1 = { 1, 1, 2, 2, 3, 3, 11, 11, 12, 12, 13, 13, 21, 21, 21, 21 };
  260. // int[] map1 = { 1, 1, 2, 2, 3, 3, 11, 11, 12, 12, 13, 13, 20, 20, 20, 20 };
  261. //int[] map1 = { 1, 1, 2, 2, 3, 3, 11, 11, 12, 12, 13, 13, 20, 20, 20, 17,18,19 };
  262. //int[] map1 = {19,19,19,9,9,9,12,17,20,1,2,3,4,5,6,7,14,14,15,15,8 };
  263. // int[] map1 = {9,9,9,12,17,20,1,2,3,4,5,6,7,14,14,8,8 };
  264. System.out.println("???????? "+((1769152804 << 3 | 6) << 5 | 12));
  265. int[] map1 = {1,2,3,4,5,6,7,8,9,9,9,12,14,14,15,15,17,19,19,19,20};
  266. System.out.println("map1-> " + map1.length +" : "+ Arrays.toString(map1));
  267. int[] map = new int[MAX_PAI_CNT];//[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
  268. System.out.println("map初始值 " + map.length +" : " + Arrays.toString(map));
  269. for (int i = 0; i < map1.length; i++) {
  270. // System.out.println("map->" + map[i]);
  271. map[map1[i]]++;//为了统计每个牌值的张数
  272. // System.out.println("map->============= " + map[i]);
  273. }
  274. System.out.println("map-> " + map.length +" : " + Arrays.toString(map));
  275. // int[] map = { 0, 0, 0, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
  276. CanHu hu = new CanHu(map, 0, true);
  277. long t = System.currentTimeMillis();//1723081942670
  278. System.out.println("t-> " + t);
  279. hu.takeOffAll();
  280. System.out.println("|耗时->" + (System.currentTimeMillis() - t) + "|hu.duiList.size()结果->" + hu.duiList.size());
  281. System.out.println("下面是hu.duiList "+byteType +" "+bytePai);
  282. System.out.println(hu.duiList);
  283. System.out.println("下面是???111");
  284. hu.duiList.stream().map(dui -> {
  285. System.out.println("这是 dui "+dui);
  286. ArrayList<List<Integer>> duilist = new ArrayList<List<Integer>>();
  287. while (dui > 0) {
  288. System.out.println("这是000 dui "+dui+" bitPai "+bitPai+" bitType "+bitType);
  289. duilist.add(popDui(dui));
  290. System.out.println("这是111 dui "+dui+" bitPai "+bitPai+" bitType "+bitType);
  291. dui >>>= (bitPai + bitType);
  292. System.out.println("这是222 dui "+dui+" bitPai "+bitPai+" bitType "+bitType);
  293. }
  294. return duilist;
  295. }).forEach(System.out::println);
  296. System.out.println("下面是???222");
  297. hu.laiZiList.forEach(laizi -> {
  298. while (laizi > 0) {
  299. System.out.print((laizi & bytePai) + "|=====");
  300. laizi >>>= bitPai;
  301. }
  302. System.out.println("下面是???333");
  303. System.out.println("-----");
  304. });
  305. System.out.println("下面是???444 "+hu.pushDui(1769152804,12,6)+" "+hu.pushDui(1931551948,12,6));
  306. System.out.println("???????? "+((1769152804 << 3 | 6) << 5 | 12));
  307. System.out.println("下面是???666 "+hu.pushDui(1769152804,12,6)+" "+hu.pushDui(1931551948,12,6));
  308. }
  309. }