diff --git a/app/Http/Controllers/HorseRaceController.php b/app/Http/Controllers/HorseRaceController.php index c11d3d7..a6f18ea 100644 --- a/app/Http/Controllers/HorseRaceController.php +++ b/app/Http/Controllers/HorseRaceController.php @@ -51,6 +51,7 @@ class HorseRaceController extends Controller // 计算各马匹当前注额 $config = GameConfig::forGame('horse_racing')?->params ?? []; $houseTake = (int) ($config['house_take_percent'] ?? 5); + $seedPool = (int) ($config['seed_pool'] ?? 0); $horsePools = HorseBet::query() ->where('race_id', $race->id) @@ -59,13 +60,13 @@ class HorseRaceController extends Controller ->pluck('pool', 'horse_id') ->toArray(); + $oddsMap = HorseRace::calcOdds($horsePools, $houseTake, $seedPool); + // 计算实时赔率 $horses = $race->horses ?? []; - $horsesWithBets = array_map(function ($horse) use ($horsePools, $houseTake) { + $horsesWithBets = array_map(function ($horse) use ($horsePools, $oddsMap) { $horsePool = (int) ($horsePools[$horse['id']] ?? 0); - $totalPool = array_sum(array_values($horsePools)); - $netPool = $totalPool * (1 - $houseTake / 100); - $odds = $horsePool > 0 ? round($netPool / $horsePool, 2) : null; + $odds = $horsePool > 0 ? ($oddsMap[$horse['id']] ?? null) : null; return [ 'id' => $horse['id'], diff --git a/app/Jobs/CloseHorseRaceJob.php b/app/Jobs/CloseHorseRaceJob.php index 4aed36b..e4365ee 100644 --- a/app/Jobs/CloseHorseRaceJob.php +++ b/app/Jobs/CloseHorseRaceJob.php @@ -70,6 +70,7 @@ class CloseHorseRaceJob implements ShouldQueue $config = GameConfig::forGame('horse_racing')?->params ?? []; $houseTake = (int) ($config['house_take_percent'] ?? 5); + $seedPool = (int) ($config['seed_pool'] ?? 0); $winnerId = (int) $race->winner_horse_id; // 按马匹统计各匹下注金额 @@ -82,7 +83,7 @@ class CloseHorseRaceJob implements ShouldQueue $totalPool = array_sum($horsePools); $winnerPool = (int) ($horsePools[$winnerId] ?? 0); - $netPool = (int) ($totalPool * (1 - $houseTake / 100)); + $distributablePool = HorseRace::calcDistributablePool($horsePools, $houseTake, $seedPool, $winnerPool); // 结算:遍历所有下注记录 $bets = HorseBet::query() @@ -93,7 +94,7 @@ class CloseHorseRaceJob implements ShouldQueue $totalPayout = 0; - DB::transaction(function () use ($bets, $winnerId, $netPool, $winnerPool, $currency, &$totalPayout) { + DB::transaction(function () use ($bets, $winnerId, $distributablePool, $winnerPool, $currency, &$totalPayout) { foreach ($bets as $bet) { if ((int) $bet->horse_id !== $winnerId) { // 未中奖(本金已在下注时扣除) @@ -104,7 +105,7 @@ class CloseHorseRaceJob implements ShouldQueue // 中奖:按注额比例分配净注池 if ($winnerPool > 0) { - $payout = (int) round($netPool * ($bet->amount / $winnerPool)); + $payout = (int) round($distributablePool * ($bet->amount / $winnerPool)); } else { $payout = 0; } diff --git a/app/Models/HorseRace.php b/app/Models/HorseRace.php index 42c6079..d22aba4 100644 --- a/app/Models/HorseRace.php +++ b/app/Models/HorseRace.php @@ -114,33 +114,43 @@ class HorseRace extends Model } /** - * 根据注池计算各马匹实时赔率(彩池制,扣除庄家抽水后按比例分配)。 + * 计算本场可派奖总池。 * - * @param int $horseBetAmounts 各马匹的注额数组 [horse_id => amount] - * @param int $housePercent 庄家抽水百分比 + * 可派奖池 = 系统初始化资金池 + 玩家总下注 - 抽水, + * 且至少不低于中奖马匹总下注,避免出现“押中反亏”的体验。 + * + * @param array $horseBetAmounts + */ + public static function calcDistributablePool(array $horseBetAmounts, int $housePercent, int $seedPool = 0, int $winnerPool = 0): float + { + $totalPool = array_sum($horseBetAmounts); + $netPlayerPool = $totalPool * (1 - $housePercent / 100); + + return max($netPlayerPool + max(0, $seedPool), $winnerPool); + } + + /** + * 根据注池计算各马匹实时赔率(含系统初始化资金池)。 + * + * @param array $horseBetAmounts 各马匹的注额数组 [horse_id => amount] * @return array horse_id => 赔率(含本金) */ - public static function calcOdds(array $horseBetAmounts, int $housePercent): array + public static function calcOdds(array $horseBetAmounts, int $housePercent, int $seedPool = 0): array { $totalPool = array_sum($horseBetAmounts); if ($totalPool <= 0) { - // 尚无下注,返回等额赔率 - $count = count($horseBetAmounts); - return array_map(fn () => 1.0, $horseBetAmounts); } - $netPool = $totalPool * (1 - $housePercent / 100); + $distributablePool = static::calcDistributablePool($horseBetAmounts, $housePercent, $seedPool); $odds = []; foreach ($horseBetAmounts as $horseId => $amount) { if ($amount <= 0) { - // 无人押注的马,赔率设为理论最大值 - $odds[$horseId] = round($netPool, 2); + $odds[$horseId] = round($distributablePool, 2); } else { - // 赔率 = 净注池 / 该马注额(含本金返还) - $odds[$horseId] = round($netPool / $amount, 2); + $odds[$horseId] = round($distributablePool / $amount, 2); } } diff --git a/database/seeders/GameConfigSeeder.php b/database/seeders/GameConfigSeeder.php index 8008103..e368428 100644 --- a/database/seeders/GameConfigSeeder.php +++ b/database/seeders/GameConfigSeeder.php @@ -97,6 +97,7 @@ class GameConfigSeeder extends Seeder 'horse_count' => 4, // 参赛马匹数量 'min_bet' => 100, // 最低押注 'max_bet' => 100000, // 最高押注 + 'seed_pool' => 10000, // 系统初始化资金池 'house_take_percent' => 5, // 庄家抽水(%) ], ], diff --git a/resources/views/admin/game-configs/index.blade.php b/resources/views/admin/game-configs/index.blade.php index 73e273a..40bdd86 100644 --- a/resources/views/admin/game-configs/index.blade.php +++ b/resources/views/admin/game-configs/index.blade.php @@ -93,10 +93,12 @@ @php $params = $game->params ?? []; $labels = gameParamLabels($game->game_key); + $paramKeys = array_values(array_unique(array_merge(array_keys($labels), array_keys($params)))); @endphp
- @foreach ($params as $paramKey => $paramValue) + @foreach ($paramKeys as $paramKey) + @php $paramValue = $params[$paramKey] ?? ($labels[$paramKey]['default'] ?? '') @endphp @php $meta = $labels[$paramKey] ?? ['label' => $paramKey, 'type' => 'number', 'unit' => ''] @endphp