技術文章ゲーム・パズル関係


 

 

ポーカー 手の確率
Nobuhide Tsuda
Apr-2014

手役判定

enum {
    HIGH_CARD = 0,
    ONE_PARE,
    TWO_PARE,
    THREE_OF_A_KIND,
    STRAIGHT,
    FLUSH,
    FULL_HOUSE,
    FOUR_OF_A_KIND,
    STRAIGHT_FLUSH,
    N_KIND_HAND,
};
// ランクは c1 >= c2 >= c3 >= c4 >= c5 とする
// A のランクは 12, 2 のランクは 0 とする
int checkHand(int c1, int c2, int c3, int c4, int c5)
{
    int r1 = c1 / 4;
    int s1 = c1 % 4;
    int r2 = c2 / 4;
    int s2 = c2 % 4;
    int r3 = c3 / 4;
    int s3 = c3 % 4;
    int r4 = c4 / 4;
    int s4 = c4 % 4;
    int r5 = c5 / 4;
    int s5 = c5 % 4;
    if( s1 == s2 && s2 == s3 && s3 == s4 && s4 == s5 
        && (r1 == r2 + 1 && r2 == r3 + 1 && r3 == r4 + 1 && r4 == r5 + 1
                || r1 == 12 && r2 == 3 && r3 == 2 && r4 == 1 && r5 == 0) )
    {
        return STRAIGHT_FLUSH;
    }
    if( r1 == r2 && r2 == r3 && r3 == r4
        || r2 == r3 && r3 == r4 && r4 == r5 )
    {
        return FOUR_OF_A_KIND;
    }
    if( r1 == r2 && r2 == r3 && r4 == r5 
        || r1 == r2 && r3 == r4 && r4 == r5 )
    {
        return FULL_HOUSE;
    }
    if( s1 == s2 && s2 == s3 && s3 == s4 && s4 == s5 )
        return FLUSH;
    if( r1 == r2 + 1 && r2 == r3 + 1 && r3 == r4 + 1 && r4 == r5 + 1
        || r1 == 12 && r2 == 3 && r3 == 2 && r4 == 1 && r5 == 0 ) 
        return STRAIGHT;
    if( r1 == r2 && r2 == r3
        || r2 == r3 && r3 == r4
        || r3 == r4 && r4 == r5 )
    {
        return THREE_OF_A_KIND;
    }
    if( r1 == r2 && r3 == r4
        || r1 == r2 && r4 == r5
        || r2 == r3 && r4 == r5 )
    {
        return TWO_PARE;
    }
    if( r1 == r2 || r2 == r3 || r3 == r4 || r4 == r5 )
        return ONE_PARE;
    return HIGH_CARD;
}

5枚だけの場合

    int nHand[N_KIND_HAND] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
    int cnt = 0;
    for (int c1 = 52; --c1 >= 4; ) {
        for (int c2 = c1; --c2 >= 3; ) {
            for (int c3 = c2; --c3 >= 2; ) {
                for (int c4 = c3; --c4 >= 1; ) {
                    for (int c5 = c4; --c5 >= 0; ) {
                        nHand[checkHand(c1, c2, c3, c4, c5)] += 1;
                        ++cnt;
                    }
                }
            }
        }
    }
    cout << "finished.\n";
    cout << "cnt = " << cnt << "\n";
    for (int i = 0; i < N_KIND_HAND; ++i) {
        cout << nHand[i] << " " << nHand[i] * 100.0 / cnt << "% "
        << handName[i] << "\n";
    }

実行結果:

finished.
cnt = 2598960
1302540 50.1177% highCard
1098240 42.2569% onePare
123552 4.7539% twoPare
54912 2.11285% theeOfAKind
10200 0.392465% straight
5108 0.19654% flush
3744 0.144058% fullHouse
624 0.0240096% fourOfAKind
40 0.00153908% straightFlush

7枚から5枚を選ぶ場合

    int nHand[N_KIND_HAND] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
    int cnt = 0;
    for (int c1 = 52; --c1 >= 6; ) {
        for (int c2 = c1; --c2 >= 5; ) {
            for (int c3 = c2; --c3 >= 4; ) {
                for (int c4 = c3; --c4 >= 3; ) {
                    for (int c5 = c4; --c5 >= 2; ) {
                        for (int c6 = c5; --c6 >= 1; ) {
                            for (int c7 = c6; --c7 >= 0; ) {
                                int h =             checkHand(c1, c2, c3, c4, c5);
                                h = std::max(h, checkHand(c1, c2, c3, c4, c6));
                                h = std::max(h, checkHand(c1, c2, c3, c4, c7));
                                h = std::max(h, checkHand(c1, c2, c3, c5, c6));
                                h = std::max(h, checkHand(c1, c2, c3, c5, c7));
                                h = std::max(h, checkHand(c1, c2, c3, c6, c7));
                                h = std::max(h, checkHand(c1, c2, c4, c5, c6));
                                h = std::max(h, checkHand(c1, c2, c4, c5, c7));
                                h = std::max(h, checkHand(c1, c2, c4, c6, c7));
                                h = std::max(h, checkHand(c1, c2, c5, c6, c7));
                                h = std::max(h, checkHand(c1, c3, c4, c5, c6));
                                h = std::max(h, checkHand(c1, c3, c4, c5, c7));
                                h = std::max(h, checkHand(c1, c3, c4, c6, c7));
                                h = std::max(h, checkHand(c1, c3, c5, c6, c7));
                                h = std::max(h, checkHand(c1, c4, c5, c6, c7));
                                h = std::max(h, checkHand(c2, c3, c4, c5, c6));
                                h = std::max(h, checkHand(c2, c3, c4, c5, c7));
                                h = std::max(h, checkHand(c2, c3, c4, c6, c7));
                                h = std::max(h, checkHand(c2, c3, c5, c6, c7));
                                h = std::max(h, checkHand(c2, c4, c5, c6, c7));
                                h = std::max(h, checkHand(c3, c4, c5, c6, c7));
                                nHand[h] += 1;
                                ++cnt;
                            }
                        }
                    }
                }
            }
        }
    }
    cout << "finished.\n";
    cout << "cnt = " << cnt << "\n";
    for (int i = 0; i < N_KIND_HAND; ++i) {
        cout << nHand[i] << " " << nHand[i] * 100.0 / cnt << "% "
        << handName[i] << "\n";
    }

実行結果:

役名場合の数確率
straightFlush415840.0310828%
fourOfAKind2248480.168067%
fullHouse34731842.5961%
flush40476443.02549%
straight61800204.61938%
theeOfAKind64616204.82987%
twoPare3143340023.4955%
onePare5862780043.8225%
highCard2329446017.4119%
Total133784560100%
cnt = 133784560
23294460 17.4119% highCard
58627800 43.8225% onePare
31433400 23.4955% twoPare
6461620 4.82987% theeOfAKind
6180020 4.61938% straight
4047644 3.02549% flush
3473184 2.5961% fullHouse
224848 0.168067% fourOfAKind
41584 0.0310828% straightFlush