156 lines
5.0 KiB
PHP
156 lines
5.0 KiB
PHP
<?php
|
||
|
||
/**
|
||
* 文件功能:AI小班长自动参与百家乐下注
|
||
*
|
||
* 在每局百家乐开启时延迟调度执行:
|
||
* 1. 检查是否存在连输休息惩罚(1小时)
|
||
* 2. 检查可用金币,确保留存底金
|
||
* 3. 获取近期路单进行简单决策
|
||
* 4. 提交下注
|
||
*
|
||
* @author ChatRoom Laravel
|
||
*
|
||
* @version 1.0.0
|
||
*/
|
||
|
||
namespace App\Jobs;
|
||
|
||
use App\Enums\CurrencySource;
|
||
use App\Models\BaccaratBet;
|
||
use App\Models\BaccaratRound;
|
||
use App\Models\GameConfig;
|
||
use App\Models\Sysparam;
|
||
use App\Models\User;
|
||
use App\Services\UserCurrencyService;
|
||
use Illuminate\Bus\Queueable;
|
||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||
use Illuminate\Foundation\Bus\Dispatchable;
|
||
use Illuminate\Queue\InteractsWithQueue;
|
||
use Illuminate\Queue\SerializesModels;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Redis;
|
||
|
||
class AiBaccaratBetJob implements ShouldQueue
|
||
{
|
||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||
|
||
public function __construct(
|
||
public readonly BaccaratRound $round,
|
||
) {}
|
||
|
||
public function handle(UserCurrencyService $currency): void
|
||
{
|
||
// 1. 检查总开关与游戏开关
|
||
if (Sysparam::getValue('chatbot_enabled', '0') !== '1' || ! GameConfig::isEnabled('baccarat')) {
|
||
return;
|
||
}
|
||
|
||
$round = $this->round->fresh();
|
||
if (! $round || ! $round->isBettingOpen()) {
|
||
return;
|
||
}
|
||
|
||
$user = User::where('username', 'AI小班长')->first();
|
||
if (! $user) {
|
||
return;
|
||
}
|
||
|
||
// 2. 检查连输惩罚超时
|
||
if (Redis::exists('ai_baccarat_timeout')) {
|
||
return; // 还在禁赛期
|
||
}
|
||
|
||
// 3. 检查余额与限额
|
||
$config = GameConfig::forGame('baccarat')?->params ?? [];
|
||
$minBet = (int) ($config['min_bet'] ?? 100);
|
||
$maxBet = (int) ($config['max_bet'] ?? 50000);
|
||
|
||
// 至少保留 2000 金币底仓
|
||
$availableGold = ($user->jjb ?? 0) - 2000;
|
||
if ($availableGold < $minBet) {
|
||
return; // 资金不足以支撑最小下注
|
||
}
|
||
|
||
// 下注金额:可用余额的 2% ~ 5%,并在 min_bet 和 max_bet 之间
|
||
$percent = rand(2, 5) / 100.0;
|
||
$amount = (int) round($availableGold * $percent);
|
||
$amount = max($minBet, min($amount, $maxBet));
|
||
|
||
// 如果依然大于实际 jjb (保险兜底),则放弃
|
||
if ($amount > $user->jjb) {
|
||
return;
|
||
}
|
||
|
||
// 4. 决策逻辑:简单分析近期路单
|
||
// 取最近 10 局
|
||
$recentResults = BaccaratRound::query()
|
||
->where('status', 'settled')
|
||
->orderByDesc('id')
|
||
->limit(10)
|
||
->pluck('result')
|
||
->toArray();
|
||
|
||
$bigCount = count(array_filter($recentResults, fn ($r) => $r === 'big'));
|
||
$smallCount = count(array_filter($recentResults, fn ($r) => $r === 'small'));
|
||
|
||
// 基础策略:追逐热点 (跟大部队) 或 均值回归 (逆势)
|
||
// 这里做一个简单的随机倾向:
|
||
$strategy = rand(1, 100);
|
||
if ($strategy <= 10) {
|
||
$betType = 'triple'; // 10% 概率博豹子
|
||
} elseif ($bigCount > $smallCount) {
|
||
// 大偏热,70%概率顺势买大,30%逆势买小
|
||
$betType = rand(1, 100) <= 70 ? 'big' : 'small';
|
||
} elseif ($smallCount > $bigCount) {
|
||
$betType = rand(1, 100) <= 70 ? 'small' : 'big';
|
||
} else {
|
||
$betType = rand(0, 1) ? 'big' : 'small';
|
||
}
|
||
|
||
// 5. 执行下注 (同 BaccaratController::bet 逻辑)
|
||
DB::transaction(function () use ($user, $round, $betType, $amount, $currency) {
|
||
// 幂等:同一局只能下一注
|
||
$existing = BaccaratBet::query()
|
||
->where('round_id', $round->id)
|
||
->where('user_id', $user->id)
|
||
->lockForUpdate()
|
||
->exists();
|
||
|
||
if ($existing) {
|
||
return;
|
||
}
|
||
|
||
// 扣除金币
|
||
$currency->change(
|
||
$user,
|
||
'gold',
|
||
-$amount,
|
||
CurrencySource::BACCARAT_BET,
|
||
"AI小班长百家乐 #{$round->id} 押 ".match ($betType) {
|
||
'big' => '大', 'small' => '小', default => '豹子'
|
||
},
|
||
);
|
||
|
||
// 写入下注记录
|
||
BaccaratBet::create([
|
||
'round_id' => $round->id,
|
||
'user_id' => $user->id,
|
||
'bet_type' => $betType,
|
||
'amount' => $amount,
|
||
'status' => 'pending',
|
||
]);
|
||
|
||
// 更新局次汇总统计
|
||
$field = 'total_bet_'.$betType;
|
||
$countField = 'bet_count_'.$betType;
|
||
$round->increment($field, $amount);
|
||
$round->increment($countField);
|
||
$round->increment('bet_count');
|
||
|
||
// 广播各选项的最新押注人数(让前台看到 AI 下注的人数增长)
|
||
event(new \App\Events\BaccaratPoolUpdated($round));
|
||
});
|
||
}
|
||
}
|