本文档仅作设计,不修改代码。是
PHASE1_DESIGN.md的细化和补充。
现状 GameModel::json 输出的是全量状态(双方舰船的坐标/血量/朝向全都在)。联网后绝不能把全量状态下发客户端,否则就是「全图外挂」。服务端必须按玩家视角过滤。
- 己方舰船:全量下发(坐标、血量、朝向、体积)——本人永远可见。
- 敌方舰船:只下发「已揭示」的格子;未揭示格子一律以
fog呈现,不给坐标/朝向/血量。 - 敌方血量:仅当某敌舰全部格子都被揭示时才下发其当前血量(与现有 GUI 的血量圆点显示一致)。可配置为「永不显示敌方精确血量」以增强策略性。
- 行/列提示:公开(当前规则即双方合计)。
- 种子 seed:不下发(防止客户端据此反推布局);仅在「结算后回放」中由服务端提供。
{
"currentPlayer": 0, "winner": -1, "rows": 9, "cols": 9,
"rowHints": [5,5,4,5,3,4,3,0,1],
"colHints": [5,5,4,5,3,4,3,0,1],
"myShips": [
{ "index":0,"size":1,"hp":1,"dir":1,"cells":[[2,8]] },
{ "index":1,"size":2,"hp":2,"dir":2,"cells":[[2,5],[3,5]] }
],
"enemyShips": [ // 仅含“已揭示”信息
{ "size":5,"hp":5,"cells":[[1,3],[2,3],[3,3]] } // 部分揭示:cells 只给已揭示格,hp 默认省略
],
"view": [ // 每格:fog / water / own / enemy
["fog","water","own","enemy", ...],
...
]
}- 以
GameModel的isRevealed(P, r, c)和ship(i).owner == P为依据逐格/逐船过滤。 - 建议新增纯函数:
QJsonObject buildFilteredState(int player) const(或独立于GameModel的StateFilter工具类),供服务端调用;json命令保留为「调试用全量输出」,不进入网络协议。
采用标准 Elo,胜负二值(无平局),投降按负处理。
期望胜率 E_a = 1 / (1 + 10^((R_b - R_a) / 400))
新分数 R_a' = R_a + K * (S_a - E_a)
其中 S_a = 1(胜)、0(负)
| 参数 | 值 | 说明 |
|---|---|---|
| 初始分 R₀ | 1200 | 新玩家 |
| K 值 | 32(前 20 局)→ 16(之后) | 新号收敛快,老号波动小 |
| 投降 | S=0 | 投降方判负 |
| 场景 | A 分 | B 分 | 结果 | 变化 |
|---|---|---|---|---|
| 均分对战 | 1200 | 1200 | A 胜 | A→1216,B→1184 |
| 高打低 | 1400 | 1000 | A 胜 | A→1403,B→997 |
| 低打高(爆冷) | 1000 | 1400 | A 胜 | A→1029,B→1371 |
| 段位 | 分数区间 |
|---|---|
| 青铜 | < 1100 |
| 白银 | 1100–1250 |
| 黄金 | 1250–1400 |
| 铂金 | 1400–1550 |
| 钻石 | ≥ 1550 |
目标:不改玩法,把「本地热座」流程替换为「网络会话」流程,保留本地模式用于测试/离线。
| 类 | 职责 |
|---|---|
NetClient |
WebSocket 连接、鉴权、消息收发、心跳、断线重连 |
GameSession |
客户端会话:持有服务端下发的 state、提交动作、驱动界面 |
StateSnapshot |
解码 §1.2 的过滤状态为可渲染结构(或直接复用 JSON) |
当前 BoardWidget 直接查询 GameModel。改造方案二选一:
- 方案 A(推荐):
BoardWidget改为渲染StateSnapshot(从服务端 state 解码),彻底与GameModel解耦;本地热座模式也统一走StateSnapshot(由本地GameModel生成)。 - 方案 B(改动小):客户端保留
GameModel作为「镜像」,收到state后重放/重建镜像再渲染。缺点:镜像与权威可能漂移,需频繁全量同步。
现状:菜单 → 玩家1观察 → 玩家2观察 → 轮流行动 → 结束(热座)
改后:菜单 → 登录 → 匹配 → 对局(网络) → 结算 → 回放/再来一局
MainWindow 的阶段状态机把「观察/回合」的本地切换替换为「等待服务端 state」;动作按钮改为向服务端发 action 并等待 action_result。
- 保留 CLI 与本地热座模式(离线、测试、AI 对战)。
- 网络模式作为「房间模式」并列存在,用同一套
BoardWidget渲染。
WAITING → MATCHED → PLAYING → FINISHED
↑ │(超时/掉线)
└──────────┘
| 事件 | 处理 |
|---|---|
| 回合超时(如 60s) | 服务端自动 pass,推进回合 |
| 玩家掉线 | 保留房间(如 120s),期间可 request_state 重连 |
| 掉线超时 | 判负(ELO 按负结算),对手 opponent_left |
| 连续超时 N 次 | 判负 |
| 投降 | 立即 FINISHED,按负结算 |
- Redis 有序集合,按 ELO 排序;入队写入
score=ELO。 - 匹配窗口随等待时间放宽(如 0s±50 → 30s±200)。
- 产出
(userA, userB, seed),交房间服务创建权威GameModel。
| 改动 | 位置 | 性质 |
|---|---|---|
buildFilteredState(player) |
新增(服务端侧) | 新增纯函数 |
StateSnapshot 渲染 |
boardwidget |
改造 |
NetClient / GameSession |
新增 | 新增 |
MainWindow 流程 |
mainwindow |
改造(保留本地模式) |
json 命令 |
cli |
保留(调试用,不进网络协议) |