石头剪刀布(Rock–Paper–Scissors, RPS)
- 类别:回合制匹配游戏原型
- 目标:验证匹配、房间生命周期、锁步回合、服务器权威判定与日志存档的全流程。
- 原型代号:
proto-002-rps - 依赖模块:
proto-001-echo-chatroom - 推荐语言栈:Go / Node.js / Rust
- 网络协议:WebSocket(双向实时)
一、概述(Overview)
“石头剪刀布”是所有 匹配制游戏 的起点。
它既具备简单的规则确定性(三种动作、明确胜负),
又包含了最基础的网络交互闭环:
匹配 → 准备 → 提交 → 判定 → 结算 → 存档
它验证了以下关键能力:
- 匹配队列机制:支持多玩家排队等待配对;
- 状态锁步(Turn-based Lockstep):同时提交指令,统一结算;
- 服务器权威判定:防作弊与重放;
- 断线重连 与 对局恢复;
- 日志系统:完整记录对局过程。
这使得 RPS 成为整个“联机验证体系”的第二块基石。
二、核心玩法与系统目标(Gameplay & Objectives)
2.1 玩法简述
- 玩家点击“开始匹配”;
- 匹配系统将两个玩家配成一组;
- 双方进入对战房间,倒计时开始;
- 双方在 5 秒内选择动作(石头、剪刀、布);
- 超时未提交则默认弃权;
- 服务端判定胜负,广播结果;
- 支持多局模式(BO3)。
2.2 系统目标与验证点
| 类别 | 功能目标 | 验证重点 |
|---|---|---|
| 匹配系统 | 随机或 Elo 匹配两名玩家 | 队列调度、并发锁 |
| 回合系统 | 同步状态更新 | 状态机控制、定时器 |
| 权威判定 | 服务器结算胜负 | 防作弊、防重放 |
| 存档系统 | 保存战局日志 | 可重放性验证 |
| 断线恢复 | 重新连接后恢复状态 | Snapshot 恢复机制 |
| 观战系统 | 第三方只读通道 | 延迟广播与隔离 |
| 扩展验证 | 积分 / Elo 排名 | MatchHistory + Leaderboard |
三、系统架构设计(Architecture)
3.1 模块图
graph TD
A["Client"] --> B["Gateway Server"]
B --> C["Matchmaker"]
B --> D["Room Service"]
D --> E["Game Logic Engine"]
E --> F["Event Logger"]
E --> G["Ranking Service"]
说明:
| 模块 | 功能说明 |
|---|---|
| Gateway Server | 用户接入、身份验证、连接管理 |
| Matchmaker | 匹配系统(队列、Elo 算法) |
| Room Service | 创建房间、维护状态机 |
| Game Logic Engine | 回合判定逻辑与状态更新 |
| Event Logger | 对局日志与重放存储 |
| Ranking Service | Elo 积分与排行榜计算 |
3.2 系统分层
接入层(Gateway)
- 负责连接与路由
- 校验 token、绑定用户 ID
逻辑层(Game Engine)
- 处理回合状态
- 调用定时器触发结算
数据层(Storage)
- Redis(匹配队列与房间状态)
- PostgreSQL(对局日志、Elo 分数)
监控层(Metrics)
- Prometheus 指标采集
- Grafana 可视化
3.3 组件交互流程
sequenceDiagram
Client->>Gateway: request_match()
Gateway->>Matchmaker: enqueue(player)
Matchmaker->>RoomService: create_room(p1,p2)
RoomService->>Clients: notify_room_ready
Clients->>GameLogic: submit_action(rock/paper/scissors)
GameLogic->>Logger: record_event
GameLogic->>Clients: result(win/lose/draw)
四、功能模块详解(Functional Modules)
4.1 Matchmaker(匹配系统)
4.1.1 功能描述
匹配系统的任务是:
根据玩家的进入顺序或 Elo 分数,将两名玩家配成一场游戏。
4.1.2 队列机制
基于 Redis SortedSet(score 为 Elo);
支持:
enqueue(player_id, score)dequeue(pair of players)
匹配策略:
- 优先相近 Elo;
- 若等待时间 > T 秒,则扩大匹配窗口。
4.1.3 关键参数
| 参数 | 默认值 | 含义 |
|---|---|---|
MATCH_TICK | 100ms | 匹配轮询间隔 |
MATCH_WINDOW | 100 Elo | 初始 Elo 差距 |
EXPAND_RATE | 20 Elo/s | 匹配范围扩大速度 |
4.1.4 数据结构
type MatchRequest struct {
UserID string
Elo int
EnqueueTime time.Time
}
4.2 Room Service(房间服务)
4.2.1 职责
- 创建/销毁房间;
- 管理房间成员;
- 驱动游戏状态机。
4.2.2 状态机
stateDiagram-v2
[*] --> Idle
Idle --> Matching: enqueue
Matching --> Ready: pair found
Ready --> Playing: countdown
Playing --> Judging: all submitted or timeout
Judging --> Result: server decision
Result --> Finished: show result
Finished --> [*]
4.2.3 数据结构
type Room struct {
ID string
Players []Player
State RoomState
Round int
Actions map[string]string
Timer *time.Timer
}
4.3 Game Logic Engine(判定逻辑)
4.3.1 判定规则
| 动作 A | 动作 B | 结果 |
|---|---|---|
| Rock | Scissors | A 胜 |
| Scissors | Paper | A 胜 |
| Paper | Rock | A 胜 |
| 相同 | 相同 | 平局 |
4.3.2 防作弊机制
- 客户端提交动作时不暴露给对方;
- 每回合有唯一
RoundToken; - 服务器收到动作 → 暂存;
- 双方都提交或超时 → 判定;
- 所有操作写入日志;
- 客户端提交签名:
SHA256(player_id + round + secret)。
4.3.3 多局模式(BO3)
- 每局独立计分;
- 胜方计 1 分;
- 先获得 2 分即胜。
4.4 Event Logger(事件日志)
4.4.1 日志结构
{
"room_id": "rps-001",
"round": 1,
"actions": {
"u1": "rock",
"u2": "scissors"
},
"result": "u1_win",
"timestamp": 1730689200
}
4.4.2 存储结构
Redis:短期缓存;
PostgreSQL:长期归档;
支持回放(Replay):
- 按时间序列重放;
- 验证一致性 hash。
4.5 Ranking Service(Elo 排名)
4.5.1 算法公式
[
E_A = \frac{1}{1+10^{(R_B-R_A)/400}}
]
[
R_A’ = R_A + K(S_A - E_A)
]
4.5.2 参数
| 参数 | 默认 | 说明 |
|---|---|---|
K | 32 | 调整系数 |
R_init | 1000 | 初始 Elo |
S | 胜=1, 负=0, 平=0.5 | 比赛结果 |
4.5.3 数据结构
type EloRecord struct {
UserID string
Score int
Win int
Lose int
Draw int
}
五、状态与事件定义(State & Event Definitions)
5.1 客户端事件
| 事件 | 参数 | 描述 |
|---|---|---|
match_start | - | 匹配开始 |
match_success | {room_id} | 匹配成功 |
round_start | {countdown} | 回合开始 |
submit_action | {move: rock/paper/scissors} | 提交动作 |
round_result | {winner, actions} | 回合结算 |
match_end | {score} | 对局结束 |
六、数据模型(Data Model)
| 表 | 字段 | 说明 |
|---|---|---|
matches | id, p1, p2, result, start_at, end_at | 比赛记录 |
rounds | id, match_id, round_no, actions, winner | 每回合日志 |
elo_scores | user_id, elo, win, lose, draw | 玩家积分 |
七、验证指标(Metrics & KPI)
| 指标 | 目标 | 说明 |
|---|---|---|
| 匹配平均耗时 | < 2 秒 | 正常队列延迟 |
| 回合提交延迟 | < 100ms | Ping-Pong 校准 |
| 判定一致率 | 100% | 日志校验 |
| 断线恢复成功率 | ≥ 99% | Snapshot |
| 吞吐能力 | ≥ 1000 房间 / 节点 | 并发验证 |
八、扩展功能(Extensions)
积分排行榜(Elo Rank)
- Redis SortedSet + 周期性刷新
- 每日 Top N 公告
重连机制
- 客户端断开后 30 秒内重新连接 → 恢复房间状态
- 服务器持有
SessionSnapshot
观战系统
- 延迟 1 回合广播动作(防剧透)
- 分层广播:玩家 vs 观众
回放系统
- 重放日志 → 客户端动画化重现
- 支持加速播放与分析
九、技术选型与实现建议
| 层级 | 推荐技术 | 理由 |
|---|---|---|
| 网络层 | Go + WebSocket | 性能稳定 |
| 匹配层 | Redis SortedSet | 时间复杂度 O(logN) |
| 状态层 | FSM + TimerWheel | 精准控制回合超时 |
| 数据层 | PostgreSQL | 强一致存档 |
| 缓存层 | Redis | 快速读取 Elo 与房间状态 |
| 日志层 | Loki / ElasticSearch | 可视化检索 |
| 监控层 | Prometheus + Grafana | 实时可视化 |
十、压测与运维(Load & Ops)
| 测试项 | 内容 | 目标 |
|---|---|---|
| 匹配压力 | 10 万用户并发入队 | 平均延迟 < 2s |
| 回合同步 | 每秒 5000 回合 | 无漏包 |
| 日志写入 | 500 MB/min | IO 无阻塞 |
| 网络丢包恢复 | 30% 丢包率 | 重连成功率 >99% |
自动化监控指标:
match_queue_lengthroom_active_totalelo_update_latencydisconnect_reconnect_total
十一、设计反思与演化(Reflection & Evolution)
11.1 设计反思
- RPS 虽简单,但完整覆盖了在线对局最核心的流程闭环;
- 它的关键不是“游戏逻辑”,而是“系统可靠性”;
- 匹配、超时、判定、存档构成了所有游戏的公共骨架。
11.2 向下一阶段演化
| 目标 | 下一原型 |
|---|---|
| 网格逻辑与棋盘状态 | → #3 井字棋 |
| 回放 / 观战系统 | → #4 快速问答抢答 |
| 状态同步与 Tick 机制 | → #6 Pong |
| 房间生命周期管理 | → #10 mini-SLG |
十二、总结
“石头剪刀布” 是 服务器权威模型(Server-authoritative Model) 的最佳入门。
它让我们验证了从“客户端输入”到“服务器决策”的完整闭环:
每一条消息、每一次延迟、每一个回合状态,
都在教我们一件事——
“在分布式的不确定世界中,服务器才是唯一真相。”
相关技术栈与进一步学习
本原型验证的核心技术:匹配队列、回合锁步同步、服务器权威判定、防重放攻击
| 相关教程 | 关联内容 |
|---|---|
| 《游戏服务端编程实践》 | — |
| 《游戏服务端入门知识储备》 | — |
💡 如果你想系统性地理解游戏服务端开发的全栈知识体系,可以参考
《产品原型开发指南》目录页,
了解从「联机 Hello World」到「永续自治世界」的完整学习路线。
核心概念定义
回合锁步同步(Turn-Lockstep Sync):一种回合制游戏同步协议:所有玩家在每个回合**同时提交动作**,服务端在截止时间后统一收集、校验、判定并广播结果,确保所有客户端看到严格一致的游戏状态。
匹配队列(Matchmaking Queue):游戏服务端维护的玩家等待池,根据玩家属性(Elo 分数、地区、延迟)进行快速配对或延迟匹配,目的是在公平性与等待时间之间取得平衡。
服务器权威(Server Authority):游戏架构设计原则:所有关键判定(胜负、位置、状态变更)必须由服务器计算并仲裁,客户端仅做预测渲染,防止外挂篡改本地数据。
常见问题解答(FAQ)
以下问答帮助快速回顾本原型的核心要点,也有助于搜索引擎与大模型更好地理解内容主题。
Q1: 为什么石头剪刀布需要服务器权威?
如果不做服务器权威,客户端可篡改本地出拳结果(例如总是出克制对手的拳)。服务器收集双方动作后统一揭晓,确保公平性与防作弊的基本原则。
Q2: 匹配队列中如何防止队友匹配到彼此?
将已完成匹配的 PlayerID 加入临时黑名单,或使用会话隔离:同一匹配 ID 的多个玩家放入同一房间,不再参与其他配对。
Q3: 如果玩家超时未提交动作怎么办?
标准策略是携带默认动作(如上一回合的重复使用或随机)进行判定;同时触发放弃惩罚(如扣分或判负),并在客户端显示倒计时警告。
Q4: 回合锁步同步和帧同步有什么区别?
回合锁步是「离散时间片」模型(如每回合 10 秒做一次决策),帧同步是「连续时间片」模型(每 16ms 做状态同步)。前者适合策略/回合制,后者适合动作/格斗游戏。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。