1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ポーカーの組み合わせは何通りあるか

Last updated at Posted at 2020-08-22

はじめに

前回に紹介した、組み合わせ処理を使って、ポーカー・ハンド(役)の組み合わせが全部で何通りあるかを検証します。

ソースコード

検証用のソースコードを実装しました。

poker.d
struct Combinations(T) {
  import std.traits: Unqual;
  
  Unqual!T[] pool, front;
  size_t[] index;
  size_t n, r;
  bool empty = false;
  
  this(T[] pool_, in size_t r_) pure nothrow @safe {
    this.pool = pool_.dup;
    this.n = pool.length;
    this.r = r_;
    if (r > n){
      empty = true;
    }
    front.length = r;
    index.length = r;
    foreach ( i; 0 .. r){
      front[i] = pool[i];
      index[i] = i;
    }
  }
  void popFront() pure nothrow @safe {
    if (!empty) {
      bool broken = false;
      size_t pos;
      foreach_reverse (immutable i; 0 .. r) {
        pos = i;
        if (index[i] != i + n - r) {
          broken = true;
          break;
        }
      }
      if (!broken) {
        empty = true;
        return;
      }
      index[pos]++;
      foreach (immutable i; pos + 1 .. r){
        index[i] = index[i - 1] + 1;
        front[i] = pool[index[i]];
      }
      front[pos] = pool[index[pos]];
    }
  }
}

Combinations!(T) combinations(T)(T[] items, in size_t k)
{
  return typeof(return)(items, k);
}

int analyzeHand(int[] card) pure
{
  int[5] num;    // 2,3,4...Q,K,A
  int[13] sheet;
  int[5] kind;
  bool same = true;
  
  for ( int j = 0; j < card.length; j++ ){
    num[j] = card[j] >> 2;
    sheet[num[j]]++;
    if ( (card[0] & 0x03) != (card[j] & 0x03) ){
      same = false;
    }
  }
  for ( int j = 0; j < sheet.length; j++ ){
    kind[sheet[j]]++;
  }
  switch ( kind[0] ){
    case 9:
      return( 8 );                // 8(One pair)
    case 10:
      return( kind[3] ? 6 : 7 );  // 6(Three of a kind) 7(Two pair)
    case 11:
      return( kind[4] ? 2 : 3 );  // 2(Four of a kind) 3(Full house)
    default:
      int x = num[0];
      if ( (num[1] == x + 1 && num[2] == x + 2 && num[3] == x + 3)
        && (num[4] == x + 4 || (num[0] == 0 && num[4] == 12)) ){
        // 0(Royal flush) 1(Straight flush) 5(Straight)
        return( same ? ((num[0] == 8) ? 0 : 1) : 5 );
      } else {
        return( same ? 4 : 9 );  // 4(Flush) 9(High Cards)
      }
  }
}

int analyzeSevenHand(int[] card) pure
{
  import std.algorithm.comparison: min;
  
  int hand = 9;  // 9(High Cards)
  foreach ( c; card.combinations(5) ){
    hand = min(hand, c.analyzeHand);
  }
  return ( hand );
}

string[] name = [
  "Royal flush","Straight flush","Four of a kind","Full house","Flush",
  "Straight","Three of a kind","Two pair","One pair","High Cards"
];

void calculate(string msg, int n, int function(int[]) fp)
{
  import std.stdio;
  import std.range: array, iota;
  
  writeln(msg);
  int[10] hand;
  foreach ( card; 52.iota.array.combinations(n) ){
    hand[fp(card)]++;
  }
  for ( int j = 0; j < hand.length; j++ ){
    writefln("%-20s %10d", name[j], hand[j]);
  }
}

void main() {
  calculate("Poker hand", 5, &analyzeHand);
  calculate("Seven card stud", 7, &analyzeSevenHand);
}

ソースコード補足説明

struct Combinations(T)は、組み合わせを取得するための構造体です。
emptyfrontpopFrontを用意することで、Rangeの仕組みを利用しています。
D言語 Rangeについて

struct Combinations(T)UFCSで使いやすくするために、関数Combinations!(T) combinations(T)(T[] items, in size_t k)を用意しています。

analyzeHandは、ポーカーの役を判定するための関数です。
引数のcardは大きさ5の配列で、トランプのカードを表す数値(0~51)が入っている前提です。

カードを表す数値(0~51)は、

  • 下位2ビットでトランプのマーク(♠、♦、♥、♣)を表現
  • 残りのビットでトランプの数字(0~12を2, 3, 4 ... Q, K, Aに割り当て)を表現

戻り値は、ポーカーの役を表す数値(0~9)です。定数定義をさぼって、コメントで補足しています。

関数中のswitch ( kind[0] )を使って、ペアになっていないカードの数を判定しています。
kind[3]1であれば同じ数字が3枚、kind[4]1であれば同じ数字が4枚そろっていることになります。

実行結果

ポーカーの役の組み合わせを2パターン算出しました。

  • 最初に配られた5枚でのポーカーの役の組み合わせ(ポーカー・ハンド)
  • 最初に配られた7枚から5枚を選んだ最善のポーカーの役の組み合わせ(セブンカード・スタッド)
実行結果
Poker hand
Royal flush                   4
Straight flush               36
Four of a kind              624
Full house                 3744
Flush                      5108
Straight                  10200
Three of a kind           54912
Two pair                 123552
One pair                1098240
High Cards              1302540
Seven card stud
Royal flush                4324
Straight flush            37260
Four of a kind           224848
Full house              3473184
Flush                   4047644
Straight                6180020
Three of a kind         6461620
Two pair               31433400
One pair               58627800
High Cards             23294460

参考情報

実行結果が正しいかどうかを以下のサイトで確認しています。

ポーカー・ハンドの一覧

D言語 組み合わせの実装例

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?