用一个int表示德州扑克玩家牌力

博客

这个方法是在python的一个德州库(PyPokerEngine)里看到的,并不是原创,但是原方法bug特别的多,直接导致牌局的胜负判断错误,所以我对原方法进行了一些改进,但是原方法的思想非常厉害,所以值得推荐一番。

原库的思想是这样的:

int有32位,扑克牌最大的牌是K,值是13,需要用4位来表示,所以利用高16位表示牌型(如一对,两对,顺子等)值,用低16位表示关键牌的值(如一对中,对子的牌大小)。

[牌型大小(16bit)] [关键牌1(4bit)] [关键牌2(4bit)] [手牌1(4bit)] [手牌1(4bit)]

比如 A K Q 5 5,这副牌,可以使用二进制 0000 0000 0000 0001 0000 0101 0001 1101表示。

其中,高16位 0000 0000 0000 0001 表示一对,如果是两对则用 0000 0000 0000 0010 表示,这样的好处是,牌型大的牌无需比较牌面的大小,两对行成的int永远大于一对。其中低16位中的前8位表示的是牌中关键牌的值,这里 0000 0101 表示的是一对5中的5,低16位中的后8位表示的是手牌的大小,我这里假设A K是手牌,所以值为 0001 1101。

乍一看原库的思想的确很妙,不管是什么牌型直接用一个int数字就能表示并且轻易的比较,但是在有的牌局中,这个方法却出现了致命的bug。

在牌型关键牌平局的时候,只能比手牌,这样的比较肯定是错误的。在德州的规则中,如果两名玩家都是一对5,那么需要比较剩下的3张最大的牌,这个时候在原库思想中比的是玩家手牌,但是当桌面上5张牌就是最大的牌的时候,双方应该是平局,手牌不应该左右牌局的胜负方。比如这样一局牌:

公共牌:A K Q J J
玩家1手牌:10 9
玩家2手牌:8 7

这局牌在正确的规则中,应该是平局。但是在原库的代码中,判定玩家1获胜。所以需要修改一下原库的部分算法。

高16位的算法依然保持不变:

public final int HIGH_CARD = 0; // 高牌
public final int ONE_PAIR = 1 << 8; // 一对
public final int TWO_PAIR = 1 << 9; // 两对
public final int THREE_CARD = 1 << 10; // 三张
public final int STRAIGHT = 1 << 11; // 顺子
public final int FLUSH = 1 << 12; // 同花
public final int FULL_HOUSE = 1 << 13; // 葫芦
public final int FOUR_CARD = 1 << 14; // 四张
public final int STRAIGHT_FLUSH = 1 << 15; // 同花顺
public final int ROYAL_FLUSH = 1 << 16; // 皇家同花顺

重点就是接下来的每一种牌型的后16位写法,全部都不需要保存手牌了。

同花顺:只需要保存同花顺中最小牌在后16位就可以了,比如 10 J Q K A,那么只需要保存10,就能判断同花顺的大小。

四张:保存相同的4张牌的牌的大小和剩下最大的那张牌的大小,比如 A A A A K,那么只需要保存 A K 0 0。

葫芦:保存3张相同牌的牌大小和另外一对的牌大小,比如 Q Q Q J J,那么保存的就是Q J 0 0。

顺子:同同花顺存储方法。

同花:5张牌,最大的是A(用14表示),最多5张牌加起来最大的数字是69(并不可能在同花中出现),用8位二进制完全可以存起来,那么同花就保存最大5张牌的和。

三张:依次保存的是,三张相同牌的牌大小,剩下两张最大的牌大小,如Q Q Q J 9,那么按顺序存的是Q J 9 0。

两对:依次保存的是,较大的一对的牌大小,较小的一对的牌大小,剩下最大的牌的大小,如 Q Q J J 10,那么按顺序保存的 Q J 10 0。

一对:依次保存的是,一对的牌大小,剩下3张最大的牌的大小,如 Q Q J 9 8,那么保存的是 Q J 9 8。

高牌:同同花存储方法。

三张举例,对应的代码如下:

