欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

麻将胡牌逻辑 java

程序员文章站 2022-05-10 21:30:38
...

      最近写了一个麻将的胡牌逻辑,这个麻将是没有万字牌 和 东西南北风牌,以前也写过麻将胡牌逻辑,都没有记录,这次记录一下,方便以后查阅

 

   

/**
	 * 胡牌
	 * @param isZiMo  是否自摸
	 * @param roleId  胡牌玩家
	 * @param pcc     麻将场
	 */
	public static boolean huCard(boolean isZiMo,int roleId,PlayCardContext pcc){
		PlayCardUnit pcu = pcc.getCardUnitByRoleId(roleId);
		
		List<Byte> handCards = pcu.getCards();
		List<OperateCardData> chiPengGangCard = pcu.getChiPengGangCard();
		
		int cardSize = handCards.size();
		//1-9的索引为筒子 11-19为条子 21-23为中发白
		byte[] cards = new byte[24];
		byte[] color = new byte[3];
		
		for (int i = 0; i < cardSize; i++) {
			byte cardId = handCards.get(i);
			SCard card = (SCard) StaticData.getStaticModel(EStaticData.CARD, cardId);
			int index = 0;
			
			if(card.type == EColorType.TONG_ZI.getType()){
				index = card.value;
				color[0]++;
			}else if (card.type == EColorType.TIAO_ZI.getType()) {
				index = 10+card.value;
				color[1]++;
			}else  {
				index = 20+card.value;
				color[2]++;
			}
			cards[index]++;
		}
		int colorCount = (color[0]!=0?1:0)+(color[1]!=0?1:0)+(color[2]!=0?1:0);
		boolean isSameColor = colorCount==1;
		
		if(isSameColor){
			int size = chiPengGangCard==null?0:chiPengGangCard.size();
			
			if(size>0){
				for (int i = 0; i < size; i++) {//计算吃碰杠的牌是否清一色
					OperateCardData ocd = chiPengGangCard.get(i);
					SCard card = (SCard) StaticData.getStaticModel(EStaticData.CARD, ocd.getCards().get(0));
					
					if(card.type == EColorType.TONG_ZI.getType()){
						color[0]++;
					}else if (card.type == EColorType.TIAO_ZI.getType()) {
						color[1]++;
					}else  {
						color[2]++;
					}
				}
				colorCount = (color[0]!=0?1:0)+(color[1]!=0?1:0)+(color[2]!=0?1:0);
				isSameColor = colorCount==1;
			}
			
		}
		List<String> huCardPatterns = new ArrayList<>();//胡牌牌型
		int fanCount =isHu(cards, cardSize, chiPengGangCard,isSameColor,huCardPatterns);
		boolean isHuCard = fanCount !=-1;
		
		if(isHuCard){
			pcc.setStart(false);
			pcc.setReadyRoleIds(null);
			pcc.calHuScore(roleId, isZiMo, fanCount);
			pcc.setWinUnit(pcu);
		}
		return isHuCard;
	}
	
	
	
	/**
	 * 是否胡牌
	 * @param cards                具有的手牌信息
	 * @param cardSize             手牌数量
	 * @param chiPengGangCard      所有吃碰杠的牌
	 * @param isSameColor          是否清一色
	 * @return                     -1-没有胡牌 其他-为胡牌的翻数
	 */
	public static int isHu(byte[] cards,int cardSize,List<OperateCardData> 
					chiPengGangCard,boolean isSameColor,List<String> huCardPatterns){
		if(cardSize<2||((cardSize-2)%3)!=0) return -1;//查看牌型是否满足3n+2
		Map<Byte,Byte> cardTypeCounts = new HashMap<>(3);
		Map<Byte,Byte> chiPengGang = new HashMap<>(3);
		
		for (int i = 0; i < CARD_COUNT; i++) {//计算手牌 每种牌 的数量(0 1 2 3 4)
			byte count = cards[i];
			if(count<=1) continue;
			Byte inCount = cardTypeCounts.get(count);
			cardTypeCounts.put(count, (byte)(1+(inCount==null?0:inCount)));
		}
		int size = chiPengGangCard==null?0:chiPengGangCard.size();
		
		for (int i = 0; i < size; i++) {//计算吃碰杠的牌
			OperateCardData ocd = chiPengGangCard.get(i);
			
			if(ocd.getCardType() == EOperateCardType.CHI_TYPE){
				Byte inCount = cardTypeCounts.get((byte)1);
				cardTypeCounts.put((byte)1, (byte)(1+(inCount==null?0:inCount)));
			}else if(ocd.getCardType() == EOperateCardType.PENG_TYPE){
				Byte inCount = cardTypeCounts.get((byte)2);
				cardTypeCounts.put((byte)2, (byte)(1+(inCount==null?0:inCount)));
			}else if(ocd.getCardType() == EOperateCardType.AN_GANG_TYPE
					||ocd.getCardType() == EOperateCardType.MING_GANG_TYPE){
				Byte inCount = cardTypeCounts.get((byte)3);
				cardTypeCounts.put((byte)3, (byte)(1+(inCount==null?0:inCount)));
			}
		}
		Byte qiDuiZiCount = cardTypeCounts.get((byte)2);//对子的数量
		Byte anGangCount = cardTypeCounts.get((byte)4);//四个的数量
		Byte anKeCount = cardTypeCounts.get((byte)3);//三个的数量
		
		Byte chiCardCount = chiPengGang.get((byte)1);//吃的数量
		Byte mingKeCount = chiPengGang.get((byte)2);//碰的数量
		Byte mingGangCount = chiPengGang.get((byte)3);//杠的数量(包括明杠 暗杠)
		
		//七对子的数量
		int qdzCount = (qiDuiZiCount==null?0:qiDuiZiCount)+(anGangCount==null?0:(anGangCount*2));
		//刻和杠的数量
		int keZiAndGangCount = (anGangCount==null?0:anGangCount)+(mingGangCount==null?0:mingGangCount)
				+(anKeCount==null?0:anKeCount)+(mingKeCount==null?0:mingKeCount);
		//吃碰杠的数量
		int chiPengGangCount = (mingGangCount==null?0:mingGangCount)
				+(chiCardCount==null?0:chiCardCount)+(mingKeCount==null?0:mingKeCount);
		
		int hongZhongCount = cards[21];
		int faCaiCount = cards[22];
		int baiBanCount = cards[23];
		//红中 发财 白板的数量
		int totalCount = hongZhongCount+faCaiCount+baiBanCount;
		
		if(qdzCount==7){//七对子
			if(isSameColor){//清一色七对子
				huCardPatterns.add(Hu_card_type_1);
				return 8;
			}else if (anGangCount!=null) {//豪华七对子
				huCardPatterns.add(Hu_card_type_3);
				return 8;
			}else if (totalCount>=8){//三元七对
				huCardPatterns.add(Hu_card_type_4);
				return 8;
			}
			huCardPatterns.add(Hu_card_type_2);
			return 4;
		}else if(chiCardCount==null&&(qiDuiZiCount==null?
				0:qiDuiZiCount)==1&&keZiAndGangCount>=4){//碰碰胡
			huCardPatterns.add(Hu_card_type_5);
			
			if(isSameColor){
				huCardPatterns.add(Hu_card_type_1);
				return 8;
			}
			return 4;
		}else if((qiDuiZiCount==null?0:qiDuiZiCount)==1&&chiPengGangCount>=4){//手抓一
			huCardPatterns.add(Hu_card_type_6);
			
			if(isSameColor){
				huCardPatterns.add(Hu_card_type_1);
				return 8;
			}
			return 4;
		}else {//普通胡牌
			List<List<CardTypeData>> cardTypeDatas = new ArrayList<>();
			
			for (int i = 0; i < CARD_COUNT; i++) {
	            int count = cards[i];
	            
				if(count>=2){
					byte[] data = new byte[CARD_COUNT];
					System.arraycopy(cards, 0, data, 0, CARD_COUNT);
					data[i] -=2 ;
					List<CardTypeData> currData = new ArrayList<>();
					currData.add(new CardTypeData(ECardType.JIANG, data[i]));
					
					if (isHuCurrCardType(data, currData)) {
						cardTypeDatas.add(currData);
					}
				}
			}
			if(cardTypeDatas.size()<=0) return -1;//不胡牌

			if(totalCount==8){//小三元
				huCardPatterns.add(Hu_card_type_7);
				return 4;
			}else if(totalCount==9){//大三元
				huCardPatterns.add(Hu_card_type_8);
				return 8;
			}
			huCardPatterns.add(Hu_card_type_9);
			return 1;
		}
	}
	
	
	/**
	 * 当前牌型是否能胡牌
	 * @param cards  胡牌信息
	 * @param result 胡牌牌型
	 * @return
	 */
	private static boolean isHuCurrCardType(byte[] cards,List<CardTypeData> result){
		for (int i = 0; i < CARD_COUNT; i++) {
			int value = cards[i];
			if(value == 0) continue;
			
			if(value ==1||value ==4){
				if(i>20||cards[i+1]<1||cards[i+2]<1) return false;
				result.add(new CardTypeData(ECardType.SHUN_ZI, (byte)cards[i+2]));
				cards[i]--;
				cards[i+1]--;
				cards[i+2]--;
				
				if(value ==4){
					result.add(new CardTypeData(ECardType.AN_KE_ZI, (byte)value));
					cards[i]=0;
				}
			}else if (value ==2) {
				if(i>20||cards[i+1]<2||cards[i+2]<2) return false;
				cards[i]-=2;
				cards[i+1]-=2;
				cards[i+2]-=2;
				CardTypeData ctd = new CardTypeData(ECardType.SHUN_ZI, (byte)cards[i+2]);
				result.add(ctd);
				result.add(ctd);
			}else if (value ==3) {
				result.add(new CardTypeData(ECardType.AN_KE_ZI, (byte)value));
				cards[i]=0;
			}
			isHuCurrCardType(cards, result);
		}
		return true;
	}