= 0 ? $x : 26 + $start - $d; } /** * 豹子点数:该次摇取顺、逆落点档位不能为 T4、T5 * * @param list $tier */ private static function leopardOk(array $tier): bool { foreach (self::LEOPARD as $d) { foreach ([self::landingCw($d), self::landingCcw($d)] as $idx) { $t = $tier[$idx]; if ($t === 'T4' || $t === 'T5') { return false; } } } return true; } /** * @param array $params * @return array{tier_reward_form: string} */ public static function generate(array $params): array { $t1Cw = self::intParam($params, 't1_fixed_cw'); $t1Ccw = self::intParam($params, 't1_fixed_ccw'); $t2MinCw = self::intParam($params, 't2_min_cw'); $t2MinCcw = self::intParam($params, 't2_min_ccw'); $t4Cw = self::intParam($params, 't4_fixed_cw'); $t4Ccw = self::intParam($params, 't4_fixed_ccw'); $t5Cw = self::intParam($params, 't5_fixed_cw'); $t5Ccw = self::intParam($params, 't5_fixed_ccw'); $amt1 = self::numParam($params, 'amt_t1'); $amt2 = self::numParam($params, 'amt_t2'); $amt3 = self::numParam($params, 'amt_t3'); $amt4 = self::numParam($params, 'amt_t4'); $bestTier = null; $bestScore = INF; for ($attempt = 0; $attempt < 32; $attempt++) { $tier = self::randomInitialTier($attempt); $temp = 5.0; for ($step = 0; $step < 8000; $step++) { $score = self::score($tier, $t1Cw, $t1Ccw, $t2MinCw, $t2MinCcw, $t4Cw, $t4Ccw, $t5Cw, $t5Ccw); if ($score < $bestScore) { $bestScore = $score; $bestTier = $tier; } $i = mt_rand(0, 25); $j = mt_rand(0, 25); if ($i === $j) { continue; } $oldI = $tier[$i]; $oldJ = $tier[$j]; $tier[$i] = $oldJ; $tier[$j] = $oldI; if (!self::leopardOk($tier)) { $tier[$i] = $oldI; $tier[$j] = $oldJ; continue; } $newScore = self::score($tier, $t1Cw, $t1Ccw, $t2MinCw, $t2MinCcw, $t4Cw, $t4Ccw, $t5Cw, $t5Ccw); $delta = $newScore - $score; $u = mt_rand() / max(1, mt_getrandmax()); if ($delta < 0 || ($temp > 0.02 && exp(-$delta / $temp) > $u)) { // keep } else { $tier[$i] = $oldI; $tier[$j] = $oldJ; } $temp *= 0.999; } } if ($bestTier === null || $bestScore > 45) { throw new \RuntimeException('无法在豹子与条数约束下收敛盘面,请调整条数后重试'); } $json = self::buildJson($bestTier, $amt1, $amt2, $amt3, $amt4); return ['tier_reward_form' => $json]; } /** @return list */ private static function randomInitialTier(int $seedBias): array { mt_srand((int) (microtime(true) * 1000000) + $seedBias * 10007); $tier = []; for ($p = 0; $p < 26; $p++) { $tier[$p] = ['T1', 'T2', 'T3'][mt_rand(0, 2)]; } if (!self::leopardOk($tier)) { for ($p = 0; $p < 26; $p++) { $tier[$p] = 'T3'; } } return $tier; } /** * @param list $tier */ private static function score( array $tier, int $t1Cw, int $t1Ccw, int $t2MinCw, int $t2MinCcw, int $t4Cw, int $t4Ccw, int $t5Cw, int $t5Ccw ): float { if (!self::leopardOk($tier)) { return 1e9; } $h = self::histogram($tier); $s = 0.0; $s += ($h['cw']['T1'] - $t1Cw) ** 2; $s += ($h['ccw']['T1'] - $t1Ccw) ** 2; $s += max(0, $t2MinCw - $h['cw']['T2']) ** 2 * 8; $s += max(0, $t2MinCcw - $h['ccw']['T2']) ** 2 * 8; $s += ($h['cw']['T4'] - $t4Cw) ** 2; $s += ($h['ccw']['T4'] - $t4Ccw) ** 2; $s += ($h['cw']['T5'] - $t5Cw) ** 2; $s += ($h['ccw']['T5'] - $t5Ccw) ** 2; return $s; } /** * @param list $tier * @return array{cw: array, ccw: array} */ private static function histogram(array $tier): array { $cw = ['T1' => 0, 'T2' => 0, 'T3' => 0, 'T4' => 0, 'T5' => 0]; $ccw = ['T1' => 0, 'T2' => 0, 'T3' => 0, 'T4' => 0, 'T5' => 0]; for ($d = 5; $d <= 30; $d++) { $cw[$tier[self::landingCw($d)]]++; $ccw[$tier[self::landingCcw($d)]]++; } return ['cw' => $cw, 'ccw' => $ccw]; } /** * @param list $tier */ private static function remarkForTier(string $t, float $amt2): string { if ($t === 'T1') { return '大奖'; } if ($t === 'T2') { return $amt2 < 100 ? '完美回本' : '小赚'; } if ($t === 'T3') { return '抽水'; } if ($t === 'T4') { return '惩罚'; } if ($t === 'T5') { return '再来一次'; } return ''; } private static function buildJson(array $tier, float $amt1, float $amt2, float $amt3, float $amt4): string { $rows = []; for ($i = 0; $i < 26; $i++) { $t = $tier[$i]; if ($t === 'T5') { $ui = '再来一次'; $uiEn = 'Once again'; $ev = '0'; } else { $a = match ($t) { 'T1' => $amt1, 'T2' => $amt2, 'T3' => $amt3, 'T4' => $amt4, default => $amt3, }; $ui = self::fmtMoney($a); $uiEn = self::fmtMoney($a); $ev = self::fmtMoney($a); } $rows[] = [ 'grid_number' => strval(5 + $i), 'ui_text' => $ui, 'ui_text_en' => $uiEn, 'real_ev' => $ev, 'tier' => $t, 'remark' => self::remarkForTier($t, $amt2), ]; } return json_encode($rows, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR); } private static function fmtMoney(float $v): string { if (abs($v - round($v)) < 0.000001) { return strval((int) round($v)); } return rtrim(rtrim(sprintf('%.4f', $v), '0'), '.'); } private static function intParam(array $params, string $key): int { $v = $params[$key] ?? 0; if (is_string($v) && trim($v) === '') { return 0; } if (!is_numeric($v)) { return 0; } return intval(strval($v)); } private static function numParam(array $params, string $key): float { $v = $params[$key] ?? 0; if (is_string($v) && trim($v) === '') { return 0.0; } if (!is_numeric($v)) { return 0.0; } return floatval(strval($v)); } }