Files
36-character-flower/docs/36字花-核心玩法与前端规则摘要.md
JiaJun 6aaf90a6ac docs(game): 添加游戏模块数据
- 新增 useGameBoardVm 数据层实施说明文档
- 添加 36字花核心玩法与前端规则摘要
- 创建游戏模块数据与界面分层第一阶段实施稿
- 定义四层架构:api/dto、store、view-model hooks、ui层
- 规范 PC 与 Mobile 共享业务逻辑的改造方案
- 明确各层职责边界和组件改造顺序
2026-05-09 17:52:30 +08:00

397 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 36字花核心玩法与前端规则摘要
## 1. 项目定位
36字花是一个**单期开奖结果、单期号循环运行**的实时开奖类游戏。
前端的核心界面是:
- 36 宫格下注盘
- 倒计时与当前期状态栏
- 筹码与确认下注区
- 开奖历史与走势信息
- 公告、规则、自动托管、充值提现等外围模块
产品运行原则:
- 全平台共享同一局数据
- `PC``Mobile` 只分界面,不分玩法、不分对局
- 前端必须以服务端状态为准,不能靠本地时间自行判断开奖或封盘
---
## 2. 核心玩法
### 2.1 基本盘面
- 游戏共有 **36 个号码格子**
- 每个格子代表一个“字花编号”
- 编号范围为 **1-36**
- 当前前端盘面布局为 **6 x 6**
相关代码与约束:
- [src/features/game/shared/constants.ts](/Users/jiaunun/Desktop/36-character-flower/src/features/game/shared/constants.ts)
- `GAME_GRID_ROWS = 6`
- `GAME_GRID_COLUMNS = 6`
- `GAME_TOTAL_CELLS = 36`
### 2.2 开奖规则
- 每一期只会开出 **1 个中奖号码**
- 开奖号码属于 1-36 中的一个
- 用户只要下注号码集合中包含该号码,即视为中奖
接口口径见:
- [docs/36字花-移动端接口设计草案.md](/Users/jiaunun/Desktop/36-character-flower/docs/36字花-移动端接口设计草案.md)
- `POST /api/game/placeBet`
文档原意:
- 玩家提交的是“号码集合 + 单注金额”
- 系统按“单注金额 × 号码数量”计算本笔总扣款
- 开奖后只出一个号码
- 若该号码命中玩家所选集合,则该笔下注中奖
---
## 3. 下注模型
### 3.1 单注结构
一笔下注至少包含:
- `period_no`:下注目标期号
- `numbers`:本次下注号码集合
- `single_bet_amount`:单个号码的下注金额
说明:
- `numbers` 是一个号码集合,而不是单个号码
- 多选号码时,总扣款 = `single_bet_amount × numbers数量`
- 重复号码应去重
### 3.2 前端当前数据模型
当前前端 store 中的单笔选择数据为:
- `cellId`
- `chipId`
- `amount`
- `placedAt`
- `source`
定义见:
- [src/features/game/shared/types.ts](/Users/jiaunun/Desktop/36-character-flower/src/features/game/shared/types.ts)
- `BetSelection`
当前本地 mock 与 store 落地方式是:
- 每点击一个格子,会追加一条 `selection`
- 每条 `selection` 对应一个格子和一个筹码金额
这与接口文档中的“号码集合提交”并不完全一致。
因此当前前端可以先采用如下理解:
- UI 交互阶段:按“逐格选择”记录本地状态
- 提交到后端阶段:再把本地多个格子聚合成 `numbers`
这是后续 `confirm bet` 需要承担的转换逻辑。
---
## 4. 回合状态机
### 4.1 当前状态枚举
当前项目中定义的回合阶段为:
- `waiting`
- `betting`
- `locked`
- `revealing`
- `settled`
定义见:
- [src/features/game/shared/constants.ts](/Users/jiaunun/Desktop/36-character-flower/src/features/game/shared/constants.ts)
接口文档中的状态口径包括:
- `betting`
- `locked`
- `settling`
- `finished`
- `void`
说明:
- 当前前端内部状态和接口文档状态还未完全统一
- 第一阶段前端可继续沿用内部状态机
- 后续真实联调时,要补一层接口状态 -> 前端状态的映射
### 4.2 各阶段前端规则
#### `BETTING`
- 允许选格子
- 允许切换筹码
- 允许清除当前选择
- 允许重复上一注
- 允许确认下注
- 允许开启自动托管
#### `LOCKED`
- 已封盘
- 前端必须立即停止下注交互
- 不应等待后端返回后才禁用点击
#### `REVEALING / SETTLING`
- 等待开奖与派彩
- 展示开奖结果、跑马灯、中奖态
#### `SETTLED / FINISHED`
- 本期结束
- 准备进入下一轮
- 历史、走势、余额等应刷新
#### `VOID`
- 本期作废
- 需要退款待开奖本金
- 前端要清理本期下注态并正确提示
---
## 5. 封盘与倒计时规则
### 5.1 核心原则
- 前端必须以服务端返回的时间和阶段为准
- 到达封盘时间点时,前端应立即锁盘
- 即使网络延迟,也不能继续允许下注交互
这点在需求文档中是明确要求:
- [docs/frontend-baseline-requirements.md](/Users/jiaunun/Desktop/36-character-flower/docs/frontend-baseline-requirements.md)
### 5.2 当前前端倒计时模型
当前前端使用:
- `round.bettingClosesAt`
- `round.revealingAt`
- `round.settledAt`
并通过:
- [src/features/game/shared/selectors.ts](/Users/jiaunun/Desktop/36-character-flower/src/features/game/shared/selectors.ts)
- `getRoundCountdownMs(round)`
来计算当前倒计时毫秒数。
规则如下:
- `waiting / betting`:倒计时到 `bettingClosesAt`
- `locked / revealing`:倒计时到 `revealingAt`
- 其余:倒计时到 `settledAt`
### 5.3 Mock 数据口径
当前 mock 数据中:
- 开始后约 18 秒封盘
- 约 24 秒开奖
- 约 30 秒结算
来源:
- [src/features/game/shared/mock-data.ts](/Users/jiaunun/Desktop/36-character-flower/src/features/game/shared/mock-data.ts)
这只是前端演示节奏,不代表最终真实服务端配置。
---
## 6. 赔率、金额与筹码规则
### 6.1 当前赔率
当前 mock 中每个格子赔率固定为:
- `36`
来源:
- [src/features/game/shared/mock-data.ts](/Users/jiaunun/Desktop/36-character-flower/src/features/game/shared/mock-data.ts)
- `createGameCells()`
### 6.2 当前默认筹码
当前默认筹码面额为:
- `10`
- `25`
- `50`
- `100`
- `200`
- `500`
来源:
- [src/features/game/shared/constants.ts](/Users/jiaunun/Desktop/36-character-flower/src/features/game/shared/constants.ts)
- `DEFAULT_GAME_CHIP_AMOUNTS`
### 6.3 下注限制
从接口文档与基线需求中可得出以下前端规则:
- 单次下注号码数量不得超过 `pick_max_number_count`
- 单号码下注金额不得超过 `single_number_max_bet`
- 总下注额不得超过余额
- 封盘后不能继续下注
文档来源:
- [docs/36字花-移动端接口设计草案.md](/Users/jiaunun/Desktop/36-character-flower/docs/36字花-移动端接口设计草案.md)
- [docs/frontend-baseline-requirements.md](/Users/jiaunun/Desktop/36-character-flower/docs/frontend-baseline-requirements.md)
---
## 7. 中奖、历史与走势
### 7.1 历史记录
每期开奖后应产生一条历史记录,至少包括:
- `roundId`
- `winningCellId`
- `settledAt`
- `payoutMultiplier`
- `totalPoolAmount`
定义见:
- [src/features/game/shared/types.ts](/Users/jiaunun/Desktop/36-character-flower/src/features/game/shared/types.ts)
- `HistoryEntry`
### 7.2 走势
前端会基于历史数据派生走势信息,包括:
- `currentStreak`
- `hitCount`
- `missCount`
- `direction`
- `lastHitRoundId`
派生逻辑见:
- [src/features/game/shared/selectors.ts](/Users/jiaunun/Desktop/36-character-flower/src/features/game/shared/selectors.ts)
- `deriveTrendEntries(history)`
说明:
- 走势属于纯派生展示数据
- 不应由 UI 组件自己重复计算
---
## 8. 公告、维护与运行开关
### 8.1 运行开关
接口文档中存在:
- `runtime_enabled`
含义:
- `true`:游戏正常运行
- `false`:后台维护中,禁止下注
规则:
- 维护中不允许新下注
- 当前已开盘的一局仍可正常开奖和派彩
- 前端应禁用下注入口并提示维护状态
### 8.2 公告
公告是前端大厅的一部分,但不属于主玩法。
当前前端已存在公告模型:
- `AnnouncementState`
- `AnnouncementItem`
它们属于会话层状态,不应混入下注与回合逻辑。
---
## 9. 自动托管
接口文档中已定义自动托管能力:
- `POST /api/game/autoSpin`
入参包括:
- `action`
- `period_no`
- `numbers`
- `single_bet_amount`
- `rounds`
说明:
- 自动托管属于建立在主玩法之上的扩展能力
- 它依赖同一套选号与下注规则
- 当前前端可以先保留 UI 壳层,不需要在主玩法没走通前抢先落业务
---
## 10. 前端当前最应该优先走通的主玩法链路
基于上述规则,当前前端最核心、最应该优先走通的是:
1. 状态栏拿到当前期状态与倒计时
2. 控制栏拿到当前筹码与总下注额
3. 选号盘点击格子后写入本地下注选择
4. 总下注额、选中数量、选号高亮联动刷新
5. 后续再补确认下注请求与开奖结果回写
这也是为什么当前下一步应优先实现:
- `useGameBoardVm`
而不是优先改 `mobile` 或外围弹窗。
---
## 11. 总结
36字花这个项目的核心不是“36 张图摆出来”,而是下面这条实时对局链路:
- 同一局
- 同一倒计时
- 同一开奖结果
- 36 格可选号码
- 用户用统一筹码模型下注
- 封盘、开奖、派奖按服务端状态推进
前端实现时必须坚持两点:
1. **玩法规则统一**
- PC 和 Mobile 只能换壳,不能换规则
2. **服务端状态优先**
- 前端可以先做本地交互反馈
- 但回合状态、封盘、开奖、派彩都必须最终以服务端为准