飞道的博客

还在抱怨王者荣耀水晶难抽?PHP一文带你搞懂游戏中的抽奖算法

413人阅读  评论(0)

前言: 没有特别幸运,那么请先特别努力,别因为懒惰而失败,还矫情地将原因归于自己倒霉。你必须特别努力,才能显得毫不费力。

希望:所以说,树倒了,没有一片雪花是无辜的,抽奖都是假的,只有人家想让你中和不想让你中,如果大家觉得文章有帮助,请给博主一波关注和评论。

目录

一、初始化奖品

二、谢谢参与

三、过滤抽奖、如充值条件

四、重组概率

五、进行抽奖

六、过滤回调

七、最终抽奖结果

八、抽奖封装成类


一、初始化奖品

  • id 奖品的id
  • pid 奖品的自定义id
  • type 奖品类型,1、虚拟奖品 2、实物奖品 3、礼包码 待扩充
  • name 奖品名称
  • total 奖品总数
  • chance 获奖概率/抽奖基数10000
  • daynum 每日数量限制
  • pay 充值限制

  
  1. <?php
  2. $prize = [
  3. [ 'id' => 1, 'pid' => 11, 'type' => 1, 'name' => '典藏英雄', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 2000 ],
  4. [ 'id' => 2, 'pid' => 12, 'type' => 1, 'name' => '史诗皮肤', 'total' => 40, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
  5. [ 'id' => 3, 'pid' => 13, 'type' => 1, 'name' => '钻石奖励', 'total' => 80, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
  6. [ 'id' => 4, 'pid' => 14, 'type' => 1, 'name' => '荣耀水晶', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 8000 ]
  7. ];
  •  奖品详情应该从数据库中读出来
  • 奖品详情应该加入缓存,避免数据库的压力

二、谢谢参与


  
  1. <?php
  2. $thanks_prize = [
  3. 'id' => 0,
  4. 'pid' => 0,
  5. 'type' => 1,
  6. 'name' => '谢谢参与'
  7. ];
  •  为填充剩余概率的奖品

三、过滤抽奖、如充值条件


  
  1. <?php
  2. $pay_total = 7000;
  3. foreach ($prize as $key => $value) {
  4. if($value[ 'pay'] > $pay_total) unset($prize[$key]);
  5. }
  •  初步过滤一些必要因素,比如充值,角色创建时间等

四、重组概率


  
  1. <?php
  2. $now_chance = array_sum(array_column($prize, 'chance'));
  3. $remain_chance = 10000 - $now_chance;
  4. $prize[] = [ 'id' => 0, 'pid' => 0, 'type' => 1, 'name' => '谢谢参与', 'total' => 0, 'chance' => $remain_chance, 'daynum' => 0, 'pay' => 0];
  5. $award = [];
  6. $num = 0;
  7. foreach ($prize as $_v) {
  8. $num += $_v[ 'chance'];
  9. $award[] = [ 'id' => $_v[ 'id'], 'pid' => $_v[ 'pid'], 'type' => $_v[ 'type'], 'name' => $_v[ 'name'], 'total' => $_v[ 'total'], 'chance' => $num, 'daynum' => $_v[ 'daynum'], 'pay' => $_v[ 'pay']];
  10. }
  •  初步过滤后,重构新的抽奖信息,加入谢谢参与
  • 第二步重组概率

五、进行抽奖


  
  1. <?php
  2. $rand = mt_rand( 1, 10000);
  3. $result = [];
  4. foreach ($award as $_k => $_v) {
  5. if ($_k == 0) {
  6. if ($rand > 0 && $rand <= $_v[ 'chance']) {
  7. $result = $_v;
  8. break;
  9. }
  10. } else {
  11. if ($rand > $award[$_k - 1][ 'chance'] && $rand <= $_v[ 'chance']) {
  12. $result = $_v;
  13. break;
  14. }
  15. }
  16. }
  • 开始抽奖,并返回抽中的结果

六、过滤回调


  
  1. <?php
  2. //此处应该查询数据库,查看该奖品已经抽中的数量
  3. $yet_num = 50;
  4. if($result[ 'pid'] != 0 && $yet_num > $result[ 'total']) {
  5. $result = $thanks_prize;
  6. }
  7. //此处应该查询数据库,查看该奖品今日已经抽中的数量
  8. $yet_today_num = 50;
  9. if($result[ 'pid'] != 0 && $yet_today_num > $result[ 'daynum']) {
  10. $result = $thanks_prize;
  11. }
  • 二次过滤,奖品总数的限制以及奖品的每日限制等 

七、最终抽奖结果


  
  1. <?php
  2. //删除敏感字段
  3. unset($result[ 'total'],$result[ 'chance'],$result[ 'daynum'],$result[ 'pay']);
  4. //返回最终抽奖结果
  5. echo json_encode([
  6. 'prize' => $award,
  7. 'rand' => $rand,
  8. 'result' => $result
  9. ]);

八、抽奖封装成类


  
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: autofelix
  5. * Date: 2020/10/30
  6. * Time: 13:14
  7. * Desc: 抽奖算法
  8. */
  9. class Lottery
  10. {
  11. /**
  12. * 概率基数
  13. * @var int
  14. */
  15. private $total_chance = 10000;
  16. /**
  17. * 谢谢参与奖励
  18. * @var array
  19. */
  20. private $thanks_prize = [
  21. 'id' => 0,
  22. 'pid' => 0,
  23. 'type' => 1,
  24. 'name' => '谢谢参与'
  25. ];
  26. /**
  27. * 奖池
  28. * @var array
  29. */
  30. private $prize = [
  31. [ 'id' => 1, 'pid' => 11, 'type' => 1, 'name' => '典藏英雄', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 2000 ],
  32. [ 'id' => 2, 'pid' => 12, 'type' => 1, 'name' => '史诗皮肤', 'total' => 40, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
  33. [ 'id' => 3, 'pid' => 13, 'type' => 1, 'name' => '钻石奖励', 'total' => 80, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
  34. [ 'id' => 4, 'pid' => 14, 'type' => 1, 'name' => '荣耀水晶', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 8000 ]
  35. ];
  36. /**
  37. * Lottery constructor.
  38. */
  39. public function __construct()
  40. {
  41. }
  42. /**
  43. * @return int
  44. */
  45. private function get_user_pay()
  46. {
  47. //这里应该调用接口,返回用户正确的充值信息
  48. return 3000;
  49. }
  50. /**
  51. * 重构奖池、重组概率
  52. * @return array
  53. */
  54. private function init_lottery_pond()
  55. {
  56. $award = [];
  57. //充值限制
  58. $user_pay = $this->get_user_pay();
  59. foreach ( $this->prize as $key => $value) {
  60. if($value[ 'pay'] <= $user_pay) unset( $this->prize[$key]);
  61. }
  62. //加入谢谢惠顾
  63. $now_chance = array_sum(array_column( $this->prize, 'chance'));
  64. $remain_chance = $this->total_chance - $now_chance;
  65. $this->prize[] = [ 'id' => 0, 'pid' => 0, 'type' => 1, 'name' => '谢谢参与', 'total' => 0, 'chance' => $remain_chance, 'daynum' => 0, 'pay' => 0];
  66. //重组概率
  67. $num = 0;
  68. foreach ( $this->prize as $_v) {
  69. $num += $_v[ 'chance'];
  70. $award[] = [ 'id' => $_v[ 'id'], 'pid' => $_v[ 'pid'], 'type' => $_v[ 'type'], 'name' => $_v[ 'name'], 'total' => $_v[ 'total'], 'chance' => $num, 'daynum' => $_v[ 'daynum'], 'pay' => $_v[ 'pay']];
  71. }
  72. return $award;
  73. }
  74. /**
  75. * 获取抽奖结果
  76. * @return array
  77. */
  78. public function get_prize()
  79. {
  80. $award = $this->init_lottery_pond();
  81. $rand = mt_rand( 1, $this->total_chance);
  82. $result = [];
  83. foreach ($award as $_k => $_v) {
  84. if ($_k == 0) {
  85. if ($rand > 0 && $rand <= $_v[ 'chance']) {
  86. $result = $_v;
  87. break;
  88. }
  89. } else {
  90. if ($rand > $award[$_k - 1][ 'chance'] && $rand <= $_v[ 'chance']) {
  91. $result = $_v;
  92. break;
  93. }
  94. }
  95. }
  96. $result = $this->filter($result);
  97. return $result;
  98. }
  99. /**
  100. * 抽奖过滤回调函数
  101. * @param $result
  102. * @return array
  103. */
  104. public function filter($result)
  105. {
  106. //奖品总数限制,此处应该查数据库
  107. $yet_num = 50;
  108. if($result[ 'pid'] != 0 && $yet_num > $result[ 'total']) {
  109. $result = $this->thanks_prize;
  110. }
  111. //奖品每日数量限制,此处应该查数据库
  112. $yet_today_num = 50;
  113. if($result[ 'pid'] != 0 && $yet_today_num > $result[ 'daynum']) {
  114. $result = $this->thanks_prize;
  115. }
  116. //不暴露敏感信息
  117. unset($result[ 'total'], $result[ 'chance'], $result[ 'daynum'], $result[ 'pay'] );
  118. return $result;
  119. }
  120. private function __clone()
  121. {
  122. }
  123. }
  124. echo json_encode(( new Lottery())->get_prize());

 


转载:https://blog.csdn.net/weixin_41635750/article/details/109390653
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场