ドミニオンでいつ勝利点購入に切り替えると有利か
1行まとめ:ドミニオンでコイン戦略をする場合、10ターン目で勝利点購入に切り替えるのが一番有利だった
今までの話
でわかったように、アクションカードを一切買わなくても12ターン目には平均コインが1.63になるので、1デッキが平均8コインを超えるようになる。つまりその頃には属州が買えるターンもあるってことだ。ここで問題になるのは「いつコイン購入から勝利点購入に切り替えるか」だ。焦って早く買ってはコイン濃度が薄まってしまい、後で伸び悩む。一方、コイン濃度を高めてから買いはじめれば勝利点の獲得速度は早いが、追いつく前にゲームが終わってしまう。
周りのプレイヤーがどう行動するかによって大きな影響を受けるだろうと思ったので、「nターン目手前までは金貨か銀貨を買う。nターン目以降は購入できる最も高い勝利点を買う。勝利点が買えない場合は金貨や銀貨を買う」という戦略でnを変えた4人のプレイを10000回ずつシミュレーションした。
10, 10, 10, 20のとき、ゲーム終了時に獲得した勝利点の平均と標準偏差は
player 0 38.4287 4.46966624145 player 1 38.3893 4.52960765519 player 2 38.4571 4.57748398031 player 3 13.7286 7.82187586452
と10ターン目から3人が勝利点を買い始めているのに10ターンほど遅れると完全に出遅れて、平均で25点も差がついてしまう。
遅れが5ターンくらいだったらどうだろう?10, 15, 10, 10のとき
player 0 34.0452 3.95185487588 player 1 23.1996 6.612349041 player 2 33.7394 3.9206233739 player 3 33.8632 3.99002327813
それでも10点ほど出遅れてしまう。
2ターン差だったら?
10, 10, 12, 10の場合
player 0 31.7152 4.23264562183 player 1 31.8004 4.28403546204 player 2 29.1521 5.47075548622 player 3 31.6406 4.27626374771
平均ではやはり2〜3点出遅れているが、標準偏差が4〜5点あるのでこの程度の差であれば運次第で逆転しうる。
12ターン開始の人が少数派だからまけるということも考えられる?12, 10, 12, 10の時
player 0 28.8797 4.86765116971 player 1 32.0421 3.97332701775 player 2 28.9603 4.95125478137 player 3 31.9745 3.95330870917
やはり12ターン開始の人が出遅れている。
12, 10, 12, 12でも
player 0 28.7421 4.55216295732 player 1 32.1273 3.75575487885 player 2 28.9181 4.47363301915 player 3 28.8409 4.49593006952
「やはり12ターン開始と10ターン開始では10ターン開始の方が有利」ってのは何人が10点開始を選ぶかには無関係みたいだね。
じゃあもっと手前に開始するとどうなるのかな?8, 10, 8, 8のとき
player 0 31.69 5.29408160118 player 1 36.8734 5.83316144471 player 2 31.5036 5.26218462618 player 3 31.7262 5.27483019253
おやおや、逆転した。8ターン開始よりは10ターン開始の方が有利?
8, 10, 8, 10の時
player 0 30.8428 4.89545586846 player 1 34.7508 5.42166942556 player 2 30.8484 4.81404377213 player 3 34.7647 5.48778041744
10, 10, 8, 10の時
player 0 33.1002 5.02897205799 player 1 32.916 5.01730445558 player 2 30.5101 4.3520682428 player 3 33.1524 4.99991742332
ふむふむ、8ターン開始よりは10ターン開始の方が有利なのか。
もちろん戦略に関係なく無条件に10ターン開始が有利ってわけではあるまい。おそらく「コイン密度がある程度の量に達したら勝利点購入を始めるべき」ということなんだろう。あと当たり前だけども20枚中32コインの1.6と40枚中64コインの1.6では勝利点を買った時の薄まる速度が異なるので後者のほうが有利なわけなので、濃度だけで決まるもんでもないのだろう。
以下ソースコード
from random import shuffle, randint from copy import copy from math import sqrt NUM_TRIAL = 10000 def draw(deck, used, n): if len(deck) < n: shuffle(used) deck.extend(used) used = [] hand = deck[:n] deck = deck[n:] return deck, used, hand def count_money(cards): return cards.count("1") + cards.count("2") * 2 + cards.count("3") * 3 def count_vp(cards): return cards.count("E") + cards.count("V3") * 3 + cards.count("V6") * 6 class CoinStrategy: def __init__(self, threshold): self.count = 0 self.threshold = threshold def __call__(self, (deck, used, hand), game): self.count += 1 money = count_money(hand) if self.count < self.threshold: # buy money if money >= 6: used.append("3") elif money >= 3: used.append("2") else: # buy victory point if money >= 8: used.append("V6") game.vp6 -= 1 elif money >= 5 and game.vp3 > 0: used.append("V3") game.vp3 -= 1 elif money >= 2 and game.vp1 > 0: used.append("E") game.vp1 -= 1 elif money >= 6: used.append("3") elif money >= 3: used.append("2") return deck, used, hand class Player: def __init__(self, strat, game): self.used = [] self.deck = list("1111111EEE") shuffle(self.deck) self.strat = strat self.game = game def do_turn(self): self.deck, self.used, hand = self.strat(draw(self.deck, self.used, 5), self.game) self.used += hand class GameManager: def __init__(self): self.vp6 = 12 self.vp3 = 12 self.vp1 = 12 def is_finished(self): return self.vp6 == 0 def test(thresholds): NUM_PLAYER = len(thresholds) sum = [0.0] * NUM_PLAYER sumsq = [0.0] * NUM_PLAYER for _trial in range(NUM_TRIAL): game = GameManager() players = [Player(CoinStrategy(th), game) for th in thresholds] i = randint(0, NUM_PLAYER - 1) while not game.is_finished(): p = players[i] p.do_turn() i = (i + 1) % NUM_PLAYER for i in range(NUM_PLAYER): p = players[i] p.deck += p.used money = count_money(p.deck) vp = count_vp(p.deck) #print "player", i #print money, vp sum[i] += vp sumsq[i] += vp * vp for i in range(NUM_PLAYER): print "player", i print sum[i] / NUM_TRIAL, sqrt(sumsq[i] / NUM_TRIAL - (sum[i] / NUM_TRIAL) ** 2) test([12, 10, 12, 12])