不确定人数的抽奖方法

很多年前就给前公司的年会做过年会抽奖,基本要求就是年会入场时签到,签到的员工都参与抽奖(也可以设置公司高管过滤,不参与抽奖),奖品是预设好的,到时候就是给所有签到员工编号,然后抽奖过程中不断生成一组随机数,这些随机数对应的编号的员工姓名和照片就显示出来,这是很容易想到的算法。

但是还要一种情况就是互联网模式的抽奖,有点像双十一之前,阿里派发红包一样,大家都可以在开始抽奖的时候去抽,奖品也是预设好的,比如1000W的奖金池,派发完毕就抽奖完毕,每个用户可以抽取多次。这种抽奖方式主要是应对抽奖人数不确定的情况,谁也不需要提前签到报名,到了抽奖时间只要注册用户都可以抽奖。

因为抽奖人数不确定,所以采用一人多次抽奖的方案是很好的,对用户来说也是,如果第一次没有抽中,还可以尝试第二次,第三次。具体算法上,其实更简单,因为用户点击抽奖的顺序是随机的,所以我们连随机数都不用用,直接给用户的一次抽奖请求编个自增的号,如果这个号满足中奖规则,那么就分配礼品,返回该抽奖请求中奖结果,如果不满足中奖规则,那么我们就返回未中奖。

为了避免用户频繁的点击,造成服务器过高的负担,我们可以在客户端设置一个动画过程,比如转盘抽奖,可以转几秒以后才请求服务器,看是否中奖,对用户来说也增加了趣味性。为了避免用户不通过客户端,直接发起频繁的HTTP请求来刷奖,我们甚至可以在服务器设置同一个用户的请求时间间隔。

下面贴出我写的一个示例代码部分,我设置了一个自增的整数Sequence ,每个正常的抽奖请求,则Sequence ++,另外设置默认的抽奖基数baseNumber=100,如果能够Sequence能够被baseNumber整除,那么就中奖,否则不中奖:

