3ターン目に無月の門を開きたい

f:id:metagross-armor:20180115161418j:plain
《一番隊 バギン》と1マナの魔道具を考慮しない場合に、3ターン目に《卍 デ・スザーク 卍》を着地させるための条件は以下の通り。
・2ターン目の手札に、(場に残る)2マナの魔道具がある。
・3ターン目の手札に、《堕魔 グリギャン》と《卍 デ・スザーク 卍》がある。
・3ターン目の山札の上3枚の中に、魔道具が2枚以上ある。

厳密解を求めるのが面倒くさいので、例によってプログラムにお任せ。
それぞれの場合で100万回シミュレーションして、成功した割合は以下の通り。

1ターン目の手札(枚) 5 5 5 5 6 6
《卍 デ・スザーク 卍》(枚) 4 4 4 4 4 4
《堕魔 グリギャン》(枚) 4 4 4 4 4 4
2マナの魔道具(枚) 8 8 6 6 8 6
その他の魔道具(枚) 12 10 12 10 12 10
3ターン目着地(%) 12.7 11.1 9.1 7.9 17.3 11.0

卍.exe

以下ソース。

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static int startinghand;
        static int cost2;
        static int gurigyan;
        static int suzaku;
        static int madougu;

        static void Main(string[] args)
        {
            Console.WriteLine("1ターン目の手札の枚数(先5、後6)");
            startinghand = int.Parse(Console.ReadLine());
            Console.WriteLine("2マナの魔道具の枚数");
            cost2 = int.Parse(Console.ReadLine());
            Console.WriteLine("グリギャンの枚数");
            gurigyan = int.Parse(Console.ReadLine());
            Console.WriteLine("デ・スザークの枚数");
            suzaku = int.Parse(Console.ReadLine());
            Console.WriteLine("その他の魔道具の枚数");
            madougu = int.Parse(Console.ReadLine());

            int[] deck = Deck();
            int result = 0;
            int loop = 1000000;

            for (int i = 0; i < loop; i++)
            {
                if (Check(deck.Shuffle().ToArray())) result++;
            }

            result = result / (loop / 10000) + 5;
            result /= 10;
            Console.WriteLine("3ターン目にデ・スザークが着地する確率:約" + result / 10 + "." + result % 10 + "%");
            Console.ReadLine();
        }

        static bool Check(int[] deck)
        {
            bool result = false;

            //2コスト
            for (int i = 0; i < startinghand + 1; i++)
            {
                if (deck[i] == 1)
                {
                    result = true;
                    break;
                }
            }
            if (!result) return false;

            //グリギャン
            result = false;
            for (int i = 0; i < startinghand + 2; i++)
            {
                if (deck[i] == 3)
                {
                    result = true;
                    break;
                }
            }
            if (!result) return false;

            //デスザーク
            result = false;
            for (int i = 0; i < startinghand + 2; i++)
            {
                if (deck[i] == 2)
                {
                    result = true;
                    break;
                }
            }
            if (!result) return false;

            //墓地
            result = false;
            int count = 0;
            for (int i = 0; i < 3; i++)
            {
                if ((deck[startinghand + 2 + i] & 1) == 1)
                {
                    count++;
                }
            }
            if (count < 2) return false;

            return true;
        }

        static int[] Deck()
        {
            int[] deck = new int[40];

            int j = 0;
            for (int i = 0; i < cost2; i++)
            {
                deck[j] = 1;
                j++;
            }
            for (int i = 0; i < gurigyan; i++)
            {
                deck[j] = 3;
                j++;
            }
            for (int i = 0; i < suzaku; i++)
            {
                deck[j] = 2;
                j++;
            }
            for (int i = 0; i < madougu; i++)
            {
                deck[j] = 5;
                j++;
            }
            while (j < 40)
            {
                deck[j] = 0;
                j++;
            }
            return deck;
        }
    }

    public static class IEnumerableExtension
    {
        public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> collection)
        {
            return collection.OrderBy(i => Guid.NewGuid());
        }
    }
}

参考
[C#] 配列をランダムソート(シャッフル)する方法 │ Web備忘録