場景:相信你們都知道,鬥地主遊戲中有一個新的模式--癩子玩法。所以咱們的出牌的時候,N張正常的牌+M張癩子牌 就可能組合成多種牌型,這中間就涉及到了可否適配相應牌型和如何適配相應的牌型的問題。數組
輸入:N張正常的牌,M張癩子牌 固然癩子牌不超過四張。ide
輸出:R種結果,每種結果包含M張癩子牌所適配的正常牌值以及當前適配所表明的牌型。ui
言歸正傳,咱們知道鬥地主有以下幾種牌型:this
· 火箭:即雙王(雙鬼牌),什麼牌型均可打,是最大的牌。
· 炸彈:四張同數值牌(如四個5)。除火箭和比本身大的炸彈外,什麼牌型均可打。
· 單牌(一手牌):單個牌。
· 對牌(一手牌):數值相同的兩張牌。
· 三張牌:數值相同的三張牌(如三個10)。
· 三帶一手:數值相同的三張牌+ 一張單牌或一對牌。例如: 333+4或333+44
· 單順:五張或更多的連續單牌(如:34567或678910J)。不包括2點和雙王,不分花色。
· 雙順:三對或更多的連續對牌(如:33445五、88991010JJ)。不包括2點和雙王。
· 三順:二個或更多的連續三張牌(如:33344四、444555666777)。不包括2點和雙王。也叫飛機不帶翅膀。
· 飛機帶翅膀。三順+同數量的一手牌。例如:333444+69 或333444555+667799
· 四帶二:四張牌+兩手牌。例如:5555+3+8或 4444+55+77
像炸彈,單牌,雙牌,對牌,三張牌,四帶二這些牌型的適配在這裏就很少說啦。這裏着重講的是 單順,雙順,三順,三帶一及三帶一的飛機,三帶對以及三帶對的飛機牌型適配。
1 public static enum PokerSuit { 2 DIAMOND("DIAMOND", 0), CLUB("CLUB", 1), HEART("HEART", 2), SPADE("SPADE", 3), BLACK("BLACK", 4), RED("RED", 5);//black與red是爲大小王準備的 3 4 private final String name; 5 private final int value; 6 7 PokerSuit(String name, int value) { 8 this.name = name; 9 this.value = value; 10 } 11 12 @Override 13 public String toString() { 14 return getName() + ":" + getValue(); 15 } 16 17 public String getName() { 18 return name; 19 } 20 21 public int getValue() { 22 return value; 23 } 24 25 public static int getSize() { 26 return 6; 27 } 28 } 29 30 public static enum PokerRank { 31 THREE("THREE", 3), FOUR("FOUR", 4), FIVE("FIVE", 5), SIX("SIX", 6), SEVEN("SEVEN", 7), EIGHT("EIGHT", 8), NINE("NINE", 9), 32 TEN("TEN", 10), JACKY("JACKY", 11), QUEENE("QUEENE", 12), KING("KING", 13), ACE("ACE", 14), TWO("TWO", 15), JOKER("JOKER", 16); 33 34 private final String name; 35 private final int value; 36 37 PokerRank(String name, int value) { 38 this.name = name; 39 this.value = value; 40 } 41 42 @Override 43 public String toString() { 44 return getName() + ":" + getValue(); 45 } 46 47 public String getName() { 48 return name; 49 } 50 51 public int getValue() { 52 return value; 53 } 54 55 public static int getSize() { 56 return 14; 57 } 58 } 59 60 public static class PokerCard implements Comparable<PokerCard> { 61 private int mIndex; 62 private PokerSuit mSuit; 63 private PokerRank mRank; 64 65 PokerCard(int index, PokerSuit suit, PokerRank rank) { 66 this.mIndex = index; 67 this.mSuit = suit; 68 this.mRank = rank; 69 } 70 71 public PokerSuit getSuit() { 72 return mSuit; 73 } 74 75 public PokerRank getRank() { 76 return mRank; 77 } 78 79 public int getIndex() { 80 return mIndex; 81 } 82 83 @Override 84 public String toString() { 85 return "CARD[[" + getIndex() + "=" + mSuit.getName() + ":" + mRank.getName() + "]]"; 86 } 87 88 @Override 89 public int compareTo(PokerCard another) { 90 if(this.getRank().getValue() > another.getRank().getValue()) { 91 return -1; 92 } else if(this.getRank().getValue() < another.getRank().getValue()) { 93 return 1; 94 } else { 95 if(this.getSuit().getValue() > another.getSuit().getValue()) { 96 return -1; 97 } else if(this.getSuit().getValue() < another.getSuit().getValue()) { 98 return 1; 99 } else { 100 return 0; 101 } 102 } 103 } 104 }
輸入的總牌數:PokerCard [] inputCards;
咱們將輸入的牌,除癩子外,所有解析成 單張的多少個(PokerRank singleSet[]),對子的多少個(PokerRank pairSet[]),三張的多少個(PokerRank threeSet[]),四張的多少個(PokerRank fourSet[]);癩子解析成癩子張數(PokerRank laiziSet[])。
新建二個輔助數組:
int [] assistValue = new int [17]; (~,~,~,3,4,5,6,7,8,9,10,J,Q,K,A,2,JOKER)前面三個值是不用的。
PokerRank[] sAssistRanks = {
null, null, null, PokerRank.THREE, PokerRank.FOUR, PokerRank.FIVE, PokerRank.SIX, PokerRank.SEVEN, PokerRank.EIGHT, PokerRank.NINE,
PokerRank.TEN, PokerRank.JACKY, PokerRank.QUEENE, PokerRank.KING, PokerRank.ACE, PokerRank.TWO, PokerRank.JOKER
};
順子,必須是3~A之間的連續五個或五個以上的牌組成。因此咱們能夠根據牌的總數來肯定是多少順,而後在3~A之間循環判斷一次就能夠肯定有多少種適配方式。
首先初始化assistValue:
// needLaiziCount 表示當前這張牌若是適配當前牌型的話,須要的癩子牌數。 // 單順:needLaiziCount = 1 // 雙順:needLaiziCount = 2 // 三順:needLaiziCount = 3 for(int i=0; i<assistValue.length; i++) { assistValue[i] = needLaiziCount; }
而後根據singleSet, pairSet, threeSet, fourSet的值來填充assistValue的值對應值。
// 在配單順的時候,不該該出現pairSet.length>0或者threeSet.length>0或者fourSet.length>0的狀況。 // 一樣在配雙順的時候,不該該出現threeSet.length>0或者fourSet.length>0的狀況。 // 一樣在配三順的時候,不該該出現fourSet.length>0的狀況。 // 在配單順,雙順,三順的時候也不該該出現JOKER,或者TWO的牌。 // 上述狀況在配以前就應該作下判斷,就能夠直接跳過。 for(int i=0; i<singleSet.length; i++) { assistValue[singleSet[i].getValue()] = needLaiziCount - 1; } for(int i=0; i<pairSet.length; i++) { assistValue[pairSet[i].getValue()] = needLaiziCount - 2; } for(int i=0; i<threeSet.length; i++) { assistValue[threeSet[i].getValue()] = needLaiziCount - 3; } for(int i=0; i<fourSet.length; i++) { assistValue[fourSet[i].getValue()] = needLaiziCount - 4; }
接下來就開始配牌啦:
// 單順:STRAIGHT_SINGLE_COUNT = 1;雙順:STRAIGHT_SINGLE_COUNT = 2;三順:STRAIGHT_SINGLE_COUNT = 3; int straightLength = inputCards.length/STRAIGHT_SINGLE_COUNT; int startIndex = straightLength + 2; for(int i=startIndex; i<=PokerRank.ACE.getValue(); i++) { int valuesCount = 0; for(int j=i; j<i+straightLength; j++) { valuesCount += assistValue[j]; } if(valuesCount != laiziSet.length) { continue; // 不可適配 } // 開始適配 List<PokerCard> replaceCards = new ArrayList<PokerCard>(); for(int j=i; j<i+straightLength; j++) { for(int k=0; k<assistValue[j]; k++) { // getPokerCard(PokerRank rank) 表示獲取一個牌值爲rank,花色與當前手牌中不重複的PokerCard replaceCards.add(getPokerCard(sAssistRanks[j])); } } // 將本次適配的結果保存起來。 sAllReplaceCards.add(replaceCards); }
OK到如今爲止,單雙三順的牌就判斷完畢(其中的一些細節部分須要讀者本身去考慮)。spa
三帶一以及三帶一的飛機,三帶對以及三帶對的飛機牌型適配:code
飛機去掉翅膀,就是一個三個的連子,而單個的三張,能夠當作一個特殊的連子。所以咱們首先適配飛機的部分,而後適配翅膀的部分。blog
預處理:若是是三帶對及三帶對的飛機,能夠先將單張的配成對子。 固然,這幾種牌型fourSet.length都不能大於0。three
配飛機的方法同配順子同樣(你們琢磨琢磨)。遊戲
配翅膀就好辦,只要不跟當前手中的牌重複就是啦。get
這個就交給博友們本身思考吧。