Dominionにおける尺度の一つ 明確な定義をまだ見つけてない。 デッキがコインだけで構成されてる時にはそのコイン価値の平均になる値。 参考動画 単純な構成だと人間の計算で解けるが、複雑になると計算できなくて近似したり計算を諦めたりしてるみたい

じゃあプログラムで計算しよう。 一番素朴な方法はデッキの全順列についての集計をすること

  • だが、これだと計算量は階乗になる
  • デッキ11枚で1秒くらい、12枚なら12秒で13枚なら2〜3分になる(計算量の見積もり)
  • 無理ではないがちょっと時間掛かるね。
  • もう少し頭を使った実装にしよう。

デッキから5枚取ったcombinationを求めて、それに対してコインの総和の平均を集計する。 python

from itertools import combinations


def hand_to_coins(hand):
    return sum([1 for c in hand if c == '1'])


deck = "1111111EEE"
hands = list(combinations(deck, 5))


N = len(hands)
s = sum(hand_to_coins(hand) for hand in hands)

print(N)
print(s/N)

全部で252通り(10C5)の可能性があり、平均は3.5となる。

  • 参考動画では初期デッキの平均金量は0.7と言ってる
    • 参考動画の「平均金量」は「カード1枚の」で、ぼくが求めたのは「手札の」なので5倍ズレるのだな。
    • この後の予定を考えるとカード1枚のを計算するのは話がややこしくなるので、手札のを計算したい。
    • 参考動画の「平均金量」とは別の名前をつけた方がいいな。
    • 僕が求めたいものは「ランダムに手札を作った後、アクションを実行した後に購入フェーズで購入できるのは何コイン分か」という値なので「平均購買力」と呼ぶことにしよう。
    • デッキにコインしかない場合は、アクションがないのだから平均購買力は平均金量の5倍になる。

整理しつつ、ついでに「購入可能確率」も計算できるようにした python

from itertools import combinations


def hand_to_coins(hand):
    return sum([int(c) for c in hand if c in '123'])


def calc(deck, cost=5):
    hands = list(combinations(deck, 5))
    N = len(hands)
    c = sum(hand_to_coins(hand) for hand in hands) / N
    p = sum(1 for hand in hands if hand_to_coins(hand) >= cost) / N * 100
    print(f"{c:.2f}({c/5:0.2f}) {p:.1f}%")


deck = "1111111EEE"
calc(deck)  # => 3.50(0.70) 8.3%
deck += "22"
calc(deck)  # => 4.58(0.92) 53.0%

結果

  • 初期デッキの平均購買力は3.5(0.7 * 5)で、5金のカードが買える確率は8.3%
  • 銀貨を2枚買うと平均購買力は4.58(0.92 * 5)で、5金のカードが買える確率は53.0%
    • 参考動画の解説では平均金量は0.917とされてる。この差は僕が小数点以下2桁までで四捨五入してるから。

ではここで鍛冶屋を買った場合はどうなるか、を計算したい。 手札にアクションカードがある場合には実行する、今のところ鍛冶屋だけで、アクションが増えるカードは考えない。(ソースコードは後で) 結果

  • 初期デッキ+銀貨+鍛冶屋
    • 4.77(0.95) 61.1%
  • 初期デッキ+2銀貨+鍛冶屋
    • 5.29(1.06) 70.6%
      • 参考動画では1.058とされてる。四捨五入したら同じ

ここまでは参考動画と一致する アクションカードが2枚になったらどうなるか?

  • 初期デッキ+2銀貨+2鍛冶屋
    • 5.44(1.09) 79.6%
      • 参考動画では1.058とされてる。ここで初めて参考動画の平均金量の5倍と平均購買力が一致しなくなる

こちらの平均購買力の計算をブレイクダウンしてみる

  • 手札に鍛冶屋がいない場合
    • これは鍛冶屋を除く12枚から5枚選ぶのだから12C5の792通り、初期デッキ+2銀貨と同じ平均購買力4.58
  • 手札に鍛冶屋が2枚の場合
    • 残り3枚が12枚から選ばれるので12C3の220通り。最終的に12枚から6枚選ばれるので「初期デッキ+2銀貨」の平均金量0.916の6倍、5.50
  • 手札に鍛冶屋が1枚の場合
    • 鍛冶屋1が手札にあり、残り4枚を12枚から選ぶと495通り。鍛冶屋2が手札にある場合も同様なので併せて990通り。
    • この場合、アクション不足で使えない鍛冶屋1枚を含む13枚から7枚選ぶことになる。
    • ただし、4枚は先に選んでいるので単純にこの場合の平均金量を7倍してはいけない。
      • それは先に手札に入ってる4枚に鍛冶屋が入る場合をダブルカウントしてしまう
      • 12枚から先に手札に入った4枚を取り除いた8枚を考える
    • 鍛冶屋での3枚のドローに鍛冶屋が入るかどうかで場合わけが必要
      • 入らない場合、8枚から3枚を選ぶ56通りで、12枚の平均金量0.916の7倍が得られる
      • 入る場合、8枚から2枚を選ぶ28通りで、12枚の平均金量0.916の6倍が得られる
      • この加重平均6.11が「手札に1枚だけ鍛冶屋がある場合の平均購買力」
  • この3通りの加重平均5.44がこの場合の平均購買力

考察

  • 平均購買力がこれに一致することはシミュレーションしてこの値に収束することでも示せる
    • 平均金量に関しては何を観測すればわかる値なのかが不明瞭なので検証ができない。
  • 平均購買力の計算上で必要になってる「手札やドローに何枚鍛冶屋があるのかによる場合わけ」をしないで計算している値だから食い違うのだろう。
    • でもその値を使ってても強くなれてる
    • なので平均購買力の1/5である1.09と、平均金量1.058の差は強くなる上で重要ではないということ
      • まあ銅貨の1/30くらいの値だし、そりゃそうだ
      • つまり平均金量は平均購買力の近似計算手法
  • コンピュータで計算するときは平均購買力を計算する方が楽。

2022-02-21 礼拝堂圧縮と平均購買力

  • 初期デッキ 1111111eee
    • 3.50(0.70) 8.3%
  • 礼拝堂cと5コストカードXを買ったとする
    • 礼拝堂が屋敷3枚と一緒に出た場合eee1c
      • 4枚捨てると 111111cX
        • 3.75(0.75) 10.7%
      • 屋敷だけ捨てると 1111111cX
        • 3.89(0.78) 16.7%
    • 屋敷2枚と出た場合ee11c
      • 4枚捨てると11111ecX
      • 3.12(0.62) 1.8%
      • 111111ecX
      • 3.33(0.67) 4.8%
      • 1111111ecX
      • 3.50(0.70) 8.3%
    • e111c
      • 1111eecX
      • 2.50(0.50) 0.0%
      • 11111eecX
      • 2.78(0.56) 0.8%
      • 111111eec2X
      • 3.64(0.73) 21.9%
    • 1111c
      • 111eeec
      • 2.14(0.43) 0.0%
      • 1111eeec
      • 2.50(0.50) 0.0%
      • 11111eeec
      • 2.78(0.56) 0.8%
      • 111111eeec2
      • 3.64(0.73) 21.9% 平均購買力の観点では銅貨を残した方が常に良いので、回転力の効果が定量化されないと意味がないな

鍛冶屋ステロシミュレーション