From 6308a0361048076d0d45b6f2d97210c57d66bbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E9=92=8A?= Date: Tue, 14 Oct 2025 11:26:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E9=9C=80=E6=B1=82-=E6=B4=BB=E5=8A=A8?= =?UTF-8?q?=E9=9C=80=E6=B1=82-=E7=9B=B2=E7=9B=92=E8=BD=AC=E7=9B=98?= =?UTF-8?q?=E8=B0=83=E9=80=9A=E7=9B=98-=E8=B0=83=E8=AF=95-=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/BlindBoxTurntableGiftDrawWorld.php | 159 ++++++++++-------- 1 file changed, 89 insertions(+), 70 deletions(-) diff --git a/application/api/model/BlindBoxTurntableGiftDrawWorld.php b/application/api/model/BlindBoxTurntableGiftDrawWorld.php index bd7f7cd..6e2f0f6 100644 --- a/application/api/model/BlindBoxTurntableGiftDrawWorld.php +++ b/application/api/model/BlindBoxTurntableGiftDrawWorld.php @@ -200,33 +200,39 @@ class BlindBoxTurntableGiftDrawWorld extends Model if ($poolInfo['code'] !== 1) { return $poolInfo; } - $totalRemaining = $poolInfo['data']['total_remaining']; - $periods = $poolInfo['data']['periods']; - $totalDrawTimes = $poolInfo['data']['total_draw_times']; + $totalRemaining = $poolInfo['data']['total_remaining'];//奖池剩余数量 + $periods = $poolInfo['data']['periods']; //奖池期数 + $totalDrawTimes = $poolInfo['data']['total_draw_times']; //总抽奖次数 // 2. 获取可用礼物 $availableGifts = $this->getAvailableGifts($bag_data['id'], $totalDrawTimes); if (empty($availableGifts)) { - $availableGifts = $this->resetPoolAndReload($bag_data['id']); + $availableGifts = $this->resetPoolAndReload($bag_data['id']); //重置奖池并重新加载 if (empty($availableGifts)) { throw new \Exception('重置奖池后仍无可用礼物'); } + $totalDrawTimes = 0;//总抽奖次数重置 } // 3. 预加载礼物信息(减少后续查询) $giftInfoMap = $this->preloadGiftInfo($availableGifts); - // 4. 处理奖池重置逻辑 + // 4. 处理奖池重置逻辑 - 优化版本 $needGiftNum = count($toarray) * $num; //总需要的礼物数 - $remaining_available_gifts=[]; - if ($totalRemaining - $needGiftNum <= 0) {//奖池剩余数量-需要的礼物数小于0 - $remaining_available_gifts = $availableGifts; //剩余可用礼物 - $availableGifts = $this->resetPoolAndReload($bag_data['id']); //重置奖池并重新加载 + $remaining_available_gifts = []; + $remainingGiftCount = array_sum(array_column($availableGifts, 'remaining_number')); + + if ($remainingGiftCount < $needGiftNum) { + // 如果当前奖池礼物不足以满足需求 + // 保存当前剩余礼物作为上期剩余 + $remaining_available_gifts = $availableGifts; + + // 重置奖池 + $availableGifts = $this->resetPoolAndReload($bag_data['id']); if (empty($availableGifts)) { throw new \Exception('重置奖池后仍无可用礼物'); } - $totalDrawTimes = 0; - $num = abs($totalRemaining - $num); + $totalDrawTimes = 0; // 总抽奖次数重置 } // 5. 使用Alias Method预计算抽奖结果(O(1)复杂度) @@ -269,82 +275,95 @@ class BlindBoxTurntableGiftDrawWorld extends Model &$currentXlhPeriodsNum, $remaining_available_gifts ) { - //计算$remaining_available_gifts 里面 remaining_number 的累加 - $remaining_num = 0; - foreach ($remaining_available_gifts as $key=>$value) { - $remaining_num += $value['remaining_number']; - } - if($remaining_num > $num){ - $availableGifts = $remaining_available_gifts; - $remaining_available_gifts = []; - } $precomputedResults = []; $precomputedResultss = []; - $giftBagIdToGift = []; - // 构建Alias表 - $aliasTable = $this->buildAliasTable($availableGifts); - $remaining_num = 0; - foreach ($toarray as $giftUserId) { - if (!empty($remaining_available_gifts)) { - foreach ($remaining_available_gifts as $key=>$value) { - $remaining_num += $value['remaining_number']; - $gift = $giftInfoMap[$value['foreign_id']] ?? null; - for ($j = 0; $j < $value['remaining_number']; $j++) { + // 计算上期剩余礼物总数 + $remainingGiftCount = array_sum(array_column($remaining_available_gifts, 'remaining_number')); + $needGiftNum = count($toarray) * $num; + $newGiftsNeeded = max(0, $needGiftNum - $remainingGiftCount); // 计算还需要多少礼物从新奖池中抽取 + + // 先从上期剩余礼物中分配 + if (!empty($remaining_available_gifts)) { + $aliasTableForRemaining = $this->buildAliasTable($remaining_available_gifts); + + foreach ($toarray as $giftUserId) { + // 为每个用户先分配上期剩余礼物 + $userRemainingAllocation = floor($remainingGiftCount / count($toarray)); + if (count($toarray) > 0) { // 防止除零错误 + $extraGifts = $remainingGiftCount % count($toarray); + if (array_search($giftUserId, $toarray) < $extraGifts) { + $userRemainingAllocation++; + } + } + + for ($i = 0; $i < $userRemainingAllocation; $i++) { + $selectedGift = $this->selectGiftWithAliasMethod($aliasTableForRemaining); + if ($selectedGift) { + $gift = $giftInfoMap[$selectedGift['foreign_id']] ?? null; $precomputedResults[] = [ 'gift_user_id' => $giftUserId, - 'gift_bag_detail' => $value, + 'gift_bag_detail' => $selectedGift, + 'gift' => $gift, + 'draw_times' => $totalDrawTimes, + 'periods' => $periods, + ]; + $precomputedResultss[] = [ + 'gift_user_id' => $giftUserId, + 'gift_bag_detail' => $selectedGift, 'gift' => $gift, 'draw_times' => $totalDrawTimes, 'periods' => $periods, - 'j' => $j, ]; $totalDrawTimes++; $currentXlhPeriodsNum++; + // 更新Alias表 + $this->updateAliasTable($aliasTableForRemaining, $selectedGift['id']); } - unset($remaining_available_gifts[$key]); } - $numm = $num; - }else{ - $numm = $num+$remaining_num; } - for ($i = 0; $i < $numm; $i++) { - // 使用Alias Method选择礼物(O(1)复杂度) - $selectedGift = $this->selectGiftWithAliasMethod($aliasTable); - if (!$selectedGift) { - return []; + } + + // 再从新奖池中分配剩余所需礼物 + if ($newGiftsNeeded > 0 && !empty($availableGifts)) { + $aliasTableForNew = $this->buildAliasTable($availableGifts); + + foreach ($toarray as $giftUserId) { + // 计算每个用户需要从新奖池获得的礼物数量 + $userNewAllocation = floor($newGiftsNeeded / count($toarray)); + if (count($toarray) > 0) { + $extraGifts = $newGiftsNeeded % count($toarray); + if (array_search($giftUserId, $toarray) < $extraGifts) { + $userNewAllocation++; + } } - // 获取礼物信息(从预加载的map中获取,避免查询) - $giftId = $selectedGift['foreign_id']; - $gift = $giftInfoMap[$giftId] ?? null; -// if (!$gift) { -// continue; -// } + for ($i = 0; $i < $userNewAllocation; $i++) { + $selectedGift = $this->selectGiftWithAliasMethod($aliasTableForNew); + if ($selectedGift) { + $gift = $giftInfoMap[$selectedGift['foreign_id']] ?? null; + $precomputedResults[] = [ + 'gift_user_id' => $giftUserId, + 'gift_bag_detail' => $selectedGift, + 'gift' => $gift, + 'draw_times' => $totalDrawTimes, + 'periods' => $periods, + ]; + $precomputedResultss[] = [ + 'gift_user_id' => $giftUserId, + 'gift_bag_detail' => $selectedGift, + 'gift' => $gift, + 'draw_times' => $totalDrawTimes, + 'periods' => $periods, + ]; + $totalDrawTimes++; + $currentXlhPeriodsNum++; - $precomputedResults[] = [ - 'gift_user_id' => $giftUserId, - 'gift_bag_detail' => $selectedGift, - 'gift' => $gift, - 'draw_times' => $totalDrawTimes, - 'periods' => $periods, - 'i' => $i, - ]; - $precomputedResultss[] = [ - 'gift_user_id' => $giftUserId, - 'gift_bag_detail' => $selectedGift, - 'gift' => $gift, - 'draw_times' => $totalDrawTimes, - 'periods' => $periods, - 'i' => $i, - ]; - - $totalDrawTimes++; - $currentXlhPeriodsNum++; - - // 更新Alias表(模拟库存减少) - $this->updateAliasTable($aliasTable, $selectedGift['id']); + // 更新Alias表 + $this->updateAliasTable($aliasTableForNew, $selectedGift['id']); + } + } } } @@ -855,7 +874,7 @@ class BlindBoxTurntableGiftDrawWorld extends Model $totalQuantity = $roomPanInfo['total_quantity'] ?: 0; $totalRemaining = $roomPanInfo['total_remaining'] ?: 0; $periods = $periods ?: 0; - $totalDrawTimes = max(0, $totalQuantity - $totalRemaining); + $totalDrawTimes = max(0, $totalQuantity - $totalRemaining); //总抽奖次数 return [ 'code' => 1, 'msg' => '计算成功',