控制随机抽中几率 的算法[ C# | Random ]

---恢复内容开始---

最新有几个学生询问了我关于随机概率抽奖的算法,当天给他们讲解了下,第二天他们还是没写出一个完整的算法出来,要么是无法实现,要么是实现了简单的逻辑,却与自己原定的概率相差甚远,比如设定概率为10%的事件,出现的几率却远远大于概率设定为50%的事件!这让我注意到,对于大多新手来说,随机概率的问题还是比较头疼的问题;
这里写个算法,此算法可用于题库随机抽题、赌博机控制出彩率,甚至俄罗斯方块等游戏,希望对需要的朋友有帮助;
直接上代码:
测试说明:按权重比重大小,控制随机抽取物品道具
RandomController.cs
 
using System;
using System.Collections.Generic;
 
public class RandomController
{
 #region Properties
 
    private int _Count;
    /// <summary>
    /// 随机抽取个数
    /// </summary>
    public int Count
    {
        get
        {
            return _Count;
        }
        set
        {
            _Count = value;
        }
    }
 
    #endregion
 
    #region Contructors
 
    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="count">随机抽取个数</param>
    public RandomController(ushort count)
    {
        _Count = count;
    }
 
    #endregion
 
    #region Method
  #region 普通随机抽取

    /// <summary>
    /// 普通随机抽取
    /// </summary>
    /// <param name="rand"></param>
    /// <param name="datas"></param>
    /// <returns></returns>
    public int[] RandomExtract(Random rand, List<int> datas)
    {
        List<int> result = new List<int>();
        if (rand != null)
        {
            for (int i = Count; i > 0;)
            {
                int item = datas[rand.Next(25)];
                if (result.Contains(item))
                    continue;
                else
                {
                    result.Add(item);
                    i--;
                }
            }
        }
        return result.ToArray();
    }

    #endregion

    #region 受控随机抽取

    /// <summary>
    /// 受控随机抽取
    /// </summary>
    /// <param name="rand"></param>
    /// <param name="datas"></param>
    /// <param name="weights"></param>
    /// <returns></returns>
    public int[] ControllerRandomExtract(Random rand, List<int> datas, List<ushort> weights)
    {
        int nItemCount = datas.Count;
        List<int> result = new List<int>();
        if (rand != null)
        {
            //临时变量
            Dictionary<int, int> dict = new Dictionary<int, int>(nItemCount);

            //为每个项算一个随机数并乘以相应的权值
            for (int i = datas.Count - 1; i >= 0; i--)
            {
                dict.Add(datas[i], rand.Next(100) * weights[i]);
            }

            //排序
            List<KeyValuePair<int, int>> listDict = SortByValue(dict);

            //拷贝抽取权值最大的前Count项
            foreach (KeyValuePair<int, int> kvp in listDict.GetRange(0, Count))
            {
                result.Add(kvp.Key);
            }
        }
        return result.ToArray();
    }

    #endregion

    #region Tools

    /// <summary>
    /// 排序集合
    /// </summary>
    /// <param name="dict"></param>
    /// <returns></returns>
    private List<KeyValuePair<int, int>> SortByValue(Dictionary<int, int> dict)
    {
        List<KeyValuePair<int, int>> list = new List<KeyValuePair<int, int>>();

        if (dict != null)
        {
            list.AddRange(dict);

            list.Sort(
              delegate (KeyValuePair<int, int> kvp1, KeyValuePair<int, int> kvp2)
              {
                  return kvp2.Value - kvp1.Value;
              });
        }
        return list;
    }

    #endregion

    #endregion
}
 
测试脚本:RandomItem.cs
 
using System.Collections;
using System.Collections.Generic;
using System;
public class RandomItem: MonoBehaviour {
 
  //物品Id生声明
 public enum GX_ITEM_ID

    {
        none,
        ItemId1,
        ItemId2,
        ItemId3,
        ItemId4,
        ItemId5,
        total,
    }

//参与抽奖的物品Id池

    public List<int> datas = new List<int>(
       new int[]{
            (int)GX_ITEM_ID.ItemId1,
            (int)GX_ITEM_ID.ItemId2,
            (int)GX_ITEM_ID.ItemId3,
            (int)GX_ITEM_ID.ItemId4,
            (int)GX_ITEM_ID.ItemId5,
            (int)GX_ITEM_ID.none
   });

    //概率权值,权值越大,被抽中的概率越高
    public List<ushort> weights = new List<ushort>(
        new ushort[]{
            10,
            5,
            4,
            4,
            0,    //0表明永远无法抽取到这个物品
            5
    });

 

RandomController rc;

   void Start()
     {

  //随机抽取一个物品的随机控制器
        rc = new RandomController(1);

  }

  /// <summary>
    /// 根据权值随机抽取物品,返回ItemId
    /// </summary>
    /// <returns></returns>
    public GX_ITEM_ID GetRandomItem()
    {

        GX_ITEM_ID ItemId = GX_ITEM_ID.none;
         
        //随机数生成器
        System.Random rand = new System.Random();
       
        int[] rands = rc.ControllerRandomExtract(rand, datas,weights);
        ItemId = (GX_ITEM_ID) rands[0];

        //UIViewManager.Instance.testText.text = "本次抽奖获得itemId = "+ItemId;
        return ItemId;
    }

}
 
 

---恢复内容结束---

posted @ 2017-12-29 17:47  Mr1024  阅读(6680)  评论(0编辑  收藏  举报