从 5 张手牌扑克中获得对子的概率

Probability to get pair from 5-card hand poker

我需要通过模拟找到从 5 张手牌中得到一对牌的概率百分比。

到目前为止,我已经制作了 类 "Card"(功能:卡片价值、花色、按价值与另一张卡片进行比较)和 "Hand"(功能:addCard 和 isOnePair returns 仅当手牌实例中有一对牌时才为真。

Card.java:

public enum CardValue { s2, s3, s4, s5, s6, s7, s8, s9, s10, J, Q, K, A }

public enum CardSuit { C, D, H, S }

private CardValue value;
private CardSuit suit;

public Card(CardValue value, CardSuit suit) {
    this.value = value;
    this.suit = suit;
}

@Override
public boolean equals(Object obj) {
    if(obj == this) {
        return true;
    }
    if(!(obj instanceof Card)) {
        return false;
    }
    Card card = (Card)obj;
    return card.value == this.value;
}

Hand.java

private Set<Card> hand;

public Hand() {
    this.hand = new HashSet<>();
}

public void addCard(Card card) {
    this.hand.add(card);
}

@Override
public String toString() {
    return this.hand.toString();
}

private boolean isOnePair() {
    int counter = 0;
    for(Card card : hand){
        for(Card card2 : hand) {
            if(card.equals(card2)) {
                counter++;
            }
        }
        if(counter == 2) {
            return true;
        }
        counter = 0;
    }

    return false;
}
  • 首先,创建一个包含所有可能的 CardList 套牌。
  • 然后,对于模拟的每次迭代,洗牌并抽取前 5 Cards。
  • 检查是否有一对,如果有,增加一个计数器。
  • 将计数器除以迭代总数。

示例:

Random rand = new Random();

final int NUMBER_OF_VALUES = Card.CardValue.values().length;
final int NUMBER_OF_SUITS = Card.CardSuit.values().length;
final int NUMBER_OF_CARDS_IN_HAND = 5;
Card.CardValue value;
Card.CardSuit suit;
Hand hand;
List<Card> deck = new ArrayList<>();

// Deck creation
for(int i = 0; i < NUMBER_OF_VALUES; i++) {
    for(int j = 0; j <  NUMBER_OF_SUITS; j++)
        deck.add(new Card(Card.CardValue.values()[i], Card.CardSuit.values()[j]));
}

int counter = 0;
final int TOTAL = 100000;

// Simulation
for(int i = 0; i < TOTAL; i++) {
    Collections.shuffle(deck);
    hand = new Hand();
    for(int j = 0; j < NUMBER_OF_CARDS_IN_HAND; j++)
        hand.addCard(deck.get(j));
    if(hand.isOnePair()) counter++;
}

System.out.println("Probability: " + 100 * counter / (double)TOTAL + "%");

你只关心有52张牌,它们平均分布在13个等级上。您不需要模拟甲板。您只想选择 0 到 51 之间的 5 个随机数,不要重复,然后计算一个数字的排名与另一个数字的排名匹配的次数,考虑到排名在 52 个可选数字中按顺序重复 4 次。如果这种情况只发生一次,您就有一对牌。这只需要 5 次迭代的一个循环。

此代码通过 运行 200K 次迭代来估计 5 张手牌中恰好一对的概率。它在我的 Macbook Pro 上几乎是瞬间完成的:

import java.util.Random;

public class OnePair {

    // Initialize a random number generator
    private static Random random = new Random(System.currentTimeMillis());

    private static boolean doOne() {

        // Keep track of cards we've picked so we don't pick the same card twice
        boolean[] cards = new boolean[52];

        // Keep track of ranks we've seeen before
        boolean[] ranks = new boolean[13];

        // Keep track of how many times ranks have matched
        int count = 0;

        // For each of 5 cards...
        for (int i = 0 ; i < 5 ; i++) {

            // Pick a random card we haven't picked before
            int card;
            while (true) {
                card = random.nextInt(52);
                if (!cards[card]) {
                    cards[card] = true;
                    break;
                }
            }

            // If we've seen this rank before, increase our total matches
            if (ranks[card % 13])
                count += 1;

            // Remember that we've seen this rank
            ranks[card % 13] = true;
        }

        // Return if we saw exactly one pair, in which case count will be 1
        return count == 1;
    }

    public static void main(String[] args) {

        long count = 200000;
        long paired = 0;

        for (int i = 0 ; i < count ; i++)
            if (doOne())
                paired += 1;

        System.out.println((float)paired / count);

    }
}

我得到的结果抽样:

0.42265
0.42181
0.42112
0.422675
0.423895

我找到了同样问题的统计计算,规定的概率是 0.422569。