转盘活动抽奖算法记录

一、转盘活动抽奖算法记录。

    1. 首先抽奖的概率如下:

概率:
0.51858
0.3 0.15 0.02 0.01 0.001 0.0004 0.00002

  2. 抽奖的抽奖代码:

/// <summary>
        /// 概率抽奖
        /// </summary>
        /// <returns>返回奖品ID</returns>
        public fksd_prize RateLotteryPrize(List<fksd_prize> fksd_Prizes)
        {
            int value = random.Next(1, 100001);

            List<fksd_prize> turntablePrizeInfos = fksd_Prizes;
            fksd_prize _Prize = new fksd_prize();
            decimal left = 0, right = 0;
            for (int i = 0; i < turntablePrizeInfos.Count; i++)
            {
                right = turntablePrizeInfos[i].Probability * 100000 + left;
                if (value > left && value <= right)
                {
                    _Prize = turntablePrizeInfos[i];
                    break;
                }
                left = right;
            }

            return _Prize;
        }

   3. 来看看测试100万次抽奖代码。

 List<fksd_prize> fksd_Prizes = new List<fksd_prize>();
            var ps = new fksd_prize();
            ps.Id = 1;
            ps.Probability = 0.51858M;
            fksd_Prizes.Add(ps);
            ps = new fksd_prize();
            ps.Id = 2;
            ps.Probability = 0.30M;
            fksd_Prizes.Add(ps);
            ps = new fksd_prize();
            ps.Id = 3;
            ps.Probability = 0.15M;
            fksd_Prizes.Add(ps);
            ps = new fksd_prize();
            ps.Id = 4;
            ps.Probability = 0.02M;
            fksd_Prizes.Add(ps);
            ps = new fksd_prize();
            ps.Id = 5;
            ps.Probability = 0.01M;
            fksd_Prizes.Add(ps);
            ps = new fksd_prize();
            ps.Id =6;
            ps.Probability = 0.001M;
            fksd_Prizes.Add(ps);
            ps = new fksd_prize();
            ps.Id = 7;
            ps.Probability = 0.0004M;
            fksd_Prizes.Add(ps);
            ps = new fksd_prize();
            ps.Id = 8;
            ps.Probability = 0.00002M;
            fksd_Prizes.Add(ps);

            var keyCount = new Dictionary<int, int>();

            var luckyDrawBll = new LuckyDrawBll();
            var tcount = 1000000;
            for (int i = 0; i < tcount; i++)
            {
                ps = luckyDrawBll.RateLotteryPrize(fksd_Prizes);
                if (keyCount.ContainsKey(ps.Id))
                {
                    keyCount[ps.Id]++;
                }
                else
                {
                    keyCount.Add(ps.Id, 1);
                }
            }
            foreach (int item in keyCount.Keys)
            {
                Console.WriteLine( "ID:" + item.ToString() + "  --values:" + (Convert.ToDecimal(keyCount[item] ) / tcount).ToString());
            }
            Console.ReadKey();
100万次抽奖概率分布

 以上可以看到的是,概率还是很接近的。

  4. 相关抽奖代码如下:

