【C#】一个简单的伪随机方法

目录

前言

需求

实现

算法

代码实现

总结


前言

        伪随机是游戏中常用的功能,但是我看网上的实现都比较复杂,或者不够随机(比如用线性同余法)。所以就自己实现一个算了,用最简单的方式。

需求

类似于抽卡那种,例如10连抽必中1张(概率10%),然后这1张在这10次里面是随机出现的。如果第一张就抽中了,那后面9张都不会中;同理,如果前9张都每中,则最后一张必中。

实现

算法

        基本思路如下:

        先获取一个概率(P),然后得到当前概率下的随机周期(1/P)。例如0.1(10%)的概率,那么周期就是10。

        然后内部需要记录两个参数:在周期里的随机的次数、本周期是否已经抽中过了。

        然后开始随机,一开始仍然一个P的概率随机,查看随机结果。如果已经中了,之后就不再中,如果没中,则下一次随机时概率为P*2(在下一次为P*3,以此类推)。当随机次数到达周期内上限时,设置为必中。

代码实现

/// <summary>
    /// 随机工具;
    /// 自带真随机和伪随机两种模式;
    /// </summary>
    public class RandomTool
    {
        private Random random;
        public float Chance;

        /// <summary>
        /// 随机工具
        /// </summary>
        /// <param name="seed">种子</param>
        /// <param name="chance">概率(0~1)</param>
        public RandomTool(int seed, float chance)
        {
            random = new Random(seed);
            //这里用的Unity的Clamp,限制取值在0~1之间;实际上最小值不能为0,否则会有错误;
            Chance = UnityEngine.Mathf.Clamp01(chance);
        }

        //随机周期,根据概率四舍五入;
        private int PseudRandomCycle => UnityEngine.Mathf.RoundToInt(1 / Chance);               
        private int cycleIndex = 0;
        private bool isTrueInCycle = false;//本周期是否已经随机成功了
        private float cycleChance => Chance + cycleIndex * Chance;

        public void ResetPseudorandomParam()
        {
            cycleIndex = 0;
            isTrueInCycle = false;
        }

        private bool GetPesudorandomResult(int randVal)
        {
            if (isTrueInCycle) return false;
            //理论上下面这个特殊判定可以不需要,到最后概率是100%
            if (cycleIndex == PseudRandomCycle - 1) return true;

            var ret = randVal < cycleChance * 100;
            if (ret) isTrueInCycle = true;
            return ret;
        }

        /// <summary>
        /// 获取下一个随机结果;
        /// </summary>
        public bool NextRandomResult
        {
            get
            {
                if (Chance == 0) return false;

                int randVal = random.Next(0, 100);
                //伪随机;
                if (cycleIndex >= PseudRandomCycle)
                    ResetPseudorandomParam();
                bool ret = GetPesudorandomResult(randVal);
                cycleIndex++;
                return ret;

            }
        }

    }

总结

这个算法非常简单,当然使用会有一定限制。

在特殊情况下简单使用的话是没问题的。

猜你喜欢

转载自blog.csdn.net/cyf649669121/article/details/122990575