Kurter's Workshop

かーたーによるドミニオンのシミュレーション

属州場の鍛冶屋ステロ

そんなこんなであんなどんな、なんなんだ…

 

 

どうやら、鍛冶屋ステロについてのシミュレーション結果が貼られようとしているわけです。

 

 

最初期の計測なので、シミュレーターの骨格が変わっており、それだけで結果が変わる可能性もあります。

 

f:id:Kurter:20190529221450p:plain

鍛冶屋ステロ 4-3

 

平均は14.57T程度と、だいたい巷で言われている鍛冶屋ステロの速度くらいになっていますね。 

5-2については現状特に検証していませんが、わりと(1Tくらい??)遅くなる気がします。

 

 

 

アルゴリズムの詳細を示します。

鍛冶屋ステロのアルゴリズムは、以下のようにしました。

 

Sub actionAlgorithmProvinceSmithyAdjusted()

  Dim i As Integer
  Dim j As Integer
  Dim k As Integer
  Dim smithyInDeck As Boolean
  smithyInDeck = False
  
  
  If actionNumber = 0 Then
    'Do Nothing
  Else
    If cardInHand(trnP, 20) >= 1 Then
      j = howManyCoins(2) '手札金量を求める
      
      
      If j >= 8 Then '8金以上
        If deckNumber(trnP) = 0 Then
          actionCardNotPlayed = True
        ElseIf deckNumber(trnP) <= 5 Then 'デッキが5枚以下
          For i = 1 To deckNumber(trnP) Step 1
            If Worksheets("Sheet1").Cells(1 + opFld * trnP, i).Value = 20 Then
              smithyInDeck = True 'デッキ内に鍛冶屋がある
              Exit For
            Else
              'Do Nothing
            End If
            
          Next
          
          If smithyInDeck = True Then
            actionCardNotPlayed = True
          Else
            k = howManyCoins(1) 'デッキ内金量を求める
            
            If deckNumber(trnP) > 3 Then
              If k < 8 Then
                Call playAction(20)
                Call playSmithy
              Else
                 actionCardNotPlayed = True
              End If
              
            ElseIf deckNumber(trnP) = 3 Then
              If k < 6 Then
                Call playAction(20)
                Call playSmithy
              Else
                actionCardNotPlayed = True
              End If
              
            ElseIf deckNumber(trnP) = 2 Then
              If k < 3 Then
                Call playAction(20)
                Call playSmithy
              Else
                actionCardNotPlayed = True
              End If
              
            Else
              If k = 0 Then
                Call playAction(20)
                Call playSmithy
              Else
                actionCardNotPlayed = True
              End If
              
            End If
            
          End If
          
        Else
          Call playAction(20)
          Call playSmithy
        End If
        
      Else
        Call playAction(20)
        Call playSmithy
      End If
      
    Else
      'Do Nothing
    End If
  
  End If

End Sub

 

20番は、鍛冶屋に割り当てられた番号です。

 

If Worksheets("Sheet1").Cells(1 + opFld * trnP, i).Value = 20 then の部分の意味を補足しておきます。

「Sheet1」は骨格部分で説明した、データ格納用のシート1です。

次の部分に、セルの行、列の順に座標が書かれています。

行の部分は、「1」がデッキを表します。「opFld」は、対戦相手のフィールドとの座標のズレ(同時に、1プレイヤー分のシート1に占めるエリアの行数)を意味しているパブリック変数で、これは20行相当になります。そして、「trnP」は現在のターンプレイヤーを意味するパブリック変数で、プレイヤーにあわせ、0と1を切り替えられます。つまり、プレイヤー0のターンであれば1行目、プレイヤー1のターンであれば21行目を表していて、これらを同一のアルゴリズムで賄うための表記になっています。

列の部分は、繰り返し用のローカル変数「i」で定義されており、デッキの底から順に一番上まで検索されていく中で、逐次切り替わっていきます。

最後のValueは内容を表していて、「= 20」だけであればこのセルの内容に20(鍛冶屋)を代入せよということですが、ここは条件文の中なので、このセルの内容が20であれば、ということになります。

 

