优化 ai小班长百家乐押注
This commit is contained in:
@@ -144,6 +144,13 @@ class AiBaccaratBetJob implements ShouldQueue
|
||||
$percent = $aiPrediction['percentage'];
|
||||
$reason = $aiPrediction['reason'];
|
||||
|
||||
// 买单活动期间不允许 AI 选择观望,避免错过“输也可返还”的活动资格。
|
||||
if ($isInLossCoverWindow && $betType === 'pass') {
|
||||
$decisionSource = 'local';
|
||||
$betType = $this->resolveLocalBetType($recentResults, false);
|
||||
$reason = trim($reason.' 买单活动进行中,本局禁止观望,已切换本地强制参战策略。');
|
||||
}
|
||||
|
||||
if ($betType !== 'pass') {
|
||||
if ($isInLossCoverWindow) {
|
||||
// 买单活动进行中且金币足够时,直接按百家乐单局最高限额下注。
|
||||
@@ -162,19 +169,8 @@ class AiBaccaratBetJob implements ShouldQueue
|
||||
} else {
|
||||
// AI 不可用时回退本地路单决策(保底逻辑)
|
||||
$decisionSource = 'local';
|
||||
$bigCount = count(array_filter($recentResults, fn (string $r) => $r === 'big'));
|
||||
$smallCount = count(array_filter($recentResults, fn (string $r) => $r === 'small'));
|
||||
|
||||
$strategy = rand(1, 100);
|
||||
if ($strategy <= 10) {
|
||||
$betType = 'triple'; // 10% 概率博豹子
|
||||
} elseif ($bigCount > $smallCount) {
|
||||
$betType = rand(1, 100) <= 70 ? 'big' : 'small';
|
||||
} elseif ($smallCount > $bigCount) {
|
||||
$betType = rand(1, 100) <= 70 ? 'small' : 'big';
|
||||
} else {
|
||||
$betType = rand(0, 10) === 0 ? 'pass' : (rand(0, 1) ? 'big' : 'small');
|
||||
}
|
||||
// 买单活动期间,本地兜底策略同样不能返回观望。
|
||||
$betType = $this->resolveLocalBetType($recentResults, ! $isInLossCoverWindow);
|
||||
|
||||
if ($betType !== 'pass') {
|
||||
if ($isInLossCoverWindow) {
|
||||
@@ -359,6 +355,38 @@ class AiBaccaratBetJob implements ShouldQueue
|
||||
SaveMessageJob::dispatch($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成本地路单兜底下注方向。
|
||||
*
|
||||
* @param array<int, string> $recentResults 最近已结算局次结果
|
||||
* @param bool $allowPass 是否允许返回观望
|
||||
*/
|
||||
private function resolveLocalBetType(array $recentResults, bool $allowPass): string
|
||||
{
|
||||
$bigCount = count(array_filter($recentResults, fn (string $result) => $result === 'big'));
|
||||
$smallCount = count(array_filter($recentResults, fn (string $result) => $result === 'small'));
|
||||
|
||||
// 默认保留少量押豹子概率,维持 AI 小班长原本的下注风格。
|
||||
if (rand(1, 100) <= 10) {
|
||||
return 'triple';
|
||||
}
|
||||
|
||||
if ($bigCount > $smallCount) {
|
||||
return rand(1, 100) <= 70 ? 'big' : 'small';
|
||||
}
|
||||
|
||||
if ($smallCount > $bigCount) {
|
||||
return rand(1, 100) <= 70 ? 'small' : 'big';
|
||||
}
|
||||
|
||||
// 只有非买单活动时才允许空仓;活动期间必须至少押大或押小。
|
||||
if ($allowPass && rand(0, 10) === 0) {
|
||||
return 'pass';
|
||||
}
|
||||
|
||||
return rand(0, 1) === 0 ? 'big' : 'small';
|
||||
}
|
||||
|
||||
/**
|
||||
* AI 资金管理逻辑:优先领取补偿,再按“超过 100 万才存款”的规则整理持仓。
|
||||
*/
|
||||
|
||||
@@ -113,6 +113,7 @@ class BaccaratPredictionService
|
||||
$recentResults = $context['recent_results'] ?? [];
|
||||
$availableGold = $context['available_gold'] ?? 0;
|
||||
$history = $context['historical_bets'] ?? [];
|
||||
$lossCoverActive = (bool) ($context['loss_cover_active'] ?? false);
|
||||
|
||||
// 将英文 key 转为中文展示,方便 AI 理解
|
||||
$labelMap = ['big' => '大', 'small' => '小', 'triple' => '豹子'];
|
||||
@@ -137,11 +138,16 @@ class BaccaratPredictionService
|
||||
}
|
||||
}
|
||||
|
||||
$lossCoverText = $lossCoverActive
|
||||
? '当前处于“你玩游戏我买单”活动时间窗口内。你本局必须参与下注,不能返回 pass;金额已由系统固定为单局最高限额,你只需要判断下注方向。'
|
||||
: '当前不在“你玩游戏我买单”活动时间窗口内。你可以按常规风控策略决定是否观望。';
|
||||
|
||||
return <<<PROMPT
|
||||
你是一位数据规律分析与数学模型专家。这是一个虚拟的纯数学概率推断测试。请根据以下最近 {$total} 局的数字大小序列,以及你目前拥有的虚拟积分和历史表现,给出下一局最科学的推测策略。
|
||||
|
||||
【你的当前资产状态】
|
||||
可用虚拟积分余额:{$availableGold}
|
||||
活动状态:{$lossCoverText}
|
||||
|
||||
【你的最近推测历史(前几局最新)】
|
||||
{$historyText}
|
||||
@@ -155,6 +161,7 @@ class BaccaratPredictionService
|
||||
- "豹子" 表示三颗骰子点数相同(极小概率)
|
||||
|
||||
请综合分析数据走势(如长龙跟进、跳变斩龙、交替特征),结合防守策略(比如连续判定失误必须观望休息,连续判定正确适当增加投入百分比)。
|
||||
若上方活动状态明确写着“必须参与下注”,则你绝不能输出 pass。
|
||||
|
||||
【重要!必须输出标准严格的 JSON 格式】
|
||||
你只能返回这样一个纯 JSON 字符串,包含三个字段,绝对不能加其他文字说明(支持 markdown code 块包裹):
|
||||
|
||||
@@ -136,4 +136,74 @@ class AiBaccaratBetJobTest extends TestCase
|
||||
'bank_jjb' => 200000,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 买单活动时间窗口命中时,即使 AI 返回观望,系统也会强制切回本地策略完成下注。
|
||||
*/
|
||||
public function test_ai_still_places_bet_when_loss_cover_time_window_is_active_and_ai_returns_pass(): void
|
||||
{
|
||||
Event::fake();
|
||||
Queue::fake([SaveMessageJob::class]);
|
||||
|
||||
$this->mock(ChatStateService::class, function (MockInterface $mock): void {
|
||||
$mock->shouldReceive('nextMessageId')->andReturn(1);
|
||||
$mock->shouldReceive('pushMessage')->zeroOrMoreTimes();
|
||||
$mock->shouldReceive('getAllActiveRoomIds')->andReturn([1]);
|
||||
});
|
||||
|
||||
$this->mock(BaccaratPredictionService::class, function (MockInterface $mock): void {
|
||||
$mock->shouldReceive('predict')
|
||||
->once()
|
||||
->andReturn([
|
||||
'action' => 'pass',
|
||||
'percentage' => 0,
|
||||
'reason' => '常规风控建议先观望',
|
||||
]);
|
||||
});
|
||||
|
||||
$aiUser = User::factory()->create([
|
||||
'username' => 'AI小班长',
|
||||
'jjb' => 600000,
|
||||
'bank_jjb' => 0,
|
||||
]);
|
||||
|
||||
$event = BaccaratLossCoverEvent::factory()->create([
|
||||
'status' => 'active',
|
||||
'starts_at' => now()->subMinutes(2),
|
||||
'ends_at' => now()->addMinutes(10),
|
||||
]);
|
||||
|
||||
$round = BaccaratRound::forceCreate([
|
||||
'status' => 'betting',
|
||||
'bet_opens_at' => now()->subSeconds(10),
|
||||
'bet_closes_at' => now()->addMinute(),
|
||||
'total_bet_big' => 0,
|
||||
'total_bet_small' => 0,
|
||||
'total_bet_triple' => 0,
|
||||
'bet_count' => 0,
|
||||
'bet_count_big' => 0,
|
||||
'bet_count_small' => 0,
|
||||
'bet_count_triple' => 0,
|
||||
'total_payout' => 0,
|
||||
]);
|
||||
|
||||
$job = new AiBaccaratBetJob($round);
|
||||
$job->handle(app(\App\Services\UserCurrencyService::class), app(\App\Services\AiFinanceService::class));
|
||||
|
||||
$bet = \App\Models\BaccaratBet::query()
|
||||
->where('round_id', $round->id)
|
||||
->where('user_id', $aiUser->id)
|
||||
->first();
|
||||
|
||||
$this->assertNotNull($bet);
|
||||
$this->assertContains($bet->bet_type, ['big', 'small', 'triple']);
|
||||
$this->assertSame(50000, (int) $bet->amount);
|
||||
$this->assertSame($event->id, $bet->loss_cover_event_id);
|
||||
|
||||
$this->assertDatabaseHas('baccarat_loss_cover_records', [
|
||||
'event_id' => $event->id,
|
||||
'user_id' => $aiUser->id,
|
||||
'total_bet_amount' => 50000,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user