相同概率的抽奖程序另类实现——使用数据库,无需数学原理

  抽奖,是很多企业、聚会的常见玩乐形式,光彩绚丽的抽奖屏幕背后,是计算程序+抽奖用户信息。程序=算法+数据结构。

好,说抽奖程序的的实现吧。这个实现一般需要应用数学原理。而本文的方法是我在参加一次婚礼的抽奖体验后突然想到的,一种比较简单、无需数学原理的方法。

功能:能按照相同概率,从用户集合中抽出随机的部分用户集合作为中奖者。抽奖可以进行多次,对已中奖的用户不会重复抽取。

  使用技术:

1.SqlServer数据库,使用NewID()作为select随机筛选函数

2.sql随机函数

3.为了快速方便的搭建原型,使用EF 4.1 DB first,然后代码生成Model类(我在快速开发原型是喜欢EF,讨厌sql-实体转换。能让我从sql中解放出来,专注业务逻辑。只有

当需要的sql逻辑比较复杂,EF难以实现或效率不行时我才写sql-实体转换)。

 

  主要逻辑:

1.建立LotteryUsers(抽奖用户的英文词组)表,定义用户信息、以及是否已中过奖的标志位IsLotteried,默认都是false-0(IsDelete-该用户是否已删除、无效)。

2.执行sql查询出定量的中奖用户集合 :

SELECT TOP(@chooseCount) * FROM LotteryUsers lu WHERE lu.IsDeldte = 0 AND lu.IsLotteried = 0  ORDER BY NEWID()

并且将这些中奖用户的IsLotteried字段设置为true-1

3.控制台显示中奖的用户集合

 

DB建表语句:

 1 CREATE TABLE [dbo].[LotteryUsers](
 2     [Id] [int] IDENTITY(1,1) NOT NULL,
 3     [JobNumber] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
 4     [Name] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
 5     [IsLotteried] [bit] NOT NULL,
 6     [IsDeldte] [bit] NOT NULL,
 7  CONSTRAINT [PK_LotteryUsers] PRIMARY KEY CLUSTERED 
 8 (
 9     [Id] ASC
10 )
View Code

结构、示例数据:

 

程序结构:

代码(使用EF 4.1,实体生成模型),代码细节、EF技术看不懂没关系,了解原理即可:

 1 static void Main(string[] args)
 2         {
 3             //添加测试数据:用户信息
 4             ////using (LotteryContext context = new LotteryContext())
 5             ////{
 6             //    for (int i = 1; i < 101; i++)
 7             //    {
 8             //        LotteryUser user = new LotteryUser
 9             //        {
10             //            JobNumber = i.ToString("00000"),
11             //            Name = "niu"+i.ToString(),
12             //            IsLotteried = false,
13             //            IsDeldte = false,
14             //        };
15             //        context.LotteryUsers.Add(user);
16             //    }
17             //    context.SaveChanges();
18             //}
19 
20             //从用户集合中随机抽取部分中奖用户显示
21             var lotteryUsers = GetPrizeUsersAndUpdatePrized(10);
22             foreach (var lotteryUser in lotteryUsers)
23             {
24                 Console.WriteLine(string.Join(",", lotteryUser.Id, lotteryUser.JobNumber, lotteryUser.Name));
25             }
26 
27         }
28 
29         /// <summary>
30         /// 从用户集合中随机抽取部分中奖用户,并将这些用户更新为已中奖、下次不会重复中奖
31         /// </summary>
32         /// <param name="chooseCount">指定中奖用户个数</param>
33         public static List<LotteryUser> GetPrizeUsersAndUpdatePrized(int chooseCount)
34         {
35             List<LotteryUser> lotteryUsers = new List<LotteryUser>();
36             using (LotteryContext context = new LotteryContext())
37             {
38 
39                 string lotteryUsersSql = @"SELECT TOP(@chooseCount) * FROM LotteryUsers lu 
40                                         WHERE lu.IsDeldte = 0 AND lu.IsLotteried = 0 
41                                         ORDER BY NEWID()";
42                 lotteryUsers = context.LotteryUsers.SqlQuery(lotteryUsersSql
43                     , new SqlParameter("@chooseCount", chooseCount)).ToList();
44                 //foreach (var lotteryUser in lotteryUsers)
45                 //{
46                 //    Console.WriteLine(string.Join(",", lotteryUser.Id, lotteryUser.JobNumber, lotteryUser.Name, lotteryUser.IsLotteried, lotteryUser.IsDeldte));
47                 //}
48                 
49                 //更新已得过奖状态为:是
50                 foreach (var lotteryUser in lotteryUsers)
51                 {
52                     lotteryUser.IsLotteried = true;
53                 }
54                 context.SaveChanges();
55 
56                 return lotteryUsers;
57             }
58         }
View Code

 

就这样,lotteryUsers即是中奖的用户。若要继续抽奖,只要再调用GetPrizeUsersAndUpdatePrized()即可,中奖用户不会重复。

 

 

---------------------------------------------备注、其他----------------

1.对于某些抽奖,若要内定某些VIP中某个奖,最好不要写死、在配置文件中写上VIP的名字,在抽奖函数中传入这些VIP的名单、直接确认。

2.对于某些次VIP们,若需要提高中奖概率,需要待议。可能实现的方法有:在users表中加上权重Pritory值,然后再做某些操作;或者采用其他较复杂的数学实现方法。

3.我的程序不注重程序\DB效率,所以未经优化。但是实际上,一般抽奖用户也就1W人以下,完全不存在性能问题。(中国16亿人全名抽奖,淘宝京东等全站抽奖数据量很大的,需要另行优化)。

posted on 2015-10-06 16:40  nlh774  阅读(859)  评论(0编辑  收藏  举报