最近写了一个麻将的胡牌逻辑,这个麻将是没有万字牌 和 东西南北风牌,以前也写过麻将胡牌逻辑,都没有记录,这次记录一下,方便以后查阅
/**
* 胡牌
* @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;
}