// 搜索卡牌列表中是否存在三张,并返回三张的牌面大小,不存在返回-1
private static int searchThreeCard(List<Card> cards) {
    int bestRank = -1;
    Map<Integer, List<Card>> rankGroup = cards.stream().collect(Collectors.groupingBy(Card::getRank, Collectors.toList()));
    for (Integer rank : rankGroup.keySet()) {
        List<Card> cardList = rankGroup.get(rank);
        if (cardList.size() >= 3 && rank > bestRank) {
            bestRank = rank;
        }
    }
    return bestRank;
}
// 判断存在三张之后,返回三张所对应的牌力int值
if (GameUtil.searchThreeCard(cards) != -1) {
    int threeCard = GameUtil.searchThreeCard(cards) << 4;
    List<Integer> topCardRank = getTopCardRank(2, cards, threeCard >> 4);
    if (topCardRank == null) {
        return (THREE_CARD | threeCard) << 8;
    }
    return ((THREE_CARD | threeCard) << 8) | ((topCardRank.get(0) << 4) | topCardRank.get(1));
}

这样就能够在使用最小内存和最快的比较速度的情况下,判断出哪一位玩家获胜了。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当然,以下是一个简单的Java代码示例,用于判断德州扑克的牌型: ```java import java.util.ArrayList; import java.util.Collections; import java.util.List; public class PokerHandEvaluator { public static void main(String[] args) { List<Card> hand = new ArrayList<>(); hand.add(new Card("Spades", "A")); hand.add(new Card("Hearts", "K")); hand.add(new Card("Diamonds", "Q")); hand.add(new Card("Spades", "J")); hand.add(new Card("Spades", "10")); PokerHandType handType = evaluateHand(hand); System.out.println("Hand Type: " + handType); } public static PokerHandType evaluateHand(List<Card> hand) { Collections.sort(hand); if (isRoyalFlush(hand)) { return PokerHandType.ROYAL_FLUSH; } if (isStraightFlush(hand)) { return PokerHandType.STRAIGHT_FLUSH; } if (isFourOfAKind(hand)) { return PokerHandType.FOUR_OF_A_KIND; } // Check for other hand types... return PokerHandType.HIGH_CARD; } // Check if the hand is a Royal Flush (A, K, Q, J, 10 of the same suit) public static boolean isRoyalFlush(List<Card> hand) { return isStraightFlush(hand) && hand.get(0).getValue().equals("A"); } // Check if the hand is a Straight Flush (five consecutive cards of the same suit) public static boolean isStraightFlush(List<Card> hand) { return isStraight(hand) && isFlush(hand); } // Check if the hand is a Four of a Kind (four cards of the same rank) public static boolean isFourOfAKind(List<Card> hand) { for (int i = 0; i <= hand.size() - 4; i++) { if (hand.get(i).getValue().equals(hand.get(i + 3).getValue())) { return true; } } return false; } // Check if the hand is a Straight (five consecutive cards) public static boolean isStraight(List<Card> hand) { for (int i = 0; i < hand.size() - 1; i++) { if (hand.get(i).getRank() != hand.get(i + 1).getRank() - 1) { return false; } } return true; } // Check if the hand is a Flush (all cards of the same suit) public static boolean isFlush(List<Card> hand) { String suit = hand.get(0).getSuit(); for (int i = 1; i < hand.size(); i++) { if (!hand.get(i).getSuit().equals(suit)) { return false; } } return true; } } class Card implements Comparable<Card> { private String suit; private String value; public Card(String suit, String value) { this.suit = suit; this.value = value; } public String getSuit() { return suit; } public String getValue() { return value; } public int getRank() { if (value.equals("A")) { return 14; // Ace is the highest rank } else if (value.equals("K")) { return 13; } else if (value.equals("Q")) { return 12; } else if (value.equals("J")) { return 11; } else if (value.equals("10")) { return 10; } else { return Integer.parseInt(value); } } @Override public int compareTo(Card other) { return Integer.compare(this.getRank(), other.getRank()); } } enum PokerHandType { ROYAL_FLUSH, STRAIGHT_FLUSH, FOUR_OF_A_KIND, // Add other hand types as needed... HIGH_CARD } ``` 这段代码实现了一个简单的德州扑克牌型判断。你可以根据需要在`evaluateHand`方法中添加其他牌型的判断逻辑,或者修改`Card`类中的牌面值和花色,以及`PokerHandType`枚举类中的牌型。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值