🐕

レッドカードって強いの?シミュレーションで検証してみました

2024/12/17に公開

はじめに

ポケポケでデッキ構築しているとサカキかナツメかそれともレッドカードか最後の1枚をどれにするか悩むことってありますよね
特に2進化ポケモン完成を遅延する目的でレッドカードを組み込むことがあると思いますがその価値はいったいどれほどでしょうか?
実際にシミレーションを行うプログラムを作成して検証してみました

前提

これからの話は2進化ポケモン一般に当てはまる内容ですが便宜上ミューツーデッキにおける2進化を例に説明します
まずサーナイトの遅延を目的としたレッドカードが強いシチュエーションというのは相手のラルトスもしくはキルリアが場に出た直後のターンで相手の手札が4枚以上のときです
これはポケモンを場に出したターンにはそのポケモンは進化ができないというこのゲームの制約のためです

どうするか?

以前プログラムによるシミレーションの結果最速サナの確率は38%という記事を書きましたがこのときは簡単のためレッドカードを考慮していませんでした
https://zenn.dev/nwn/articles/94f7e943cc3ecc
今回このプログラムに上記のシチュエーションが発生した場合に相手の手札にレッドカードがあれば常に使用してくることを仮定してプログラムを修正しどの程度遅延効果が見込めるかを検証してみたいと思います

なお今回も簡単のため以下の制約のもとプログラムを作成しています

  • モンスターボール、博士の研究が手札にある時は常にモンスターボール、博士の研究の順序で使用する
  • たねポケモンが手札にある時は常にすべて場に出す
  • 進化できるときは常に進化する

検証

レッドカードが手に入る確率は?

まずターン別に手札にレッドカードが存在する確率をシミュレーションによって求めます
今回はデッキに含まれるレッドカードの枚数を1枚として検証を行いました

コードはこちらになります

# レッドカードの確率
import random

def simulate(basic_num, red_num):
  deck = ['research']*2 + ['ball']*2 + ['red']*red_num + ['basic']*basic_num
  deck += ['dummy']*(20-len(deck))

  # たねポケモンが1体以上含まれるまで初期手札を生成
  while True:
    random.shuffle(deck)
    hand = deck[:5]
    if 'basic' in hand:
      break
  deck = deck[5:]

  for turn in range(1, 100):
    if len(deck):
      hand.append(deck.pop(0))
    # モンスターボール使用
    for i in range(hand.count('ball')):
      hand.remove('ball')
      if 'basic' in deck:
        deck.remove('basic')
        hand.append('basic')

    # 博士の研究使用
    if 'research' in hand:
      hand.remove('research')
      for i in range(min(len(deck), 2)):
        hand.append(deck.pop(0))

    if 'red' in hand:
      return turn

SIMULATE_NUM = 100000
BASIC_NUM = 5
RED_NUM = 1
turns = [simulate(BASIC_NUM, RED_NUM) for i in range(SIMULATE_NUM)]
count = { i: 0  for i in range(1,100)}
for turn in turns:
  count[turn] += 1
result = {key: value / SIMULATE_NUM for key, value in count.items()}
sum = 0
red_propability ={}
for key, value in result.items():
  sum += value
  red_propability[key] = sum
for key, value in red_propability.items():
  print(f'{key}ターンまでに手札に存在: {round(value*100, 2)}%')
  if(key == 10):
    break

実行結果を表にまとめるとこちらになります

1ターン以内に所持している確率 34.33%
2ターン以内に所持している確率 43.42%
3ターン以内に所持している確率 50.77%
4ターン以内に所持している確率 58.24%
5ターン以内に所持している確率 65.68%
6ターン以内に所持している確率 73.08%
7ターン以内に所持している確率 80.38%
8ターン以内に所持している確率 87.68%
9ターン以内に所持している確率 94.95%

なおこの結果はたねポケモン以外の任意のカードについても当てはまります

サーナイト完成の確率は?

次にここで算出をした確率をもとにレッドカードの処理を加えたコードがこちらになります

import random

