From 743e4dc1c8b26277f45b7f7dd26e7d2213da96da Mon Sep 17 00:00:00 2001 From: zhx Date: Thu, 18 Jun 2026 18:48:29 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A4=BC=E7=89=A9=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/operations/hooks/useWheelPage.js | 2 +- .../operations/hooks/useWheelPage.test.js | 53 ++++++++++++++++++- src/features/operations/schema.ts | 2 +- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/features/operations/hooks/useWheelPage.js b/src/features/operations/hooks/useWheelPage.js index db8309c..bf51659 100644 --- a/src/features/operations/hooks/useWheelPage.js +++ b/src/features/operations/hooks/useWheelPage.js @@ -19,7 +19,7 @@ const probabilityAffectingFields = new Set([ "rtpValueCoins", ]); export const wheelPools = [ - { key: "classic", label: "Classic", tierCount: 9 }, + { key: "classic", label: "Classic", tierCount: 8 }, { key: "luxury", label: "Luxury", tierCount: 8 }, { key: "advanced", label: "Advanced", tierCount: 12 }, ]; diff --git a/src/features/operations/hooks/useWheelPage.test.js b/src/features/operations/hooks/useWheelPage.test.js index 8102fce..be021d0 100644 --- a/src/features/operations/hooks/useWheelPage.test.js +++ b/src/features/operations/hooks/useWheelPage.test.js @@ -1,5 +1,6 @@ import { describe, expect, test } from "vitest"; -import { generateWheelTierProbabilities } from "@/features/operations/hooks/useWheelPage.js"; +import { wheelConfigFormSchema } from "@/features/operations/schema"; +import { generateWheelTierProbabilities, wheelPools } from "@/features/operations/hooks/useWheelPage.js"; function tier(overrides) { return { @@ -34,6 +35,56 @@ function expectedPayoutCoins(tiers) { } describe("wheel prize probability generation", () => { + test("uses eight prize slots for the classic wheel", () => { + const classicPool = wheelPools.find((pool) => pool.key === "classic"); + const tiers = Array.from({ length: 8 }, (_, index) => + tier({ + displayName: `奖品 ${index + 1}`, + rewardCoins: 100, + rewardId: "", + rewardType: "coin", + rtpValueCoins: 100, + tierId: `classic-${index + 1}`, + }), + ); + + expect(classicPool?.tierCount).toBe(8); + expect( + wheelConfigFormSchema.safeParse({ + drawPriceCoins: 100, + effectiveFromMs: 0, + enabled: true, + initialPoolCoins: 0, + maxSingleRTPPayout: 0, + poolRatePercent: 90, + poolReserveCoins: 0, + settlementWindowDraws: 1000, + targetRTPPercent: 90, + tiers: generateWheelTierProbabilities({ drawPriceCoins: 100, targetRTPPercent: 90, tiers }), + wheelId: "classic", + }).success, + ).toBe(true); + expect( + wheelConfigFormSchema.safeParse({ + drawPriceCoins: 100, + effectiveFromMs: 0, + enabled: true, + initialPoolCoins: 0, + maxSingleRTPPayout: 0, + poolRatePercent: 90, + poolReserveCoins: 0, + settlementWindowDraws: 1000, + targetRTPPercent: 90, + tiers: generateWheelTierProbabilities({ + drawPriceCoins: 100, + targetRTPPercent: 90, + tiers: [...tiers, tier({ rewardCoins: 100, rewardId: "", rewardType: "coin", rtpValueCoins: 100, tierId: "classic-9" })], + }), + wheelId: "classic", + }).success, + ).toBe(false); + }); + test("uses the base RTP to generate coin and gift probabilities while keeping dress and prop random", () => { const result = generateWheelTierProbabilities({ drawPriceCoins: 10000, diff --git a/src/features/operations/schema.ts b/src/features/operations/schema.ts index 8459d2f..6f5309f 100644 --- a/src/features/operations/schema.ts +++ b/src/features/operations/schema.ts @@ -4,7 +4,7 @@ const rewardTypes = ["coin", "gift", "prop", "dress"] as const; const propRewardTypes = new Set(["prop", "dress"]); const wheelTierCounts: Record = { advanced: 12, - classic: 9, + classic: 8, luxury: 8, };