ポケポケのガチャ何回回すとカードが全て集まるかシュミレーションしてみた

# はじめに

皆さん、ポケポケを楽しんでいますか？私はリリース当初ほどの熱は無くなりましたが、いまでも毎日ガチャを回しています。
ふと、全カードを集めるのに何回くらいガチャを回せば良いのか気になり調べてみました。

* **ガチャ排出テーブル** の整理
* **クーポンコレクター問題** を用いた “理論上の必要パック数” の算出
* Python による **モンテカルロシミュレーション** での実測分布
をステップごとにまとめています。

---

# 前提条件
* 今回は現時点で最新の**双天の守護者**パックで計算します。ソルガレオ／ルナアーラの2種類あり、一部両パックで排出されるカードがありますが一旦別として考えます。（低レアのカードがほとんどなのでほぼ影響はないと思われます。）
* ごく稀にゴットパックと言われるレアカードが大量に入ったパックが出現しますが、0.05%とかなり確率が低いのでこれも無視します。

---

# ガチャ排出テーブル
レアリティ別のカードの排出確率です。
1回のガチャで5枚カードを引くことが出来て、何枚目かで確率が変わります。
最近色違いが導入されて以前と確率が若干変わっていますね。◆1と◆2の確率がその分若干下がっています。


| レアリティ     | 1〜3 枚目    | 4 枚目         | 5 枚目         |
| --------- | --------- | ------------ | ------------ |
| ◆1        | **100 %** | 0%           | 0%           |
| ◆2        | 0%　       | **89.000 %** | **56.000 %** |
| ◆3        | 0%　       | **4.952 %**  | **19.810 %** |
| ◆4        | 0%  　     | **1.666 %**  | **6.664 %**  |
| ☆1 (色違い1) | 0%       | **0.714 %**  | **2.857 %**  |
| ☆2 (色違い2) | 0%       | **0.333 %**  | **1.333 %**  |
| ★1        | 0%        | **2.572 %**  | **10.288 %** |
| ★2        | 0%        | **0.500 %**  | **2.000 %**  |
| ★3        | 0%        | **0.222 %**  | **0.888 %**  |
| 👑        | 0%        | **0.040 %**  | **0.160 %**  |

参考 : https://game8.jp/pokemon-tcg-pocket/650713

---

# カード枚数（片方のデッキ）
**双天の守護者**パックでの各レアリティの枚数をアプリ内で確認したものになります。ソルガレオ／ルナアーラで枚数は完全に一致しています。

| レアリティ  | 枚数      |
| ------ | ------- |
| ◆1     | 44      |
| ◆2     | 34      |
| ◆3     | 14      |
| ◆4     | 5       |
| ★1     | 12      |
| ★2     | 14      |
| ★3     | 1       |
| ☆1     | 10      |
| ☆2     | 4       |
| 👑     | 2       |
| **合計** | **140** |

---

# 期待ガチャ回数の算出
調べてみるとクーポンコレクター問題が今回適用できそうだったので、これで算出してみます。

## クーポンコレクター問題とは？
https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%BC%E3%83%9D%E3%83%B3%E3%82%B3%E3%83%AC%E3%82%AF%E3%82%BF%E3%83%BC%E5%95%8F%E9%A1%8C

簡単にまとめると、
$n$ 種類 のアイテムをランダムに集めるとき、**全部そろうまでの期待枚数**は
$n \times H_n$
で求まります。ここで
$H_n = 1 + 1/2 + … + 1/n$
は *n* 番目の調和数です。

1 パックで目的レアが平均 $p$ 枚出るなら
$\boxed{\text{必要パック数} = \dfrac{n H_n}{p}}$
となります。


## 各レアリティごとの期待ガチャ回数
以下のように算出できます。

| レア |  n |  $H_n$ | $nH_n$ | *p* (枚/pack) |    期待ガチャ回数 |
| -- | -: | -----: | -----: | -----------: | --------: |
| ◆1 | 44 | 4.3727 |  192.4 |       3.0000 |    **64** |
| ◆2 | 34 | 4.1183 |  140.0 |       1.4500 |    **97** |
| ◆3 | 14 | 3.2516 |   45.5 |       0.2476 |   **184** |
| ◆4 |  5 | 2.2833 |   11.4 |       0.0833 |   **137** |
| ★1 | 12 | 3.1032 |   37.2 |       0.1286 |   **290** |
| ★2 | 14 | 3.2516 |   45.5 |       0.0250 | **1 821** |
| ★3 |  1 | 1.0000 |    1.0 |       0.0111 |    **90** |
| ☆1 | 10 | 2.9290 |   29.3 |       0.0357 |   **820** |
| ☆2 |  4 | 2.0833 |    8.3 |       0.0167 |   **500** |
| 👑 |  2 | 1.5000 |    3.0 |       0.0020 | **1 500** |

ここで、それぞれのレア度の確率は独立で、全てのレア度について同時にガチャ抽選が行われるため、一番期待ガチャ回数が大きいレア度での値が全体のカードの期待ガチャ回数になります。
つまり、★2の期待ガチャ回数の1821回が各パックでの全カードを集める際のガチャ回数の期待値になります。
（私は微課金勢なので◆までしか集めませんが、その場合だと184回が期待値になります。）
また、これは片方のパックのみでの算出なので、ソルガレオ／ルナアーラの両方で集めるなら倍の回数ガチャを回すことになります。
個人的には◆4より◆3の方が期待ガチャ回数が大きいのが面白いと感じました。例えばゲットチャレンジで集めるなら◆3の方がコスパがいいと言えると思います。