def simulate(basic_num, is_first):
  deck = ['research']*2 + ['ball']*2 + ['ralts']*2 + ['kirlia']*2 + ['gardevoir']*2 + ['basic']*basic_num
  deck += ['dummy']*(20-len(deck))

  # たねポケモンが1体以上含まれるまで初期手札を生成
  while True:
    random.shuffle(deck)
    hand = deck[:5]
    basics_in_hand = list(filter(lambda c: c in ["ralts", 'basic'], hand))
    if len(basics_in_hand):
      break
  deck = deck[5:]

  # レッドカードが使用済みか?
  is_used = False
  # 直前のターンでラルトスorキルリアが場に出たか?
  is_do = False

  # たねポケモンをセット
  field = []
  field += basics_in_hand
  # ラルトスがセットされたときis_doをTrue
  if 'ralts' in basics_in_hand:
    is_do = True
  for basic in basics_in_hand:
    hand.remove(basic)

  for turn in range(1, 100):
    # レッドカードの処理
    # 先手の1ターン目以外 and 直前のターンにラルトスorキルリアが出た and ハンドが4枚以上 and レッドカードが使われていない とき
    # そのターンまでにレッドカードを所持している確率で発動
    rival_turn = turn - 1 if is_first else turn
    if not (is_first and turn == 1) and is_do and 4 <= len(hand) and not is_used and random.random() < red_propability[rival_turn]:
      is_used = True
      deck += hand
      random.shuffle(deck)
      hand = deck[:3]
      deck = deck[3:]
    is_do = False

    # ドロー
    if len(deck):
      hand.append(deck.pop(0))
    
    # モンスターボール使用
    for i in range(hand.count('ball')):
      hand.remove('ball')
      basics_in_deck = list(filter(lambda c: c in ["ralts", 'basic'], deck))
      if(len(basics_in_deck)):
        basic = basics_in_deck[0]
        deck.remove(basic)
        hand.append(basic)

    # 博士の研究使用
    if 'research' in hand:
      hand.remove('research')
      for i in range(min(len(deck), 2)):
        hand.append(deck.pop(0))

    # 1ターン以外の時進化の処理
    if turn!= 1:
      evolutions = []
      for candidate in hand:
          if candidate == 'kirlia' and 'ralts' in field:
              field.remove('ralts')
              evolutions.append('kirlia')
              # キルリアが場に出た時is_doをTrue
              is_do = True
          if candidate == 'gardevoir' and 'kirlia' in field:
              field.remove('kirlia')
              evolutions.append('gardevoir')
      for c in evolutions:
          hand.remove(c)
      field += evolutions

    # たねポケモンを出す
    basics_in_hand = list(filter(lambda c: c in ["ralts", 'basic'], hand))
    field += basics_in_hand
    for basic in basics_in_hand:
      hand.remove(basic)
    # ラルトスが場に出されたときis_doをTrueに
    if 'ralts' in basics_in_hand:
      is_do = True

    # サーナイトが場にいるときターン数を返してシミュレーションを終了
    if 'gardevoir' in field:
      return turn

SIMULATE_NUM = 100000
BASIC_NUM = 3
IS_FIRST = False
turns = [simulate(BASIC_NUM, IS_FIRST) for i in range(SIMULATE_NUM)]
count = { i: 0  for i in range(1,100)}
for turn in turns:
  count[turn] += 1
result = {key: value / SIMULATE_NUM for key, value in count.items()}
print(f'追加のたねポケモンが{BASIC_NUM}体の場合')
sum = 0
for key, value in result.items():
  sum += value
  print(f'{key}ターン目で揃う確率: {round(value*100, 2)}%(累計: {round(sum*100, 2)}%)')
  if key == 10:
    break

なお前回のコードでは先攻後攻の考慮はされていませんが今回の変更では区別するように変更しました
レッドカードを考慮すると後攻の場合先行の場合と異なり1ターン開始前にレッドカードを使用される可能性があるという非対称性があるからです

実行結果を表にまとめるとこちらになります
定番のミューツーデッキのたねポケモン5枚の構成で実行しています

レッドカード無 レッドカード有(先手) レッドカード有(後手)
1ターン以内に完成する確率 0.00% 0.00% 0.00%
2ターン以内に完成する確率 0.00% 0.00% 0.00%
3ターン以内に完成する確率 38.34% 33.51% 31.55%
4ターン以内に完成する確率 52.83% 46.70% 44.45%
5ターン以内に完成する確率 65.85% 58.88% 56.62%
6ターン以内に完成する確率 77.35% 69.70% 67.72%
7ターン以内に完成する確率 86.74% 78.70% 77.23%
8ターン以内に完成する確率 93.66% 85.84% 84.94%
9ターン以内に完成する確率 97.74% 91.17% 90.66%

レッドカード持ちの相手に対して後攻2ターン目でのサーナイト完成いわゆる最速サナの確率は7%ほど下がることがわかりました
全体的にみてもおおよそ0.5ターン程度の遅延効果があることがわかります
また後手のほうが影響が大きいという結果も興味深いですね

まとめ

いかがでしたか?
思っていたよりも強いなと感じる方が多いのではないでしょうか?

ぜひこの結果を参考にレッドカード使ってみてください!

Discussion