优化ai小班长

This commit is contained in:
2026-04-12 22:42:32 +08:00
parent d739fc7028
commit 353aaaf6ce
6 changed files with 36 additions and 36 deletions

View File

@@ -5,7 +5,7 @@
*
* 在每局百家乐开启时延迟调度执行:
* 1. 检查是否存在连输休息惩罚1小时
* 2. 检查可用金币,确保留存底金
* 2. 检查可用金币与活动时间窗,确定本局下注额度
* 3. 调用 AI 接口预测路单走势决定下注方向AI 不可用时回退本地决策)
* 4. 提交下注
*
@@ -87,10 +87,10 @@ class AiBaccaratBetJob implements ShouldQueue
// 5. 查询当前是否命中“你玩游戏我买单”活动窗口。
$lossCoverService = app(BaccaratLossCoverService::class);
$lossCoverEvent = $lossCoverService->findEventForBetTime(now());
$hasActiveLossCover = $lossCoverEvent?->status === 'active';
$isInLossCoverWindow = $lossCoverEvent !== null;
// 买单活动进行中时允许 AI 全仓下注;平时只动用当前手上的 jjb,不再强制保留 100 万
$bettableGold = $hasActiveLossCover
// 买单活动进行中时允许 AI 统筹“手上 + 银行”总资产;平时只动用当前手上的 jjb。
$bettableGold = $isInLossCoverWindow
? $aiFinance->getTotalGoldAssets($user)
: $aiFinance->getSpendableGold($user);
if ($bettableGold < $minBet) {
@@ -129,7 +129,7 @@ class AiBaccaratBetJob implements ShouldQueue
'recent_results' => $recentResults,
'available_gold' => $bettableGold,
'historical_bets' => $historicalBets,
'loss_cover_active' => $hasActiveLossCover,
'loss_cover_active' => $isInLossCoverWindow,
];
$aiPrediction = $predictionService->predict($context);
@@ -145,10 +145,10 @@ class AiBaccaratBetJob implements ShouldQueue
$reason = $aiPrediction['reason'];
if ($betType !== 'pass') {
if ($hasActiveLossCover) {
// 买单活动进行中AI 可放心动用全部总资产,因为本局若输可返还
$amount = $bettableGold;
$reason = trim($reason.' 买单活动进行中,本局采用总资产全额下注策略。');
if ($isInLossCoverWindow) {
// 买单活动进行中且金币足够时,直接按百家乐单局最高限额下注
$amount = min($bettableGold, $maxBet);
$reason = trim($reason.' 买单活动进行中,本局按百家乐最高限额下注。');
} else {
// 非买单活动期间,限定单局最高下注不超过手头金币的 5% 以防止 AI 破产。
$percent = min(5, max(0, $percent));
@@ -177,10 +177,10 @@ class AiBaccaratBetJob implements ShouldQueue
}
if ($betType !== 'pass') {
if ($hasActiveLossCover) {
// 本地兜底策略命中买单活动时,同样执行总资产全额下注。
$amount = $bettableGold;
$reason = '买单活动进行中,采用本地总资产全额下注兜底策略。';
if ($isInLossCoverWindow) {
// 本地兜底策略命中买单活动时,同样优先按百家乐最高限额下注。
$amount = min($bettableGold, $maxBet);
$reason = '买单活动进行中,采用本地最高限额下注兜底策略。';
} else {
$percent = rand(2, 5) / 100.0;
$amount = (int) round($bettableGold * $percent);
@@ -207,8 +207,8 @@ class AiBaccaratBetJob implements ShouldQueue
return;
}
// 买单活动期间允许全仓下注;非活动期间只检查当前手上金币是否够本次下注。
$isReadyToSpend = $hasActiveLossCover
// 买单活动期间允许为本次高额下注从银行调拨;非活动期间只检查当前手上金币是否够本次下注。
$isReadyToSpend = $isInLossCoverWindow
? $aiFinance->prepareAllInSpend($user, $amount)
: $aiFinance->prepareSpend($user, $amount);
if (! $isReadyToSpend) {

View File

@@ -5,7 +5,7 @@
*
* 统一维护 AI小班长的银行存取与阶段性理财里程碑公告
* 常规场景下仅在手上金币超过 100 万时自动存银行,
* 特殊场景(如买单活动全仓下注)才会动用银行资产。
* 特殊场景(如买单活动的大额下注)才会动用银行资产。
*/
namespace App\Services;
@@ -17,7 +17,7 @@ use App\Models\User;
use Illuminate\Support\Facades\DB;
/**
* 负责 AI小班长的常规存款、全仓取款与里程碑播报。
* 负责 AI小班长的常规存款、大额调款与里程碑播报。
*/
class AiFinanceService
{
@@ -74,9 +74,9 @@ class AiFinanceService
}
/**
* 全仓支出准备手头金币。
* 大额支出准备手头金币。
*
* 该模式不会保留手上余额阈值,适用于买单活动等可接受全额下注的场景。
* 该模式不会保留手上余额阈值,适用于买单活动等需要临时调拨银行金币的场景。
*/
public function prepareAllInSpend(User $user, int $spendAmount): bool
{

View File

@@ -105,13 +105,17 @@ class BaccaratLossCoverService
/**
* 获取某个下注时间点命中的活动。
*
* 这里按管理员设定的开始/结束时间窗口判断,
* 不强依赖后台状态已经及时切到 active
* 这样刚到开始时间的活动也能立即参与买单判定。
*/
public function findEventForBetTime(?Carbon $betTime = null): ?BaccaratLossCoverEvent
{
$betTime = $betTime ?? now();
return BaccaratLossCoverEvent::query()
->whereIn('status', ['active', 'settlement_pending', 'claimable'])
->whereNotIn('status', ['cancelled', 'completed'])
->where('starts_at', '<=', $betTime)
->where('ends_at', '>=', $betTime)
->orderByDesc('id')

View File

@@ -106,10 +106,6 @@
class="text-purple-300 hover:text-purple-100 font-bold flex items-center transition hidden sm:flex {{ request()->routeIs('duty-hall.*') ? 'text-purple-100 underline underline-offset-4' : '' }}">
勤务台
</a>
<a href="{{ route('vip.center') }}"
class="text-rose-400 hover:text-rose-300 font-bold flex items-center transition hidden sm:flex {{ request()->routeIs('vip.center') ? 'text-rose-200 underline underline-offset-4' : '' }}">
会员中心
</a>
<a href="{{ route('guestbook.index') }}"
class="text-indigo-200 hover:text-white font-bold flex items-center transition hidden sm:flex">
留言板

View File

@@ -3,7 +3,7 @@
/**
* 文件功能AI小班长百家乐下注任务测试
*
* 覆盖 AI 在“你玩游戏我买单”活动进行中时的全额下注策略,
* 覆盖 AI 在“你玩游戏我买单”活动时间窗口内的最高限额下注策略,
* 并验证下注会正确挂到买单活动记录上。
*/
@@ -57,9 +57,9 @@ class AiBaccaratBetJobTest extends TestCase
}
/**
* 买单活动进行中时AI 动用全部总资产下注,并把下注挂到活动名下。
* 买单活动时间窗口命中时AI 按百家乐最大下注额下注,并把下注挂到活动名下。
*/
public function test_ai_bets_all_spendable_gold_when_loss_cover_event_is_active(): void
public function test_ai_bets_baccarat_max_bet_when_loss_cover_time_window_is_active(): void
{
Event::fake();
Queue::fake([SaveMessageJob::class]);
@@ -87,7 +87,7 @@ class AiBaccaratBetJobTest extends TestCase
]);
$event = BaccaratLossCoverEvent::factory()->create([
'status' => 'active',
'status' => 'scheduled',
'starts_at' => now()->subMinutes(2),
'ends_at' => now()->addMinutes(10),
]);
@@ -114,14 +114,14 @@ class AiBaccaratBetJobTest extends TestCase
'user_id' => $aiUser->id,
'loss_cover_event_id' => $event->id,
'bet_type' => 'big',
'amount' => 1200000,
'amount' => 50000,
'status' => 'pending',
]);
$this->assertDatabaseHas('baccarat_loss_cover_records', [
'event_id' => $event->id,
'user_id' => $aiUser->id,
'total_bet_amount' => 1200000,
'total_bet_amount' => 50000,
'claim_status' => 'not_eligible',
]);
@@ -132,8 +132,8 @@ class AiBaccaratBetJobTest extends TestCase
$this->assertDatabaseHas('users', [
'id' => $aiUser->id,
'jjb' => 0,
'bank_jjb' => 0,
'jjb' => 950000,
'bank_jjb' => 200000,
]);
}
}

View File

@@ -3,8 +3,8 @@
/**
* 文件功能AI小班长资金调度服务测试
*
* 覆盖 AI小班长的常规存款、全仓取款与阶段性目标公告逻辑,
* 防止后续调整后再次出现“超过 100 万未存款”或全仓提取异常。
* 覆盖 AI小班长的常规存款、大额调款与阶段性目标公告逻辑,
* 防止后续调整后再次出现“超过 100 万未存款”或银行调款异常。
*/
namespace Tests\Feature;
@@ -19,7 +19,7 @@ use Illuminate\Support\Facades\Queue;
use Tests\TestCase;
/**
* 验证 AI小班长的常规存款与全仓调仓规则。
* 验证 AI小班长的常规存款与大额调仓规则。
*/
class AiFinanceServiceTest extends TestCase
{
@@ -50,7 +50,7 @@ class AiFinanceServiceTest extends TestCase
}
/**
* 全仓支出场景允许从银行提取差额,把总资产集中到手上。
* 大额支出场景允许从银行提取差额,把目标下注额调到手上。
*/
public function test_prepare_all_in_spend_withdraws_needed_gold_from_bank(): void
{