[RoutePrefix("api/Lottery")]
  public class LotteryController : AbpApiController
  {

      private static volatile int Sequence = 1;
      private static IList<int> winnerList=new List<int>();
      /// <summary>
      /// 抽奖开始标记,请通过StartNewLotteryRound打开
      /// </summary>
      private static bool start = false;
      /// <summary>
      /// 所有产品都被抽完了的标记
      /// </summary>
      private static bool allPrizeOut = false;
      /// <summary>
      /// 当前轮次ID
      /// </summary>
      private static int currentRoundId = 0;
      public ILotteryAppService LotteryAppService { get; set; }
      /// <summary>
      /// 抽奖基数,只要被该数整除就中奖
      /// </summary>
      private static int baseNumber =100;
      private static IDictionary<int,DateTime> userDrawTime=new Dictionary<int, DateTime>();

      private bool CheckUserDrawTime(int userId)
      {
          if (userDrawTime.ContainsKey(userId))
          {
              return userDrawTime[userId].AddSeconds(8) < DateTime.Now;//8s后可以抽奖
          }
          else
          {
              return true;
          }
      }
      /// <summary>
      /// 抽奖一次
      /// </summary>
      /// <param name="userId"></param>
      /// <returns></returns>
      [HttpGet]
      [Route("Draw/{userId}")]
      public DrawResult Draw(int userId)
      {
          if (!start)
          {
              return new DrawResult(400,0, "抽奖未开始");
          }
          if (allPrizeOut)
          {
              return new DrawResult(400, 0, "所有奖品已抽完");
          }
          if (!CheckUserDrawTime(userId))
          {
              return new DrawResult(400, 0, "请求过于频繁,请稍后再试");
          }

          int myNumber = Sequence++;
          userDrawTime[userId] = DateTime.Now;//记录用户这次抽奖的时间

          if (myNumber%baseNumber == 0) //中奖啦!
          {
              if (winnerList.Contains(userId))
              {
                  //用户已经中奖,不用再抽
                  return new DrawResult(200, 0, "您已经中过奖了");
              }
              var result = LotteryAppService.WriteAWinner(userId, currentRoundId);

              switch (result.ExceptionType)
              {
                  case LotteryExceptionType.NoException:
                  {
                      winnerList.Add(userId);

                      return new DrawResult(200, result.PrizeId, "");
                  }
                  case LotteryExceptionType.AllPrizeOut:
                  {
                      allPrizeOut = true;
                      return new DrawResult(400, 0, "所有奖品已抽完");

                  }
                  case LotteryExceptionType.InvalidLotteryRound:
                  {
                      return new DrawResult(400, 0, "抽奖轮次无效");
                  }
                  default:
                  {
                      return new DrawResult(400, 0, "当前用户无效");
                  }

              }

          }
          return new DrawResult(200, 0, "");

      }

      /// <summary>
      /// 获得我的奖品对象
      /// </summary>
      /// <param name="userId"></param>
      /// <returns></returns>
      [HttpGet]
      [Route("MyPrize/{userId}")]
      public IList<LotteryDto> GetMyPrize(int userId)
      {
          return LotteryAppService.GetMyPrize(userId);
      }

      /// <summary>
      /// 开始新一轮的抽奖
      /// </summary>
      /// <param name="roundId"></param>
      [HttpPost]
      [Route("StartNewLotteryRound")]
      [AbpApiAuthorize(PermissionNames.Admin)]
      public bool StartNewLotteryRound(int roundId)
      { 

          start = true;
          allPrizeOut = false;
          currentRoundId = roundId;
          return true;
      }
      /// <summary>
      /// 获得当前轮次的奖品和获奖者
      /// </summary>
      /// <returns></returns>
      [HttpGet]
      [Route("")]
      public IList<LotteryDto> GetLotteries()
      {
        return  LotteryAppService.GetLotteries(currentRoundId);
      }
      /// <summary>
      /// 获得所有的奖品和获奖者
      /// </summary>
      /// <returns></returns>
      [HttpGet]
      [Route("All")]
      public IList<LotteryDto> GetAllLotteries()
      {
          return LotteryAppService.GetLotteries(0);
      }
      /// <summary>
      /// 清空中奖结果,各种缓存
      /// </summary>
      /// <returns></returns>
      [HttpPost]
      [Route("Clean")]
      [AbpApiAuthorize(PermissionNames.Admin)]
      public bool Clean()
      {
          Sequence = 1;
          start = false;
          winnerList.Clear();
          LotteryAppService.CleanLotteries();
          return true;
      }
      /// <summary>
      /// 获取是否显示抽奖图标
      /// </summary>
      /// <returns></returns>
      [HttpGet]
      [Route("ShowLotteryIcon")]
      public bool GetShowLotteryIcon()
      {
          return LotteryAppService.ShowLotteryIcon;
      }
      /// <summary>
      /// 设置是否显示抽奖图标
      /// </summary>
      /// <param name="show"></param>
      /// <returns></returns>
      [HttpPut]
      [Route("ShowLotteryIcon/{show}")]
      public HttpResponseMessage SetShowLotteryIcon(bool show)
      { 

          try
          {
              LotteryAppService.ShowLotteryIcon = show;
              return Request.CreateResponse(HttpStatusCode.OK, true);
          }
          catch (Exception ex)
          {
              var resp = new HttpResponseMessage(HttpStatusCode.BadGateway)
              {
                  Content = new StringContent("设置ShowLotteryIcon失败:" + ex.Message),
                  ReasonPhrase = "Gateway failed"
              };
              throw new HttpResponseException(resp);
          }
      }

      /// <summary>
      /// 设置Base Number
      /// </summary>
      /// <param name="number"></param>
      /// <returns></returns>
      [HttpPut]
      [AbpApiAuthorize(PermissionNames.Admin)]
      [Route("SetBaseNumber/{number}")]
      public bool SetBaseNumber(int number)
      {
          baseNumber = number;
          return true;
      }
  }
时间: 2024-12-16 13:03:50

不确定人数的抽奖方法的相关文章

java模拟一个抽奖程序

今天用一个程序模拟一个从1-32之间,随机抽取7组号码的抽奖程序 * 需要使用Java的图形界面知识 * 窗口  JFrame * 面板  JPanel * 显示文本信息的标签  JLabel * 文本框 JTextField * 按钮  JButton 还涉及到线程Thread 先看效果图: 但是这里留一个问题?就是去除重复数字(可以自己先实现,后期我会上传的) 下面看看代码,代码中有注释,不懂留言: package thread.test1; import java.awt.BorderLa

如何用 Python 写一个简易的抽奖程序