playAction(20)は、アクションを手札からプレイエリアに持って行く動作そのものです。引数として渡された番号のアクションカードを、実際にCardInHandからCardInPlayに移動させています。

playSmithyは、鍛冶屋のアクションとしての効果、+3カードを引く、の処理になっています。

これらが分割されている理由ですが、召喚や玉座の間等、手札からのアクションプレイが行われるとは必ずしも限らない以上、分割していないと、それらすべてに対応する鍛冶屋を記述しなくてはならなくなるためです。

現在の仕様であれば、playAction(20)を、例えばplayActionBySummon(20)にするだけで、後半のplaySmithyを複数用意する必要がありません。意思決定が介在するカードの場合は、使用元次第では挙動が変化する可能性もあり、この限りではありませんが、少なくとも全く同じ動作については、先頭だけが違うプロシージャを用意する必要はないです。

 

actionCardNotPlayedは、アクションを敢えて使わなかったターンの出力用に使う、パブリック変数です。それ以外の意思決定にも絡んでくる可能性があるので、作ってあります。

 

先頭の、アクションが0ならば、という区切りはあまり意味はないですが、アクションアルゴリズムを連結して使う場合等も想定されたため、いちおう入れています。

手札内にある鍛冶屋を使わない判断に必要な条件として、手札内の金量が8金以上であることが第一、デッキが5枚以下であることが第二(0枚ならば、以下を調べない)、デッキ内に鍛冶屋があることが、そうでないならばデッキ枚数に応じた金量があることが、第三の条件になります。

第一の8金以上の条件ですが、金貨を持っていないかつ6金以上、も加えた方がいいかもしれないです。

第三の、デッキ枚数に応じた金量、はてきとうに決めているので、それよりも回転を重視すべきである可能性もあります。

現状は4-5枚ならば8金以上、3枚ならば6金以上、2枚ならば3金以上、1枚ならば1金以上で鍛冶屋を使いません。2枚以下では、回転した上に鍛冶屋や金貨を引いてしまうリスクを考えて、小さ目にしています。

また、考慮されていない条件ですが、手札の鍛冶屋が2枚あるときは、よりデッキの底が回転しない選択を取るべきな気もしますね…そうなると、デッキ枚数が3枚と2枚の間に、手札の鍛冶屋が2枚(以上)ならば、を加えることになりますね。

…いや、そもそも、デッキ内探索をする必要がないので、それ以前に分岐すべきなのか…

 

 

鍛冶屋ステロの購入アルゴリズムは、以下のようになってます。

 

Function buyAlgorithmProvinceSmithy2Split(i As Integer) As Integer

  Dim j As Integer
  
  If i >= 8 Then
    If cardOwned(trnP, 2) >= 1 Then
      j = 12
    Else
      j = 2
    End If
     
  ElseIf i >= 6 Then
    j = 2
     
  ElseIf i >= 4 Then
    If turnNumber <= 2 Then
      j = 20
    ElseIf turnNumber = 3 Then '分割管理
      If actionNumber > 0 Then '鍛冶屋を撃っていない
        j = 20
      Else
        j = 1
      End If
      
    ElseIf turnNumber >= 5 Then
      If cardOwned(trnP, 20) <= 1 Then
        j = 20
      Else
        j = 1
      End If
      
    Else
      j = 1
    End If
    
  ElseIf i >= 3 Then
    j = 1
    
  Else
    j = -1
    
  End If
  
  buyAlgorithmProvinceSmithy2Split = j

End Function

 

1番は銀貨、2番は金貨、12番は属州、20番は鍛冶屋です。また、-1は購入パスです。

3ターンに鍛冶屋を撃っていない場合、鍛冶屋を購入出来れば、鍛冶屋を連続して撃てる可能性の上がる、所謂「分割管理」状態を作り、3ターン鍛冶屋撃ちに追いすがることができます(と考えられていますが、100%の確信があるわけではないです)。

