スート(マーク)が5つ存在するトランプのポーカーにおける役の強さの算出

# 背景

通常のトランプに新しいスートを1つ追加し、5種類のスート（スペード、ハート、ダイヤ、クラブ、**スター**）があるトランプでポーカーを行う場合を考えました。  
通常の52枚のデッキとは異なる65枚のデッキになるため、ポーカーの役の出現確率や強さのバランスが変化する可能性があります。 

今回は、役の完成難易度を基準に新しい役の強弱を算出します。

# 前提条件

通常のトランプは以下の組み合わせで構成されています。

- **ランク**: A（エース）～K（キング）の13ランク  
- **スート**: スペード、ハート、ダイヤ、クラブの4種類

今回の検討では、これに新しいスート「スター（☆）」を追加した**65枚デッキ**を使用しました。
また、各ランクのカードが増え5枚になるため、新しい役である**5カード**も考慮に入れました。

# 結果

以下は、[モンテカルロ法](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%83%86%E3%82%AB%E3%83%AB%E3%83%AD%E6%B3%95)を用いて算出した役の出現確率です。  
役の完成が難しいほど上位に位置し、頻出する役ほど下位に配置しています。

| ランク              | 役名              | 出現確率 (%)   |
|--------------------|------------------|--------------|
| 1                 | Five of a Kind   | 0.0002%      |
| 2                 | Straight Flush   | 0.0006%      |
| 3                 | Four of a Kind   | 0.0475%      |
| 4                 | Flush            | 0.0775%      |
| 5                 | Full House       | 0.1892%      |
| 6                 | Straight         | 0.3771%      |
| 7                 | Three of a Kind  | 2.5979%      |
| 8                 | Two Pair         | 5.1935%      |
| 9                 | One Pair         | 43.2822%     |
| 10                | High Card        | 48.2343%     |


# 算出方法

今回の結果は、Pythonでコードを作成し、[**モンテカルロ法**](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%83%86%E3%82%AB%E3%83%AB%E3%83%AD%E6%B3%95)を用いて計算しました。
以下の手順でシミュレーションを行いました。

1. **デッキの準備**: 65枚デッキを構築（13ランク × 5スート）
2. **シミュレーション**: 1億回の試行を実施
3. **集計**: 各役の出現回数を基に確率を算出

また、実行環境にはColaboratoryを使用しました。

# 補足・考察

スートを追加した場合、役の出現確率は52枚デッキと比較してわずかに変化します。
さらに、Five of a Kind（同ランク5枚）が新たに成立可能な役として加わり、最も珍しい役となります。

脳筋で愚直に書いたコードでぶん回しているので、もっと賢い方法が沢山あるかとは思いますが
急に５スートのポーカーを行いたい場合等、なにかの参考にでもなれば幸いです。


# コード
```python
import random
from collections import Counter
 
# 5スートのデッキを生成
suits = ['Hearts', 'Diamonds', 'Clubs', 'Spades', 'Stars']
ranks = list(range(1, 14))  # 1から13のランクを使用
deck = [(rank, suit) for rank in ranks for suit in suits]
 
def generate_hand(deck):
    """デッキからランダムに5枚の手札を生成"""
    return random.sample(deck, 5)

def straight_judge(ranks):
    """手札がストレートかどうかを判定"""
    ranks = sorted(set(ranks))
    # 通常のストレート
    if len(ranks) == 5 and ranks[-1] - ranks[0] == 4:
        return True
    
    # Aが高いストレート (10, J, Q, K, A)
    if set(ranks) == {10, 11, 12, 13, 1}:
        return True
    
    return False

def classify_hand(hand):
    """手札の役を判定"""
    ranks = [card[0] for card in hand]
    suits = [card[1] for card in hand]
    rank_counts = Counter(ranks)
    unique_ranks = len(rank_counts)
    is_flush = len(set(suits)) == 1
    is_straight = straight_judge(ranks)

    # 役の判定
    if is_flush and is_straight:
        return 'Straight Flush'
    elif 5 in rank_counts.values():
        return 'Five of a Kind'
    elif 4 in rank_counts.values():
        return 'Four of a Kind'
    elif 3 in rank_counts.values() and 2 in rank_counts.values():
        return 'Full House'
    elif is_flush:
        return 'Flush'
    elif is_straight:
        return 'Straight'
    elif 3 in rank_counts.values():
        return 'Three of a Kind'
    elif list(rank_counts.values()).count(2) == 2:
        return 'Two Pair'
    elif 2 in rank_counts.values():
        return 'One Pair'
    else:
        return 'High Card'

def simulate_poker_hands(deck, num_simulations=1000000):
    """ポーカーの役の頻度をシミュレーションで求める"""
    results = Counter()

    for _ in range(num_simulations):
        hand = generate_hand(deck)
        hand_type = classify_hand(hand)
        results[hand_type] += 1

    # 頻度の低い順にソート
    sorted_results = sorted(results.items(), key=lambda x: x[1])
    for hand_type, count in sorted_results:
        print(f"{hand_type}: {count / num_simulations:.4%} ({count}/{num_simulations})")

simulate_poker_hands(deck, num_simulations=[100000000])
```

実行結果
```
Five of a Kind: 0.0002%　(193/100000000)
Straight Flush: 0.0006%　(599/100000000)
Four of a Kind: 0.0475%　(47527/100000000)
Flush: 0.0775%　(77484/100000000)
Full House: 0.1892%　(189180/100000000)
Straight: 0.3771%　(377109/100000000)
Three of a Kind: 2.5979%　(2597850/100000000)
Two Pair: 5.1935%　(5193488/100000000)
One Pair: 43.2822%　(43282250/100000000)
High Card: 48.2343%　(48234320/100000000)
```

# オマケ
友人が5種類のスートのトランプがあると言ってたので計算しました。
が後々、5色目は絵札(J,Q,K)にしか存在しなかったことが発覚しました。
ので、再計算しました。

デックを新しく作成
```python
 # 通常の4スート（1〜13）
suits = ["hearts", "spades", "diamonds", "clubs"]
normal_deck = [(rank, suit) for suit in suits for rank in range(1, 14)]

# 5つ目のスート（絵札のみ）
special_suit = "Stars"
special_deck = [(rank, special_suit) for rank in range(11, 14)]

# 通常デックと特殊デックを結合
full_deck = normal_deck + special_deck
```

実行結果
```
Five of a Kind: 0.0001%　(103/100000000)
Straight Flush: 0.0012%　(1160/100000000)
Four of a Kind: 0.0364%　(36352/100000000)
Flush: 0.1466%　(146588/100000000)
Full House: 0.1662%　(166160/100000000)
Straight: 0.3723%　(372269/100000000)
Three of a Kind: 2.3594%　(2359381/100000000)
Two Pair: 4.9566%　(4956575/100000000)
One Pair: 42.7408%　(42740784/100000000)
High Card: 49.2206%　(49220628/100000000)
```