不確定人數的抽獎方法


很多年前就給前公司的年會做過年會抽獎,基本要求就是年會入場時簽到,簽到的員工都參與抽獎(也可以設置公司高管過濾,不參與抽獎),獎品是預設好的,到時候就是給所有簽到員工編號,然后抽獎過程中不斷生成一組隨機數,這些隨機數對應的編號的員工姓名和照片就顯示出來,這是很容易想到的算法。

但是還要一種情況就是互聯網模式的抽獎,有點像雙十一之前,阿里派發紅包一樣,大家都可以在開始抽獎的時候去抽,獎品也是預設好的,比如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; 
      } 
  }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM