我正在作为大学项目开发扑克游戏,我们目前的任务是编写一种算法来对5张手牌进行得分,以便可以将两只手的得分相互比较以确定哪个更好。一手牌的分数与用随机纸牌等方式处理平局时可以做出哪一手牌的概率无关。-一手牌的分数仅基于该手牌中的5张纸牌,而没有其他纸牌在甲板上。
我们给出的示例解决方案是为每种类型的扑克手给出默认得分,该得分反映出该手的优劣-例如:
//HAND TYPES: ROYAL_FLUSH = 900000 STRAIGHT_FLUSH = 800000 ... TWO_PAIR = 200000 ONE_PAR = 100000
然后,如果比较相同类型的两只手,则该手牌中的牌值应计入该手的得分中。
因此,例如,可以使用以下公式来得分:
HAND_TYPE + (each card value in the hand)^(the number of occurences of that value)
因此,对于由三个皇后和两个7组成的满屋子,得分将是:
600000 + 12^3 + 7^2
这个公式在大多数情况下都是有效的,但是我已经确定,在某些情况下,两只相似的手可以真正地得分相同,而实际上一只手应该击败另一只手。例如:
hand1 = 4C, 6C, 6H, JS, KC hand2 = 3H, 4H, 7C, 7D, 8H
这两只手都有一对,所以各自的分数是:
100000 + 4^1 + 6^2 + 11^1 + 13^1 = 100064 100000 + 3^1 + 4^1 + 7^2 + 8^1 = 100064
当一对7s明显胜过一对6s时,这将导致平局。
我该如何改善这个公式,甚至可以使用更好的公式?
顺便说一下,在我的代码中,手以升序存储在每张卡的值的数组中,例如:
[2H, 6D, 10C, KS, AS]
编辑:
这是我的最终解决方案,这要归功于以下答案:
/** * Sorts cards by putting the "most important" cards first, and the rest in decreasing order. * e.g. High Hand: KS, 9S, 8C, 4D, 2H * One Pair: 3S, 3D, AH, 7S, 2C * Full House: 6D, 6C, 6S, JC, JH * Flush: KH, 9H, 7H, 6H, 3H */ private void sort() { Arrays.sort(hand, Collections.reverseOrder()); // Initially sorts cards in descending order of game value if (isFourOfAKind()) { // Then adjusts for hands where the "most important" cards sortFourOfAKind(); // must come first } else if (isFullHouse()) { sortFullHouse(); } else if (isThreeOfAKind()) { sortThreeOfAKind(); } else if (isTwoPair()) { sortTwoPair(); } else if (isOnePair()){ sortOnePair(); } } private void sortFourOfAKind() { if (hand[0].getGameValue() != hand[HAND_SIZE - 4].getGameValue()) { // If the four of a kind are the last four cards swapCardsByIndex(0, HAND_SIZE - 1); // swap the first and last cards } // e.g. AS, 9D, 9H, 9S, 9C => 9C, 9D, 9H, 9S, AS } private void sortFullHouse() { if (hand[0].getGameValue() != hand[HAND_SIZE - 3].getGameValue()) { // If the 3 of a kind cards are the last three swapCardsByIndex(0, HAND_SIZE - 2); // swap cards 1 and 4, 2 and 5 swapCardsByIndex(HAND_SIZE - 4, HAND_SIZE - 1); // e.g. 10D, 10C, 6H, 6S, 6D => 6S, 6D, 6H, 10D, 10C } } private void sortThreeOfAKind() { // If the 3 of a kind cards are the middle 3 cards if (hand[0].getGameValue() != hand[HAND_SIZE - 3].getGameValue() && hand[HAND_SIZE - 1].getGameValue() != hand[HAND_SIZE - 3].getGameValue()) { // swap cards 1 and 4 swapCardsByIndex(0, HAND_SIZE - 2); // e.g. AH, 8D, 8S, 8C, 7D => 8C, 8D, 8S, AH, 7D } else if (hand[0].getGameValue() != hand[HAND_SIZE - 3].getGameValue() && hand[HAND_SIZE - 4].getGameValue() != hand[HAND_SIZE - 3].getGameValue()) { Arrays.sort(hand); // If the 3 of a kind cards are the last 3, swapCardsByIndex(HAND_SIZE - 1, HAND_SIZE - 2); // reverse the order (smallest game value to largest) } // then swap the last two cards (maintain the large to small ordering) } // e.g. KS, 9D, 3C, 3S, 3H => 3H, 3S, 3C, 9D, KS => 3H, 3S, 3C, KS, 9D private void sortTwoPair() { if (hand[0].getGameValue() != hand[HAND_SIZE - 4].getGameValue()) { // If the two pairs are the last 4 cards for (int i = 0; i < HAND_SIZE - 1; i++) { // "bubble" the first card to the end swapCardsByIndex(i, i + 1); // e.g. AH, 7D, 7S, 6H, 6C => 7D, 7S, 6H, 6C, AH } } else if (hand[0].getGameValue() == hand[HAND_SIZE - 4].getGameValue() && hand[HAND_SIZE - 2].getGameValue() == hand[HAND_SIZE - 1].getGameValue()) { // If the two pairs are the first and last two cards swapCardsByIndex(HAND_SIZE - 3, HAND_SIZE - 1); // swap the middle and last card } // e.g. JS, JC, 8D, 4H, 4S => JS, JC, 4S, 4H, 8D } private void sortOnePair() { // If the pair are cards 2 and 3, swap cards 1 and 3 if (hand[HAND_SIZE - 4].getGameValue() == hand[HAND_SIZE - 3].getGameValue()) { // e.g QD, 8H, 8C, 6S, 4J => 8C, 8H, QD, 6S, 4J swapCardsByIndex(0, HAND_SIZE - 3); } else if (hand[HAND_SIZE - 3].getGameValue() == hand[HAND_SIZE - 2].getGameValue()) { // If the pair are cards 3 and 4, swap 1 and 3, 2 and 4 swapCardsByIndex(0, HAND_SIZE - 3); // e.g. 10S, 8D, 4C, 4H, 2H => 4C, 4H, 10S, 8D, 2H swapCardsByIndex(HAND_SIZE - 4, HAND_SIZE - 2); } else if (hand[HAND_SIZE - 2].getGameValue() == hand[HAND_SIZE - 1].getGameValue()) { // If the pair are the last 2 cards, reverse the order Arrays.sort(hand); // and then swap cards 3 and 5 swapCardsByIndex(HAND_SIZE - 3, HAND_SIZE - 1); // e.g. 9H, 7D, 6C, 3D, 3S => 3S, 3D, 6C, 7D, 9H => 3S, 3D, 9H, 7D, 6C } } /** * Swaps the two cards of the hand at the indexes taken as parameters * @param index1 * @param index2 */ private void swapCardsByIndex(int index1, int index2) { PlayingCard temp = hand[index1]; hand[index1] = hand[index2]; hand[index2] = temp; } /** * Gives a unique value of any hand, based firstly on the type of hand, and then on the cards it contains * @return The Game Value of this hand * * Firstly, a 24 bit binary string is created where the most significant 4 bits represent the value of the type of hand * (defined as constants private to this class), the last 20 bits represent the values of the 5 cards in the hand, where * the "most important" cards are at greater significant places. Finally, the binary string is converter to an integer. */ public int getGameValue() { String handValue = addPaddingToBinaryString(Integer.toBinaryString(getHandValue())); for (int i = 0; i < HAND_SIZE; i++) { handValue += addPaddingToBinaryString(Integer.toBinaryString(getCardValue(hand[i]))); } return Integer.parseInt(handValue, 2); } /** * @param binary * @return the same binary string padded to 4 bits long */ private String addPaddingToBinaryString(String binary) { switch (binary.length()) { case 1: return "000" + binary; case 2: return "00" + binary; case 3: return "0" + binary; default: return binary; } } /** * @return Default value for the type of hand */ private int getHandValue() { if (isRoyalFlush()) { return ROYAL_FLUSH_VALUE; } if (isStraightFlush()) { return STRAIGHT_FLUSH_VALUE; } if (isFourOfAKind()) { return FOUR_OF_A_KIND_VALUE; } if (isFullHouse()) { return FULL_HOUSE_VALUE; } if (isFlush()) { return FLUSH_VALUE; } if (isStraight()) { return STRAIGHT_VALUE; } if (isThreeOfAKind()) { return THREE_OF_A_KIND_VALUE; } if (isTwoPair()) { return TWO_PAIR_VALUE; } if (isOnePair()) { return ONE_PAIR_VALUE; } return 0; } /** * @param card * @return the value for a given card type, used to calculate the Hand's Game Value * 2H = 0, 3D = 1, 4S = 2, ... , KC = 11, AH = 12 */ private int getCardValue(PlayingCard card) { return card.getGameValue() - 2; }
有十种公认的扑克手:
9 - Royal flush 8 - Straight flush (special case of royal flush, really) 7 - Four of a kind 6 - Full house 5 - Flush 4 - Straight 3 - Three of a kind 2 - Two pair 1 - Pair 0 - High card
如果您不算西装,那么只有13种可能的卡值。卡的值为:
2 - 0 3 - 1 4 - 2 5 - 3 6 - 4 7 - 5 8 - 6 9 - 7 10 - 8 J - 9 Q - 10 K - 11 A - 12
用手编码需要4位,而对卡进行编码需要4位。您可以用24位代码对整手进行编码。
皇家同花顺将是1001 1100 1011 1010 1001 1000(0x9CBA98)
7高的顺子是0100 0101 0100 0011 0010 0001(0x454321)
两对10s和5s(以及ace)将是0010 1000 1000 0011 0011 1100(0x28833C)
我认为您有逻辑,可以弄清楚您的手牌。这样,您可能已经编写了代码以从左到右的顺序排列卡。因此,皇家同花顺将被安排为[A,K,Q,J,10]。然后,您可以使用以下逻辑构造代表手的数字:
int handValue = HandType; (i.e. 0 for high card, 7 for Four of a kind, etc.) for each card handValue = (handValue << 4) + cardValue (i.e. 0 for 2, 9 for Jack, etc.)
结果将是每手牌的唯一值,并且您确定同花顺将总是击败直牌,而王牌最高的满屋子将击败7高的满屋子,依此类推。
上面的算法取决于对扑克手进行归一化处理,首先是最重要的牌。因此,举例来说,这只手[K,A,10,J,Q](都是相同的衣服)是皇家同花顺。归一化为[A,K,Q,J,10]。如果拿到了手[10,Q,K,A,J],它也将被标准化为[A,K,Q,J,10]。手[7,4,3,2,4]是一对4。它将标准化为[4,4,7,3,2]。
[K,A,10,J,Q]
[A,K,Q,J,10]
[10,Q,K,A,J]
[7,4,3,2,4]
[4,4,7,3,2]
如果不进行标准化,则很难为每只手创建一个唯一的整数值,并确保一对4总是胜过一对3。
幸运的是,整理手是弄清楚手是什么的一部分。您 可以 执行此操作而无需进行排序,但是对五个项目进行排序将花费很短的时间,并且使很多事情变得更加容易。它不仅使确定平直度变得容易,而且将普通卡组合在一起,从而使查找对,三重和四倍变得更容易。
对于直道,同花和高牌手,您所需要做的就是整理。对于其他订单,您必须进行第二次订购,并通过分组来订购。例如,一个满屋子将是xxxyy,一对将是xxabc,(带有a,b和c,并按顺序排列),依此类推。不管怎样,大部分工作都是为您完成的。您所要做的就是将散乱者移到最后。
xxxyy
xxabc
a
b
c