分割でない場合の鍛冶屋2枚目は、5ターン以降で4金以上が出たターンにしていますが、6金以上が出続けた場合は、2枚目を導入しない可能性はあります。

 

 

前後してしまいますが、鍛冶屋を敢えて使わないことの是非を調べるため、鍛冶屋が手札にあれば、無条件に仕様するアルゴリズムのものも、10000回検証しています。

以下にその結果を示します。

 

f:id:Kurter:20190529222906p:plain

鍛冶屋ステロ 4-3 回転防止なし

 

平均ターンの変化としては、約0.03ターンと、分散の大きさに比べると、あまり確実な違いとまでは言えない気もしますが…

参考までに、上の通常の鍛冶屋ステロ検証で、アクション使用阻止が働いたのは、10000ゲーム中516回だったので、簡単のため1ゲーム1回の判定とすると、約5%のゲームにおいて、この判断が働いていることになります。

0.03ターンといえども、5%程度の話と考えると、その中では0.6T程の差をもたらしていると見ることができるかもしれないです。(ただ、そのターン以降の分岐にどのように波及していっているかを考えると、単純には言い切れない気もしますね。)

本来であるならば、何らかの形でこの状況を抽出して、比較するべきなのですが、稀なパターンを集積するのはわりと大変な気がするので、現状は不十分な検証となってしまっています。

 

 

いちおう、アクションアルゴリズムは以下のようになります。

 

Sub actionAlgorithmProvinceSmithy()

  If actionNumber = 0 Then 
    'Do Nothing
  Else
    If cardInHand(trnP, 20) >= 1 Then
      Call playAction(20)
      Call playSmithy
    Else
      'Do Nothing
    End If
    
  End If

End Sub

 

購入アルゴリズムは、上記と同じものを使っています。 

 

 

(追記)金貨のない8金において、属州を購入するパターンも検証しておいたので、追記しておきます。

 

f:id:Kurter:20190608022117p:plain

鍛冶屋ステロ 4-3 金貨のない8金:属州

 

こちらは、アクションアルゴリズムにおける回転防止は導入しております。

あまり極端な差はないですが、これを見る限りでは、金貨のないうちに属州を買うのは、全体で平均して0.05T程のマイナスをもたらすようです。

例によって残りコイントークンの平均は、金貨のない8金で属州を購入した判断の回数なので、全体では1621回あったことになります。

 

お金プレイと比較して、鍛冶屋ステロの場合、回転が速く、金貨の枚数が減るために、その少ない金貨が更に少なくなると、マイナスの影響が無視できなくなってくるのではないかと思われます。(以上追記)

 

 

 

(追記)鍛冶屋を初手の1枚しか買わないものも、ついでに検証しておいたので、載せておきます。

 

f:id:Kurter:20190608204250p:plain

鍛冶屋ステロ 4-3 鍛冶屋1枚

 

アクションアルゴリズムにおける回転防止は取り入れています。購入アルゴリズムにおいて、初手以外の鍛冶屋の購入条件を一切設けない形にしています。

2枚の検証が最適なタイミングとは必ずしも言えませんが、それでも0.15T程平均が後退しているようです。

分散は小さくなっているので、鍛冶屋を2枚入れることによる被りの影響は、沈みの影響よりも大きいということなのかもしれないですね。(以上追記)

 

 

 

(追記)鍛冶屋の総評としては、純粋にドローだけに性能を振り切っているため、4コストとしては高いポテンシャルを持っているのだが、調整力が皆無なので安定性に欠けていて、分散が大きく、悪いパターンが平均を押し下げている、というところでしょうか。

このため、調整力のあるイベントとの複合で平均ターン数の改善が見込まれます。

また、鍛冶屋は、回転によってより少ない金貨を効率よく運用できるようになることが強みである反面、弱いカードである屋敷の登場回数も同様に多くなります。屋敷を除去できる組み合わせでも、出力の向上が見込まれるでしょう。(以上追記)

 

 

 

とりあえずこんなところで、勘弁してやってください…--…