---

# シミュレーション

最後にCHATGPTにシミュレーション用のコードを書いてもらいました。
何回ガチャを回して指定のレアリティのカードが全て集まるかを10000回繰り返し、結果をヒストグラムで可視化しています。

```python
import random
import numpy as np
import matplotlib.pyplot as plt

# -----------------------------
# 1) 設定
# -----------------------------
SIMS = 10000                      # 試行回数


# -----------------------------
# 2) 封入データ
# -----------------------------
# レアリティごとの枚数
rarities_counts = {
    "◆1": 44, "◆2": 34, "◆3": 14, "◆4": 5,
    "★1": 12, "★2": 14, "★3": 1,
    "☆1": 10, "☆2": 4, "👑": 2,
}
# 全レアリティを指定
TARGET_RARITIES = rarities_counts.keys()
# TARGET_RARITIES = ["◆4", "★1", "☆1"]   # 取得したいレアリティを絞る場合はこれを使用

cards_by_rarity = {
    r: [f"{r}_{i+1}" for i in range(n)]
    for r, n in rarities_counts.items()
}

slot4_probs = [
    ("◆2", 89.000), ("◆3", 4.952), ("☆1", 0.714), ("☆2", 0.333),
    ("◆4", 1.666), ("★1", 2.572), ("★2", 0.500), ("★3", 0.222), ("👑", 0.040),
]
slot5_probs = [
    ("◆2", 56.000), ("◆3", 19.810), ("☆1", 2.857), ("☆2", 1.333),
    ("◆4", 6.664), ("★1", 10.288), ("★2", 2.000), ("★3", 0.888), ("👑", 0.160),
]

def sample_rarity(table):
    r = random.random() * 100
    cum = 0
    for rarity, prob in table:
        cum += prob
        if r < cum:
            return rarity
    return table[-1][0]

# -----------------------------
# 3) シミュレーション
# -----------------------------
target_cards = {card for r in TARGET_RARITIES for card in cards_by_rarity[r]}
packs_needed = []

for _ in range(SIMS):
    have = set()
    packs = 0
    while len(have) < len(target_cards):
        packs += 1
        # 1–3 枠（必ず ◆1）
        for _ in range(3):
            c = random.choice(cards_by_rarity["◆1"])
            if c in target_cards:
                have.add(c)
        # 4 枠
        c4 = random.choice(cards_by_rarity[sample_rarity(slot4_probs)])
        if c4 in target_cards:
            have.add(c4)
        # 5 枠
        c5 = random.choice(cards_by_rarity[sample_rarity(slot5_probs)])
        if c5 in target_cards:
            have.add(c5)
    packs_needed.append(packs)

# -----------------------------
# 4) 結果
# -----------------------------
arr = np.array(packs_needed)
print(f"=== Target rarities: {', '.join(TARGET_RARITIES)} ===")
for name, fn in [("Mean", np.mean), ("Median", np.median)]:
    print(f"{name:>8}: {fn(arr):,.1f} packs")
for q in [5, 25, 75, 95]:
    print(f"{q:>8}th %: {np.percentile(arr, q):,.0f} packs")

plt.figure(figsize=(8,5))
plt.hist(arr, bins=30, color="orange")
plt.title(f"Packs Needed to Complete {', '.join(TARGET_RARITIES)} (n={SIMS})")
plt.xlabel("Number of Packs")
plt.ylabel("Frequency")
plt.tight_layout()
plt.show()
```

> 実行結果例
=== Target rarities: ◆1, ◆2, ◆3, ◆4, ★1, ★2, ★3, ☆1, ☆2, 👑 ===
    Mean: 2,198.8 packs
  Median: 1,998.5 packs
       5th %: 1,127 packs
      25th %: 1,560 packs
      75th %: 2,598 packs
      95th %: 3,960 packs

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492492/a26e6bbc-6f2b-4d91-957d-83aa587ec40c.png)

平均2200回と先ほど算出した期待ガチャ回数よりも400回ほどずれていますね。
今回は1回のガチャで5枚カードが出るなど本来のクーポンコレクター問題と条件が異なるのが影響しているんですかね（この辺り詳しくないので理由は分かりません。。）
また、場合によっては全部集めるのに倍以上回数を要する場合もあるようです。

※ちなみに、◆1~◆4に絞ってシミュレーションした結果が以下になります。これも回数が若干多くなってますね
=== Target rarities: ◆1, ◆2, ◆3, ◆4 ===
    Mean: 205.4 packs
  Median: 193.0 packs
       5th %: 117 packs
      25th %: 156 packs
      75th %: 240 packs
      95th %: 338 packs
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492492/2816e5fa-9dd3-4f13-85a3-bc6bbd9492db.png)


---

# まとめ
**クーポンコレクター問題** により理論期待値を算出し、シミュレーションにより実際に必要なガチャ回数とズレがあることを確認しました。
ポイント交換、ゲットチャレンジなど他にもカードを手に入れる方法はありますが、全て集めるには相当な課金が必要な事がわかります。

皆さんのカード収集の参考になれば幸いです！