优化一键测试权重

This commit is contained in:
2026-03-27 14:14:59 +08:00
parent 0bdab95ab7
commit e2273ef41c
13 changed files with 403 additions and 285 deletions

View File

@@ -229,10 +229,10 @@ class DiceRewardConfigRecordLogic extends BaseLogic
}
/**
* 创建一键测试权重记录并返回 ID供后台执行器按付费/免费、顺逆方向交替写入 dice_play_record_test
* 创建一键测试权重记录并返回 ID供后台执行器写入 dice_play_record_test
* 支持两种模式1选择奖池配置 lottery_config_id档位概率取自配置2不选配置使用自定义 paid_tier_weights / free_tier_weights
* @param array|int $params 数组lottery_config_id(可选), paid_s_count, paid_n_count, free_s_count, free_n_count或兼容旧版传 4 个 int 时视为 (paid_s_count, paid_n_count, free_s_count, free_n_count)
* @param int|null $adminId 执行人(旧版 4 参调用时第二参为 paid_n_count此处不传 adminId
* @param array|int $params 数组lottery_config_id(可选), paid_s_count, paid_n_count
* @param int|null $adminId 执行人
* @return int 记录 ID
* @throws ApiException
*/
@@ -240,12 +240,10 @@ class DiceRewardConfigRecordLogic extends BaseLogic
{
$adminId = null;
if (!is_array($params)) {
// 兼容旧版调用createWeightTestRecord(paid_s_count, paid_n_count, free_s_count, free_n_count)
// 兼容旧版调用createWeightTestRecord(paid_s_count, paid_n_count)
$params = [
'paid_s_count' => (int) $params,
'paid_n_count' => (int) $adminIdOrFreeS,
'free_s_count' => (int) $freeSOrFreeN,
'free_n_count' => (int) $freeN,
];
} else {
$adminId = $adminIdOrFreeS !== null && $adminIdOrFreeS !== '' ? (int) $adminIdOrFreeS : null;
@@ -269,19 +267,18 @@ class DiceRewardConfigRecordLogic extends BaseLogic
if ($freeConfigId <= 0 && $lotteryConfigId > 0) {
$freeConfigId = $lotteryConfigId;
}
$paidS = isset($params['paid_s_count']) ? (int) $params['paid_s_count'] : (int) ($params['s_count'] ?? 0);
$paidN = isset($params['paid_n_count']) ? (int) $params['paid_n_count'] : (int) ($params['n_count'] ?? 0);
$freeS = (int) ($params['free_s_count'] ?? 0);
$freeN = (int) ($params['free_n_count'] ?? 0);
$paidS = isset($params['paid_s_count']) ? (int) $params['paid_s_count'] : 0;
$paidN = isset($params['paid_n_count']) ? (int) $params['paid_n_count'] : 0;
$chainFreeMode = !empty($params['chain_free_mode']);
foreach ([$paidS, $paidN, $freeS, $freeN] as $c) {
foreach ([$paidS, $paidN] as $c) {
if ($c !== 0 && !in_array($c, $allowed, true)) {
throw new ApiException('Counts only support 0, 100, 500, 1000, 5000');
}
}
$total = $paidS + $paidN + $freeS + $freeN;
$total = $paidS + $paidN;
if ($total <= 0) {
throw new ApiException('Sum of paid/free direction counts must be greater than 0');
throw new ApiException('Sum of paid direction counts must be greater than 0');
}
$snapshot = [];
@@ -394,24 +391,28 @@ class DiceRewardConfigRecordLogic extends BaseLogic
if (!is_array($tierWeightsSnapshot['free'])) {
$tierWeightsSnapshot['free'] = [];
}
if ($chainFreeMode) {
$tierWeightsSnapshot['chain_free_mode'] = true;
}
$record = new DiceRewardConfigRecord();
$record->test_count = $total;
$plannedPaidSpins = $paidS + $paidN;
$record->chain_free_mode = $chainFreeMode ? 1 : 0;
$record->paid_planned_spins = $plannedPaidSpins;
// 总抽奖次数与 test_count 仅在任务成功结束时写入(见 WeightTestRunner::markSuccess
$record->test_count = 0;
$record->total_play_count = 0;
$record->weight_config_snapshot = $snapshot;
$record->tier_weights_snapshot = $tierWeightsSnapshot;
$record->lottery_config_id = $lotteryConfigId > 0 ? $lotteryConfigId : null;
$record->paid_lottery_config_id = $paidConfigId > 0 ? $paidConfigId : null;
$record->free_lottery_config_id = $freeConfigId > 0 ? $freeConfigId : null;
$record->total_play_count = $total;
$record->over_play_count = 0;
$record->status = DiceRewardConfigRecord::STATUS_RUNNING;
$record->remark = null;
$record->s_count = $paidS + $paidN;
$record->n_count = $freeS + $freeN;
$record->paid_s_count = $paidS;
$record->paid_n_count = $paidN;
$record->free_s_count = $freeS;
$record->free_n_count = $freeN;
$record->play_again_count = 0;
$record->paid_tier_weights = $paidTierWeights;
$record->free_tier_weights = $freeTierWeights;
$record->result_counts = [];

View File

@@ -56,20 +56,10 @@ class WeightTestRunner
$ante = is_numeric($record->ante ?? null) ? intval($record->ante) : 1;
$paidS = (int) ($record->paid_s_count ?? 0);
$paidN = (int) ($record->paid_n_count ?? 0);
$freeS = (int) ($record->free_s_count ?? 0);
$freeN = (int) ($record->free_n_count ?? 0);
if ($paidS + $paidN + $freeS + $freeN <= 0) {
$sCount = (int) ($record->s_count ?? 0);
$nCount = (int) ($record->n_count ?? 0);
$total = $sCount + $nCount;
if ($total <= 0) {
$this->markFailed($recordId, '抽奖次数必须大于 0');
return;
}
$paidS = $sCount;
$paidN = $nCount;
} else {
$total = $paidS + $paidN + $freeS + $freeN;
$total = $paidS + $paidN;
if ($total <= 0) {
$this->markFailed($recordId, '抽奖次数必须大于 0');
return;
}
$configType0 = DiceLotteryPoolConfig::where('name', 'default')->find();
@@ -123,53 +113,30 @@ class WeightTestRunner
$done = 0;
try {
for ($i = 0; $i < $paidS; $i++) {
$usePoolWeights = $killEnabled && $poolProfitTotal >= $safetyLine && $configType1 !== null;
$paidConfig = $usePoolWeights ? $configType1 : $paidPoolConfig;
$customWeights = $usePoolWeights ? null : $paidTierWeightsCustom;
$row = $playLogic->simulateOnePlay($paidConfig, 0, 0, $ante, $customWeights);
$this->accumulateProfitForDefault($row, 0, $paidConfig, $configType0, $poolProfitTotal);
$this->aggregate($row, $resultCounts, $tierCounts);
$buffer[] = $this->rowForInsert($row, $recordId);
$done++;
$this->flushIfNeeded($buffer, $recordId, $done, $total, $resultCounts, $tierCounts);
}
for ($i = 0; $i < $paidN; $i++) {
$usePoolWeights = $killEnabled && $poolProfitTotal >= $safetyLine && $configType1 !== null;
$paidConfig = $usePoolWeights ? $configType1 : $paidPoolConfig;
$customWeights = $usePoolWeights ? null : $paidTierWeightsCustom;
$row = $playLogic->simulateOnePlay($paidConfig, 1, 0, $ante, $customWeights);
$this->accumulateProfitForDefault($row, 0, $paidConfig, $configType0, $poolProfitTotal);
$this->aggregate($row, $resultCounts, $tierCounts);
$buffer[] = $this->rowForInsert($row, $recordId);
$done++;
$this->flushIfNeeded($buffer, $recordId, $done, $total, $resultCounts, $tierCounts);
}
for ($i = 0; $i < $freeS; $i++) {
$useKillMode = $killEnabled && $poolProfitTotal >= $safetyLine && $configType1 !== null;
$freeConfig = $useKillMode ? $configType1 : $freePoolConfig;
$customWeights = $useKillMode ? null : $freeTierWeightsCustom;
$row = $playLogic->simulateOnePlay($freeConfig, 0, 1, $ante, $customWeights);
$this->accumulateProfitForDefault($row, 1, $freeConfig, $configType0, $poolProfitTotal);
$this->aggregate($row, $resultCounts, $tierCounts);
$buffer[] = $this->rowForInsert($row, $recordId);
$done++;
$this->flushIfNeeded($buffer, $recordId, $done, $total, $resultCounts, $tierCounts);
}
for ($i = 0; $i < $freeN; $i++) {
$useKillMode = $killEnabled && $poolProfitTotal >= $safetyLine && $configType1 !== null;
$freeConfig = $useKillMode ? $configType1 : $freePoolConfig;
$customWeights = $useKillMode ? null : $freeTierWeightsCustom;
$row = $playLogic->simulateOnePlay($freeConfig, 1, 1, $ante, $customWeights);
$this->accumulateProfitForDefault($row, 1, $freeConfig, $configType0, $poolProfitTotal);
$this->aggregate($row, $resultCounts, $tierCounts);
$buffer[] = $this->rowForInsert($row, $recordId);
$done++;
$this->flushIfNeeded($buffer, $recordId, $done, $total, $resultCounts, $tierCounts);
}
$this->runChainFreeMode(
$recordId,
$playLogic,
$paidS,
$paidN,
$ante,
$paidPoolConfig,
$freePoolConfig,
$paidTierWeightsCustom,
$freeTierWeightsCustom,
$configType0,
$configType1,
$safetyLine,
$killEnabled,
$poolProfitTotal,
$resultCounts,
$tierCounts,
$buffer,
$done
);
if (!empty($buffer)) {
$this->insertBuffer($buffer);
$this->updateProgress($recordId, $done, $resultCounts, $tierCounts);
// 链式/非链式:运行中均不写入 total_play_count仅在 markSuccess 落库实际总次数
$this->updateProgress($recordId, $done, $resultCounts, $tierCounts, null);
}
// 平台赚取金额:通过关联 DicePlayRecordTestreward_config_record_id统计
$this->markSuccess($recordId, $resultCounts, $tierCounts);
@@ -179,6 +146,70 @@ class WeightTestRunner
}
}
/**
* 付费次数仅由配置决定;付费抽到「再来一次」则在队列末尾插入一条免费抽奖(同方向、同底注),可链式触发
*/
private function runChainFreeMode(
int $recordId,
PlayStartLogic $playLogic,
int $paidS,
int $paidN,
int $ante,
$paidPoolConfig,
$freePoolConfig,
?array $paidTierWeightsCustom,
?array $freeTierWeightsCustom,
$configType0,
$configType1,
int $safetyLine,
bool $killEnabled,
float &$poolProfitTotal,
array &$resultCounts,
array &$tierCounts,
array &$buffer,
int &$done
): void {
$queue = [];
for ($i = 0; $i < $paidS; $i++) {
$queue[] = ['paid', 0, $ante];
}
for ($i = 0; $i < $paidN; $i++) {
$queue[] = ['paid', 1, $ante];
}
$qi = 0;
while ($qi < count($queue)) {
$item = $queue[$qi];
$isPaid = $item[0] === 'paid';
$dir = $item[1];
$playAnte = $item[2];
$lotteryType = $isPaid ? 0 : 1;
if ($isPaid) {
$usePoolWeights = $killEnabled && $poolProfitTotal >= $safetyLine && $configType1 !== null;
$cfg = $usePoolWeights ? $configType1 : $paidPoolConfig;
$customWeights = $usePoolWeights ? null : $paidTierWeightsCustom;
} else {
$useKillMode = $killEnabled && $poolProfitTotal >= $safetyLine && $configType1 !== null;
$cfg = $useKillMode ? $configType1 : $freePoolConfig;
$customWeights = $useKillMode ? null : $freeTierWeightsCustom;
}
$row = $playLogic->simulateOnePlay($cfg, $dir, $lotteryType, $playAnte, $customWeights);
$this->accumulateProfitForDefault($row, $lotteryType, $cfg, $configType0, $poolProfitTotal);
$this->aggregate($row, $resultCounts, $tierCounts);
$buffer[] = $this->rowForInsert($row, $recordId);
$done++;
if (!empty($row['grants_free_ticket'])) {
$queue[] = ['free', $dir, $playAnte];
}
$this->flushIfNeeded($buffer, $recordId, $done, count($queue), $resultCounts, $tierCounts, null);
$qi++;
}
}
/**
* 累加彩金池累计盈利,用于触发杀分,与 PlayStartLogic 一致
* @param int $lotteryType 0=付费券1=免费券
@@ -227,14 +258,14 @@ class WeightTestRunner
return $out;
}
private function flushIfNeeded(array &$buffer, int $recordId, int $done, int $total, array $resultCounts, array $tierCounts): void
private function flushIfNeeded(array &$buffer, int $recordId, int $done, int $total, array $resultCounts, array $tierCounts, ?int $recordTotalPlayCount = null): void
{
if (count($buffer) < self::BATCH_SIZE) {
return;
}
$this->insertBuffer($buffer);
$buffer = [];
$this->updateProgress($recordId, $done, $resultCounts, $tierCounts);
$this->updateProgress($recordId, $done, $resultCounts, $tierCounts, $recordTotalPlayCount);
}
private function insertBuffer(array $rows): void
@@ -259,11 +290,14 @@ class WeightTestRunner
}
}
private function updateProgress(int $recordId, int $overPlayCount, array $resultCounts, array $tierCounts): void
private function updateProgress(int $recordId, int $overPlayCount, array $resultCounts, array $tierCounts, ?int $totalPlayCount = null): void
{
$record = DiceRewardConfigRecord::find($recordId);
if ($record) {
$record->over_play_count = $overPlayCount;
if ($totalPlayCount !== null) {
$record->total_play_count = $totalPlayCount;
}
$record->result_counts = $resultCounts;
$record->tier_counts = $tierCounts;
$record->save();
@@ -288,6 +322,10 @@ class WeightTestRunner
$record->tier_counts = $tierCounts;
$record->remark = null;
$record->platform_profit = $platformProfit;
$record->play_again_count = DiceRewardConfigRecord::computePlayAgainCountFromRelated($recordId);
$actualCount = (int) DicePlayRecordTest::where('reward_config_record_id', $recordId)->count();
$record->total_play_count = $actualCount;
$record->test_count = $actualCount;
$record->save();
}
}