ガチャ出現回数計算

2022年2月15日

いくつかのガチャがあって、それぞれ確率が設定されている時にどれが選択されるかを計算するサンプルになります

コード

出現確率のリストから、どれが選択されているかを要素番号で返します
例えば、10%,20%,30%,40%と4つの発生確率である場合、その中から何番目が選択されるかを変えることになります

class ProbabilityClass
{
    List<int> ratioList = new();

    int ratioSum;
    int addSum;

    Random random;

    public ProbabilityClass(List<int> ratioSet)
    {
        ratioSum = ratioSet.Sum();

        foreach (var ratio in ratioSet)
        {
            addSum += ratio;

            ratioList.Add((int)(addSum * 100.0f / ratioSum));
        }

        random = new();
    }

    public int Probability()
    {
        int rand = random.Next(100);

        for (int i = 0; i < ratioList.Count - 1; i++)
        {
            if (ratioList[i] > rand)
            {
                return i;
            }
        }

        return ratioList.Count - 1;
    }
}

使い方

List<int> ratioSet = new() { 10, 20, 30, 40 };

ProbabilityClass probabilityClass = new(ratioSet);

Console.WriteLine($"選択された要素番号 {probabilityClass.Probability()}");

結果

選択された要素番号 1

10,000,000回のテストを含む全体のコード

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

namespace Probability
{
    class Program
    {
        static void Main(string[] args)
        {
            SimpleTest();
            LoadTest();
        }

        static void SimpleTest()
        {
            List<int> ratioSet = new() { 10, 20, 30, 40 };

            Console.WriteLine("シンプルテストの結果");

            Console.Write("要素 ");

            for (int i = 0; i < ratioSet.Count; i++)
            {
                Console.Write($"{i}:{ratioSet[i]}%, ");
            }

            ProbabilityClass probabilityClass = new(ratioSet);

            Console.WriteLine($"\n選択された要素番号 {probabilityClass.Probability()}\n");
        }

        private static void LoadTest()
        {
            Stopwatch stopWatch = new();

            stopWatch.Start();

            List<int> ratioSet = new() { 10, 20, 30, 40 };

            ProbabilityClass probabilityClass = new(ratioSet);

            int[] result = new int[ratioSet.Count];

            int count = 10000000;

            for (int i = 0; i < count; i++)
            {
                result[probabilityClass.Probability()]++;
            }

            Console.WriteLine($"負荷テストの結果: テスト回数 {count:#,0}");

            for (int i = 0; i < result.Length; i++)
            {
                Console.WriteLine($"要素番号 {i}: 割当 {ratioSet[i]}%, 結果 {result[i] * 100.0f / count }%, 回数 {result[i]:#,0}");
            }

            stopWatch.Stop();
            Console.WriteLine($"実行時間 {stopWatch.Elapsed}");
        }
    }

    class ProbabilityClass
    {
        List<int> ratioList = new();

        int ratioSum;
        int addSum;

        Random random;

        public ProbabilityClass(List<int> ratioSet)
        {
            ratioSum = ratioSet.Sum();

            foreach (var ratio in ratioSet)
            {
                addSum += ratio;

                ratioList.Add((int)(addSum * 100.0f / ratioSum));
            }

            random = new();
        }

        public int Probability()
        {
            int rand = random.Next(100);

            for (int i = 0; i < ratioList.Count - 1; i++)
            {
                if (ratioList[i] > rand)
                {
                    return i;
                }
            }

            return ratioList.Count - 1;
        }
    }
}

実行結果

負荷テストでは、10,000,000回連続して結果を求めたものになります
確率通りの結果が得られています
テスト時間は、39msですね
十分なスピードです

シンプルテストの結果
要素 0:10%, 1:20%, 2:30%, 3:40%, 
選択された要素番号 2

負荷テストの結果: テスト回数 10,000,000
要素番号 0: 割当 10%, 結果 10.00618%, 回数 1,000,618
要素番号 1: 割当 20%, 結果 20.01569%, 回数 2,001,569
要素番号 2: 割当 30%, 結果 30.01138%, 回数 3,001,138
要素番号 3: 割当 40%, 結果 39.966747%, 回数 3,996,675
実行時間 00:00:00.3988541

Press any key to continue...

C#

Posted by hidepon