不知道有多少人是被这个头图骗进来的:) 事情的起因是这样的,上周有同学问小编,看着小编的示例代码敲代码,感觉自己也会写了,如果不看的话,七七八八可能也写的出来,但是一旦自己独立写一段程序,感觉到无从下手. 其实这个很正常,刚开始学习写代码,都是跟着别人的套路往下写,看的套路少,很难形成自己的套路,这就和做数学题是一样的,做一道题就想会所有的题目,这个可能性微乎其微,都是通过大量的练习来摸索到自己的套路. 正好快过年了,各个公司都会搞一些抽奖活动,小编今天就来聊一下,如果要写一个简单的抽奖程序,小

消息化服务自实现设计

背景 一直想自己试试设计一个只属于自己的小框架,于是就有了这个项目. 代码地址 https://coding.net/u/mich/p/MiniServer/git 项目说明 该项目主要将每个服务都配置一个消息队列,服务间通过消息进行传递,同时提供了控制台指令,进行服务的管理,实现一些后台的工作(主要web太麻烦了,所以控制台输入最省力),该项目只处理过一些小型后台任务,未在正式大型项目中实际使用过! 未来展望 1. 以后估计会将以往做过的微博用户数据抓取,tower对接,股票数据抓取及分析等已

Girls and Boys

传送门 Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 12717   Accepted: 5659 Description In the second year of the university somebody started a study on the romantic relations between the students. The relation "romantically involved"

Application对象

11.1  Application对象 Application对象生存期和Web应用程序生存期一样长,生存期从Web应用程序网页被访问开始,HttpApplication类对象Application被自动创建,直到没有一个网页被访问时结束,Application对象被自动撤销.因此Application对象中的变量也有相同生存期,并且变量可以被Web应用程序中的所有网页访问.因此,可以在Application对象中建立一些全局的公用变量,由于存储在Application对象中的数值可以被应用程序

嘿嘿,今天学习啦数据检索啦

嘿嘿,今天是周二啦,昨天开始初步学习啦数据库,那么今天我们就是详细的学习啦数据库的检索啦,或许今天学习的比较多,但是我感觉还是可以的啦,最重要的是我可以接受的啦,这个是最值得庆幸的啦,现在每天学习完在这里总结成为了我的习惯,在总结中我会有更多新的发现,或许就像今天一位友友和我说的,认为我现在在培训,哪里还有时间写博客那,我想说的是,我的确把今天学习的知识都熟悉熟悉,然后自己按照老师讲的操作一遍后才来写的博客,也许还有人会问?操作一遍都可以没事情啦吗,今天学习的知识就掌握啦吗,当然不是啦,我们现在

Cookie客户端缓存.Session.Application

Cookie客户端缓存. 1.引言 随着浏览器的处理能力不断增强,越来越多的网站开始考虑将数据存储在「客户端」,那么久不得不谈本地存储了. 本地存储的好处: 一是避免取回数据前页面一片空白,如果不需要最新数据也可以减少向服务器的请求次数,从而减少用户等待从服务端获取数据的时间. 二是网络状态不佳时仍可以显示离线数据. 2.本地存储 用chrome浏览器打开一个网页,F12进入开发者模式,点击Application,我们可以看到: 以上的Local Stroage . Session Stroag

2017元宵节节抽奖活动

活动奖品:思科技术书籍<策略驱动型数据中心--ACI技术详解>,原价69元,共2本 活动方式:在本帖留言即可(留言内容任意),每人限留言一次,重复留言无效 抽奖方法:按留言楼层,随机函数取随机2个楼层数,每人一本,包邮 活动限制:本次活动仅限QQ群:375980347所有成员参与,结果会在群中公布 活动时间:2017年2月8日--11日 本此活动,教材特殊,技术难度比较大 建议对本教材涉及到的技术有现实需求的群成员参与,以免浪费 后续还会有更多的抽奖活动,敬请关注.

黄金分割点作业进度

  结对编程的作业: 黄金点游戏 黄金点游戏是一个数字小游戏,其游戏规则是: N个同学(N通常大于10),每人写一个0~100之间的有理数 (不包括0或100),交给裁判,裁判算出所有数字的平均值,然后乘以0.618(所谓黄金分割常数),得到G值.提交的数字最靠近G(取绝对值)的同学得到N分,离G最远的同学得到-2分,其他同学得0分.玩了几天以后,大家发现了一些很有意思的现象,比如黄金点在逐渐地往下移动. 现在请大家根据这个游戏规则,编一个可以多人一起玩的小游戏程序,要求如下: 1.本作业属于结