转盘活动抽奖算法记录
一、转盘活动抽奖算法记录。
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();
以上可以看到的是,概率还是很接近的。
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; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构