public class LuckyDrawBll
    {
        #region 2020年8月转盘抽奖活动
        private readonly SqlSugarClient Db = null;
        public LuckyDrawBll()
        {
            Db = DemoBase.GetInstance();
        }
        private static ConcurrentDictionary<string, int> _lockDic = new ConcurrentDictionary<string, int>();
        /// <summary>
        ///转盘抽奖活动
        /// </summary>
        /// <returns></returns>
        public async Task<int> TurntableLottery(int UserId, int SiteId)
        {
            fksd_prize prize = null;
            int value = 0;
            
            //防用户重复提交
            if (!_lockDic.TryAdd((UserId + SiteId).ToString(), 1))
            {
                Log.Error("抽奖失败:用户重复并发:", UserId.ToString(), "TurntableLottery");
                return 9;
            }
            //查找用户是否存在
            fksdtb_user _User = Db.Queryable<fksdtb_user>().Single(t => t.Id == UserId);
            if (_User == null || _User.Id <= 0)
            {
                _lockDic.TryRemove((UserId + SiteId).ToString(), out value);
                return 10;
            }
            //查询贡献值+普通抽奖次数+赠送抽奖次数
            string userlotterySQL = string.Format(" select * from fksd_leaderboardlucky where UserId=@UserId and SiteId = @SiteId");
            //获取普通抽奖次数和赠送抽奖次数
            fksd_leaderboardlucky temp = Db.Ado.SqlQuerySingle<fksd_leaderboardlucky>(userlotterySQL, new { UserId, SiteId });
            //获取贡献值并且判断今天贡献值抽奖次数是不是大于5
            //获取贡献值
            try
            {

                string ApiUrl = ConfigurationManager.AppSettings["MemberUrl"];
                var ResultHttp = RestApi.Get(ConfigurationManager.AppSettings["MemberUrl"], $"/Member/info/userid/{UserId}");
                GetResult<Member> Getresult = Focus.Common.Web.JsonHelper.JSONToObject<GetResult<Member>>(ResultHttp.ToString());
                Member member = Getresult.Data;
                string year = DateTime.Now.Year.ToString();
                string month = DateTime.Now.Month.ToString();
                string day = DateTime.Now.Day.ToString();
                string leaderboardluckylog = string.Format(" select * from fksd_leaderboardluckylog where UserId=@UserId and SiteId = @SiteId and prizeType=1 and year(CreateTime)=@year and month(CreateTime)=@month and day(CreateTime)=@day");
                List<SugarParameter> sugarParameters = new List<SugarParameter>();
                sugarParameters.Add(new SugarParameter("UserId", UserId));
                sugarParameters.Add(new SugarParameter("SiteId", SiteId));
                sugarParameters.Add(new SugarParameter("year", year));
                sugarParameters.Add(new SugarParameter("month", month));
                sugarParameters.Add(new SugarParameter("day", day));

                //查看抽奖日志
                List<fksd_leaderboardluckylog> log = Db.Ado.SqlQuery<fksd_leaderboardluckylog>(leaderboardluckylog, sugarParameters);

                //List<fksd_leaderboardluckylog> log = Db.Ado.SqlQuery<fksd_leaderboardluckylog>(leaderboardluckylog, new { UserId = _User.Id, SiteId = SiteId, year = year, month = month, day = day });
                //string config= "select * from task_config where "
                //代码预留  查询 task_config 每次抽奖获取贡献值
                //积分只能抽奖5次0
                if (temp == null)
                {
                    temp = new fksd_leaderboardlucky();
                }
                task_config task_Config = new LuckyDrawBll().GetTaskConfig("Draw3");
                task_config task_Config1 = new LuckyDrawBll().GetTaskConfig("Draw2");
                if (temp.givingLuckyDrawNum < 1 && temp.LuckyDrawNum < 1 && log.Count > Convert.ToInt32(task_Config.RewardValue) && member.CurrentCredit <= Convert.ToInt32(task_Config1.RewardValue))   //次数应该判断贡献值是否大于30
                {
                    _lockDic.TryRemove((UserId + SiteId).ToString(), out value);
                    return 11;  //没有抽奖次数
                }
                List<fksd_prize> listPrize = Db.Queryable<fksd_prize>().OrderBy("Probability desc").ToList();
                Db.Ado.BeginTran();
                //先是普通,再是赠送,积分
                int prizeType = 0;
                if (temp.LuckyDrawNum > 0)
                {
                    prize = RateLotteryPrize(listPrize);
                    temp.LuckyDrawNum = temp.LuckyDrawNum - 1;
                    int luckyresult = Db.Updateable<fksd_leaderboardlucky>(temp).ExecuteCommand();  //更新抽奖信息
                    prizeType = 2;
                }
                else if (temp.givingLuckyDrawNum > 0)
                {
                    prize = RateLotteryPrize(listPrize);
                    temp.givingLuckyDrawNum = temp.givingLuckyDrawNum - 1;
                    int luckyresult = Db.Updateable<fksd_leaderboardlucky>(temp).ExecuteCommand();  //更新抽奖信息
                    prizeType = 3;
                }
                else if (log.Count() <= Convert.ToInt32(task_Config.RewardValue) && member.CurrentCredit >= Convert.ToInt32(task_Config1.RewardValue))    //如果贡献值大于30,才会执行该方法,并且调取扣贡献值,抽奖一次扣除30
                {
                    //扣贡献值  
                    #region 扣贡献值
                    string configSql = "select * from task_config where RewardKey=@RewardKey";
                    task_config configRusult = Db.Ado.SqlQuery<task_config>(configSql, new { RewardKey = "Draw2" }).FirstOrDefault();
                    ContributionModifyNewParam param = new ContributionModifyNewParam();
                    param.userId = UserId;
                    param.timestamp = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds);
                    param.operationType = configRusult.Id;
                    string urls = ConfigurationManager.AppSettings["MemberUrl"] + "/Member/contribution_modify_new";
                    //var httpResult = await Fksd.Focus.Common.HttpHelper.WebApiPost<ContributionModifyNewParam>(urls, param);
                    fksd_prizeerrorlog errorlog = new fksd_prizeerrorlog();
                    try
                    {
                        var httpResult = RestApi.Post(ConfigurationManager.AppSettings["MemberUrl"], "/Member/contribution_modify_new", param);
                        StringBuilder sb = new StringBuilder();
                        JavaScriptSerializer json = new JavaScriptSerializer();
                        json.Serialize(param, sb);
                        errorlog.ErrorMessage = sb.ToString();

                        Focus.Common.Result results = Focus.Common.Web.JsonHelper.JSONToObject<Focus.Common.Result>(httpResult);
                        if (results.Code == Code.Fail)
                        {
                            Db.Ado.RollbackTran();
                            _lockDic.TryRemove((UserId + SiteId).ToString(), out value);
                            errorlog.RequestUrl = ConfigurationManager.AppSettings["MemberUrl"] + "/Member/contribution_modify_new";
                            errorlog.Response = httpResult;
                            errorlog.SiteId = SiteId;
                            errorlog.UserId = UserId;
                            errorlog.CreateTime = DateTime.Now;
                            Db.Insertable<fksd_prizeerrorlog>(errorlog).ExecuteCommand();
                            return 12;
                        }
                    }
                    catch (Exception e)
                    {
                        errorlog.RequestUrl = ConfigurationManager.AppSettings["MemberUrl"] + "/Member/contribution_modify_new";
                        errorlog.Response = "";
                        errorlog.ErrorMessage = e.Message.ToString();
                        errorlog.SiteId = SiteId;
                        errorlog.UserId = UserId;
                        errorlog.CreateTime = DateTime.Now;
                        Db.Insertable<fksd_prizeerrorlog>(errorlog).ExecuteCommand();
                        _lockDic.TryRemove((UserId + SiteId).ToString(), out value);
                        Db.Ado.RollbackTran();
                        return 12;
                    }


                    rebatestsendingcontribution rebatest = new rebatestsendingcontribution();
                    rebatest.CreateTime = DateTime.Now;
                    rebatest.Staues = 1;
                    rebatest.TaskName = "贡献值兑换抽奖次数_Draw2_25";
                    rebatest.UserId = UserId;
                    int result = Db.Insertable<rebatestsendingcontribution>(rebatest).ExecuteCommand();



                    #endregion

                    prize = RateLotteryPrize(listPrize);
                    prizeType = 1;
                }
                else
                {
                    _lockDic.TryRemove((UserId + SiteId).ToString(), out value);
                    Db.Ado.RollbackTran();
                    return 11;
                }
                string luckySql = "insert into fksd_leaderboardluckylog(UserId,SiteId,prizeType,CreateTime,PrizeId) VALUES(@UserId,@SiteId,@prizeType,@CreateTime,@PrizeId)";
                int excut = Db.Ado.ExecuteCommand(luckySql, new { UserId, SiteId, prizeType, CreateTime = DateTime.Now, PrizeId = prize.Id });
                if (prize.PrizeType == 1)   //调取加贡献值的方法
                {
                    string configSql = "";
                    if (prizeType == 3)
                    {
                        configSql = "select * from task_config where RewardKey=@RewardKey and ContributionType=1";
                    }
                    else
                    { 
                        configSql = "select * from task_config where RewardKey=@RewardKey and ContributionType=0";
                    }
                    task_config configRusult = Db.Ado.SqlQuery<task_config>(configSql, new { RewardKey = prize.ConfigKey }).FirstOrDefault();
                    ContributionModifyNewParam param = new ContributionModifyNewParam();
                    param.userId = UserId;
                    param.timestamp = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds);
                    param.operationType = configRusult.Id;
                    //  string urls = ConfigurationManager.AppSettings["MemberUrl"] + "/Member/contribution_modify_new";
                    //var httpResult = await Fksd.Focus.Common.HttpHelper.WebApiPost<ContributionModifyNewParam>(urls, param);
                    //var httpResult = await Fksd.Focus.Common.HttpHelper.WebApiPost<ContributionModifyNewParam>(ConfigurationManager.AppSettings["MemberUrl"], "/Member/contribution_modify_new", param);
                    fksd_prizeerrorlog errorlog = new fksd_prizeerrorlog();
                    try
                    {
                        var httpResult = RestApi.Post(ConfigurationManager.AppSettings["MemberUrl"], "/Member/contribution_modify_new", param);
                        StringBuilder sb = new StringBuilder();
                        JavaScriptSerializer json = new JavaScriptSerializer();
                        json.Serialize(param, sb);
                        errorlog.ErrorMessage = sb.ToString();
                        Focus.Common.Result results = Focus.Common.Web.JsonHelper.JSONToObject<Focus.Common.Result>(httpResult);

                        //errorlog.RequestUrl = ConfigurationManager.AppSettings["MemberUrl"] + "/Member/contribution_modify_new";
                        //errorlog.Response = httpResult;

                        //errorlog.SiteId = SiteId;
                        //errorlog.UserId = UserId;
                        //errorlog.CreateTime = DateTime.Now;
                        //int resultsss= Db.Insertable<fksd_prizeerrorlog>(errorlog).ExecuteCommand();
                        if (results.Code == Code.Fail)
                        {
                            Db.Ado.RollbackTran();
                            _lockDic.TryRemove((UserId + SiteId).ToString(), out value);

                            errorlog.RequestUrl = ConfigurationManager.AppSettings["MemberUrl"] + "/Member/contribution_modify_new";
                            errorlog.Response = httpResult;
                            
                            errorlog.SiteId = SiteId;
                            errorlog.UserId = UserId;
                            errorlog.CreateTime = DateTime.Now;
                            Db.Insertable<fksd_prizeerrorlog>(errorlog).ExecuteCommand();
                            return 12;
                        }
                    }
                    catch (Exception e)
                    {
                        errorlog.RequestUrl = ConfigurationManager.AppSettings["MemberUrl"] + "/Member/contribution_modify_new";
                        errorlog.RequestUrl = "";
                        errorlog.Response = "";
                        errorlog.ErrorMessage = e.Message.ToString();
                        errorlog.SiteId = SiteId;
                        errorlog.UserId = UserId;
                        errorlog.CreateTime = DateTime.Now;
                        Db.Insertable<fksd_prizeerrorlog>(errorlog).ExecuteCommand();
                        _lockDic.TryRemove((UserId + SiteId).ToString(), out value);
                        Db.Ado.RollbackTran();
                        return 12;
                    }
                    
                    rebatestsendingcontribution rebatest = new rebatestsendingcontribution();
                    rebatest.CreateTime = DateTime.Now;
                    rebatest.Staues = 1;
                    rebatest.TaskName = "中奖2_lucky2_51";
                    rebatest.UserId = UserId;
                    int result = Db.Insertable<rebatestsendingcontribution>(rebatest).ExecuteCommand();

                    Db.Ado.CommitTran();
                }
                else  //加金额
                {
                    StringBuilder sql = new StringBuilder();
                    sql.AppendFormat(" INSERT INTO fksd_userfinancial(`UserId`, `Amount`, `OrderNo`, `CreateTime`, `Type`, `State`,`RelationId`) VALUES ({0}, {1}, '{2}',now(), {3}, 1,{4});", UserId, Convert.ToInt32(prize.PrizeName), Guid.NewGuid().ToString("N"), 24, UserId);
                    sql.AppendFormat(" UPDATE `fksd_buyerfinancial` SET  `Amount` = Amount+{0} WHERE BuyerId={1} and CurrencyId={2};", Convert.ToInt32(prize.PrizeName), UserId, 1);
                    int result = Db.Ado.ExecuteCommand(sql.ToString());

                    if (result == 2)
                    {
                        Db.Ado.CommitTran();
                    }
                    else
                    {
                        Db.Ado.RollbackTran();
                    }
                }
                //Db.Ado.CommitTran();
                //int Logresult = Db.Updateable<fksd_leaderboardluckylog>(temp).ExecuteCommand();  //加入日志
                _lockDic.TryRemove((UserId + SiteId).ToString(), out _);

                return prize.Id;
            }
            catch (Exception e)
            {
                fksd_prizeerrorlog errorlog = new fksd_prizeerrorlog();
                Log.Info("抽奖活动出错", e.Message, "LuckyDraw");
                errorlog.RequestUrl = "";
                errorlog.Response = "";
                errorlog.ErrorMessage = e.Message.ToString();
                errorlog.SiteId = SiteId;
                errorlog.UserId = UserId;
                errorlog.CreateTime = DateTime.Now;
                Db.Insertable<fksd_prizeerrorlog>(errorlog).ExecuteCommand();

                _lockDic.TryRemove((UserId + SiteId).ToString(), out value);
                Db.Ado.RollbackTran();
            }
            return 12;  //出错
        }
        //轮播最近100条参与抽奖用户的获奖
        public List<Getprizes> Getprize()
        {
            string configSql = "select b.UserName,c.PrizeType,c.PrizeName,a.CreateTime from fksd_leaderboardluckylog a left join fksdtb_user b on a.UserId=b.Id left join fksd_prize c on a.PrizeId=c.Id  order by a.CreateTime desc limit 100";
            List<Getprizes> userList = Db.Ado.SqlQuery<Getprizes>(configSql);
            return userList;
        }

        /// <summary>
        /// 获取该用户的
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="siteId"></param>
        /// <returns></returns>
        public fksd_leaderboardlucky GetLeaderboardlucky(int userId, int siteId)
        {
            string configSql = "select * from fksd_leaderboardlucky where UserId=@userId and SiteId=@siteId";
            fksd_leaderboardlucky configRusult = Db.Ado.SqlQuery<fksd_leaderboardlucky>(configSql, new { userId = userId, siteId = siteId }).FirstOrDefault();
            return configRusult;
        }

        public List<Getprizes> GetUserPrize(int userId, int siteId)
        {
            //select b.UserName,c.PrizeType,c.PrizeName from fksd_leaderboardluckylog a left join fksdtb_user b on a.UserId=b.Id left join fksd_prize c on a.PrizeId=b.Id  where a.UserId=@userId  and a.SiteId=@siteId and TO_DAYS(now()) - TO_DAYS(a.CreateTime) <=7
            //string userPrizeList = "select * from fksd_leaderboardluckylog a left join fksdtb_user b on a.UserId=b.Id where a.UserId=@userId  and a.SiteId=@siteId TO_DAYS(now()) - TO_DAYS(a.CreateTime) <=7 ";

            string userPrizeList = "select b.UserName,c.PrizeType,c.PrizeName,a.CreateTime from fksd_leaderboardluckylog a left join fksdtb_user b on a.UserId=b.Id left join fksd_prize c on a.PrizeId=c.Id  where a.UserId=@userId and a.SiteId=@siteId and TO_DAYS(now()) - TO_DAYS(a.CreateTime) <=7 ";
            List<Getprizes> userList = Db.Ado.SqlQuery<Getprizes>(userPrizeList, new { userId, siteId });
            return userList;
        }
        /// <summary>
        /// 获取所有的奖品
        /// </summary>
        /// <returns></returns>
        public List<fksd_prize> GetPrizes()
        {
            string sql = "select * from fksd_prize";
            List<fksd_prize> list = Db.Ado.SqlQuery<fksd_prize>(sql);
            return list;
        }
        public static Random random = new Random();
        /// <summary>
        /// 概率抽奖
        /// </summary>
        /// <returns>返回奖品ID</returns>
        public fksd_prize RateLotteryPrize(List<fksd_prize> fksd_Prizes)
        {
            int value = random.Next(1, 100001);

            List<fksd_prize> turntablePrizeInfos = fksd_Prizes;
            fksd_prize _Prize = new fksd_prize();
            decimal left = 0, right = 0;
            for (int i = 0; i < turntablePrizeInfos.Count; i++)
            {
                right = turntablePrizeInfos[i].Probability * 100000 + left;
                if (value > left && value <= right)
                {
                    _Prize = turntablePrizeInfos[i];
                    break;
                }
                left = right;
            }

            return _Prize;
        }
        /// <summary>
        /// 读取配置文件
        /// </summary>
        /// <param name="RewardKey"></param>
        /// <returns></returns>
        public task_config GetTaskConfig(string RewardKey)
        {
            string configSql = "select * from task_config where RewardKey=@RewardKey";
            task_config configRusult = Db.Ado.SqlQuery<task_config>(configSql, new { RewardKey = RewardKey }).FirstOrDefault();
            return configRusult;
        }
        /// <summary>
        /// 提交亚马逊
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public int Addlegivingluckylog(fksd_legivingluckylog model)
        {
            int result = Db.Insertable<fksd_legivingluckylog>(model).ExecuteCommand();
            return result;
        }
        /// <summary>
        /// 获取亚马逊订单号
        /// </summary>
        /// <param name="commentorderId"></param>
        /// <returns></returns>
        public fksd_legivingluckylog Getlegivingluckylog(int commentorderId)
        {
            string configSql = "select * from fksd_legivingluckylog where commentorderId=@commentorderId";
            fksd_legivingluckylog configRusult = Db.Ado.SqlQuery<fksd_legivingluckylog>(configSql, new { commentorderId = commentorderId }).FirstOrDefault();
            return configRusult;
        }


        #endregion

        /// <summary>
        /// 增加奖励抽奖次数
        /// </summary>
        /// <param name="entity"></param>
        public void AddLuckyDrawNum(fksd_leaderboardlucky entity)
        {

            var leaderboard = Db.Queryable<fksd_leaderboardlucky>().First(w => w.SiteId == entity.SiteId && entity.UserId == w.UserId);
            if (leaderboard == null)
            {
                Db.Insertable<fksd_leaderboardlucky>(entity).ExecuteCommand();
            }
            else
            {
                leaderboard.givingLuckyDrawNum += entity.givingLuckyDrawNum;
                Db.Updateable<fksd_leaderboardlucky>(leaderboard).ExecuteCommand();
            }

        }

        /// <summary>
        /// 增加奖励抽奖次数
        /// </summary>
        /// <param name="entity"></param>
        public void AddleaderboardluckyNum(fksd_leaderboardlucky entity)
        {

            var leaderboard = Db.Queryable<fksd_leaderboardlucky>().First(w => w.SiteId == entity.SiteId && entity.UserId == w.UserId);
            if (leaderboard == null)
            {
                Db.Insertable<fksd_leaderboardlucky>(entity).ExecuteCommand();
            }
            else
            {
                leaderboard.LuckyDrawNum += entity.LuckyDrawNum;
                Db.Updateable<fksd_leaderboardlucky>(leaderboard).ExecuteCommand();
            }

        }
    }
抽奖活动所有相关的代码

   5. 奖品实体如下:

 /// <summary>
    /// 奖品表
    /// </summary>
    public class fksd_prize
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }

        /// <summary>
        /// 奖品类型: 1.贡献值,3. 现金
        /// </summary>
        public int PrizeType { get; set; }

        /// <summary>
        /// 奖品金额
        /// </summary>
        public string PrizeName { get; set; }

        /// <summary>
        /// 活动id,默认0
        /// </summary>
        public int ActivityId { get; set; }

        /// <summary>
        /// 概率
        /// </summary>
        public decimal Probability { get; set; }

        /// <summary>
        /// 对应配置表的key
        /// </summary>
        public string ConfigKey { get; set; }

    }
奖品对应的实体
原文地址:https://www.cnblogs.com/wangjinya/p/13582371.html