PromotionRules.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. <?php
  2. namespace App\Support;
  3. use Illuminate\Support\Facades\Validator;
  4. final class PromotionRules
  5. {
  6. public const LOSS = 7;
  7. public const FIRST_DEPOSIT = 8;
  8. public const WHEEL = 9;
  9. public const TASKS = ['online', 'login', 'invite', 'deposit', 'team_deposit', 'bet', 'team_bet'];
  10. public const DAILY = ['online', 'login'];
  11. public const PRIZES = ['0-666', '100', '50', '200', '350', '500', '150', '366'];
  12. public static function supports(int $type): bool { return in_array($type, [7, 8, 9], true); }
  13. public static function types(): array { return [7 => '净亏邀请奖励', 8 => '首充奖励', 9 => '转盘活动']; }
  14. public static function defaults(int $type): array
  15. {
  16. $common = ['turnover_ratio' => '0.00'];
  17. return $common + match ($type) {
  18. 7 => ['loss_amount' => '500.00', 'invite_count' => 3, 'reward_amount' => '500.00'],
  19. 8 => ['min_deposit' => '100.00', 'reward_amount' => '10.00'],
  20. 9 => ['completion_probability' => '20.00', 'online_seconds' => 3600,
  21. 'deposit_amount' => '3000.00', 'team_deposit_amount' => '500.00',
  22. 'bet_amount' => '5000.00', 'team_bet_amount' => '3000.00'],
  23. default => [],
  24. };
  25. }
  26. public static function normalize(int $type, array $input): array
  27. {
  28. $defaults = self::defaults($type);
  29. Validator::make(['params' => $input], ['params' => ['array:' . implode(',', array_keys($defaults))]])->validate();
  30. $data = array_replace($defaults, $input);
  31. $rules = [];
  32. foreach ($data as $key => $value) {
  33. $rules[$key] = match ($key) {
  34. 'invite_count' => ['required', 'integer', 'min:1', 'max:1000'],
  35. 'online_seconds' => ['required', 'integer', 'min:60', 'max:86400'],
  36. 'completion_probability' => ['required', 'numeric', 'between:0,100', 'regex:/^\d{1,3}(\.\d{1,2})?$/'],
  37. 'turnover_ratio' => ['required', 'numeric', 'between:0,10000', 'regex:/^\d{1,5}(\.\d{1,2})?$/'],
  38. default => ['required', 'numeric', 'gt:0', 'regex:/^\d{1,12}(\.\d{1,2})?$/'],
  39. };
  40. }
  41. Validator::make($data, $rules)->validate();
  42. foreach ($data as $key => $value) $data[$key] = in_array($key, ['invite_count', 'online_seconds'], true) ? (int)$value : bcadd((string)$value, '0', 2);
  43. return $data;
  44. }
  45. public static function draw(int $coins, bool $complete, string $probability, ?callable $random = null): array
  46. {
  47. $random ??= fn (int $min, int $max) => random_int($min, $max);
  48. $remaining = 66600 - $coins;
  49. if ($remaining <= 0) throw new \LogicException('请先领取本轮奖金');
  50. $hit = $complete && $random(1, 10000) <= (int)bcmul($probability, '100', 0);
  51. if ($hit) return ['prize_index' => 0, 'amount_cents' => $remaining, 'reached' => true];
  52. // Choose eligible sectors before drawing. A fixed face value is never truncated.
  53. $eligible = [0];
  54. foreach (self::PRIZES as $i => $amount) if ($i && (int)$amount * 100 < $remaining) $eligible[] = $i;
  55. $index = $eligible[$random(0, count($eligible) - 1)];
  56. $amount = $index === 0 ? $random(0, $remaining - 1) : (int)self::PRIZES[$index] * 100;
  57. return ['prize_index' => $index, 'amount_cents' => $amount, 'reached' => false];
  58. }
  59. }