在线联机原型全集:第 3 章 井字棋 / 四子棋(Tic-Tac-Toe / Connect Four)
类别:1v1 棋盘落子制游戏原型 目标:验证服务器权威的空间状态管理、对局日志回放、观战通道与断线恢复。 原型代号:
proto-003-board依赖模块:proto-001-echo-chatroom,proto-002-rps推荐语言栈:Go / Rust / TypeScript(Node) 网络协议:WebSocket + JSON 消息流
一、概述(Overview)
“井字棋(Tic-Tac-Toe)” 与 “四子棋(Connect Four)” 是两种典型的网格棋类原型: 规则简单、状态有限、动作离散。 但它们的实现意义在于:
它们第一次让「游戏服务器」不仅处理消息或回合,而是维护一个可验证的状态空间(State Space)。
这意味着我们开始验证:
- 空间状态的同步;
- 合法性裁定;
- 状态回放;
- 观战与断线重连;
- 数据持久化与重演一致性。
本章是后续所有棋类、战棋乃至地图游戏的核心基石。
二、核心玩法与系统目标(Gameplay & Objectives)
2.1 游戏规则简介
Tic-Tac-Toe
- 3×3 棋盘;
- 两名玩家交替落子;
- 连成一条线(横 / 竖 / 斜)者获胜;
- 棋盘填满无人胜出则平局。
Connect Four
- 7×6 网格;
- 棋子从上落下;
- 任意方向连成 4 个相同颜色即胜;
- 平局条件同上。
2.2 功能目标
| 类别 | 功能目标 | 验证重点 |
|---|---|---|
| 棋盘系统 | 可变网格状态 | 状态存储与序列化 |
| 回合系统 | 玩家轮流操作 | 回合锁步机制 |
| 判定逻辑 | 胜负判断 | 服务器权威计算 |
| 日志系统 | 对局存档 | 可重放性验证 |
| 观战系统 | 只读通道 | 延迟广播 |
| 断线恢复 | Snapshot 机制 | 快照+重连 |
| 合法性 | 防作弊与越界 | 服务端裁定 |
| 回放验证 | 哈希一致性 | Deterministic Replay |
三、系统架构设计(Architecture)
graph TD
A[Client] --> B[Gateway]
B --> C[RoomManager]
C --> D[BoardEngine]
D --> E[Validator]
D --> F[ReplayLogger]
C --> G[SpectatorService]
模块说明
| 模块 | 职责 |
|---|---|
| Gateway | 用户连接、身份验证、心跳管理 |
| RoomManager | 房间创建 / 加入 / 状态机管理 |
| BoardEngine | 棋盘逻辑计算与状态更新 |
| Validator | 合法性判断与越界检测 |
| ReplayLogger | 对局事件日志存储与回放 |
| SpectatorService | 观战订阅、延迟广播 |
| Storage | Redis + PostgreSQL(快照 + 日志) |
四、功能模块详解(Functional Modules)
4.1 RoomManager(房间管理)
结构定义
type Room struct {
ID string
Players []Player
Board *Board
Turn int
State RoomState
ReplayLog []Event
}
状态机
stateDiagram-v2
[*] --> Waiting
Waiting --> Playing: 两人准备
Playing --> Checking: 行动完成
Checking --> End: 胜/平判定
End --> [*]
功能
- 房间创建、销毁;
- 轮转玩家回合;
- 调用
BoardEngine执行落子; - 控制定时器超时与托管。
4.2 BoardEngine(棋盘引擎)
职责
维护棋盘状态(二维数组)并执行合法性验证。
type Board struct {
Width int
Height int
Grid [][]Cell
}
type Cell struct {
Owner string // X, O, or empty
}
操作接口
| 方法 | 描述 |
|---|---|
Place(x, y, player) |
尝试落子 |
CheckWin() |
判断胜负 |
IsFull() |
棋盘是否填满 |
Snapshot() |
序列化快照 |
合法性校验
- 落点未被占用;
- 坐标在范围内;
- 轮到该玩家行动;
- 禁止多次提交。
4.3 Validator(合法性判定)
提供防作弊机制:
-
所有动作在服务端重算;
-
客户端只负责输入坐标;
-
提交动作附带签名;
-
使用哈希校验状态一致性:
state_hash = sha256(board_snapshot + last_move)
4.4 ReplayLogger(对局日志)
数据结构
{
"room_id": "ttt-001",
"round": 5,
"actions": [
{"player": "A", "pos": [0,0]},
{"player": "B", "pos": [1,1]}
],
"board": [
["A","B",""],
["","A","B"],
["","","A"]
],
"winner": "A"
}
功能
-
每步落子写入 Redis Stream;
-
每局结束后持久化 PostgreSQL;
-
提供回放 API:
/replay/{room_id};- 按时间序列推送事件。
4.5 SpectatorService(观战系统)
- 支持观众加入房间;
- 只读、延迟 1 步广播;
- 防止作弊透视;
- 支持观战聊天频道;
- 可设置最大观战数。
4.6 Snapshot / Recovery(断线恢复)
- 每步落子后生成
snapshot_hash; - 存入 Redis(TTL 5min);
- 客户端断线重连 → 请求
/resume(room_id); - 服务器返回快照并重新加入房间。
五、状态机与事件流(State Machine & Flow)
sequenceDiagram
ClientA->>Gateway: join_room
ClientB->>Gateway: join_room
Gateway->>RoomManager: start_match
RoomManager->>BoardEngine: init_board
ClientA->>BoardEngine: place(0,0)
BoardEngine->>Validator: validate
Validator->>RoomManager: update_state
RoomManager->>ReplayLogger: log(move)
RoomManager->>Clients: broadcast(state)
六、数据模型(Data Schema)
| 表 | 字段 | 说明 |
|---|---|---|
boards |
id, width, height, state_json | 当前棋盘快照 |
moves |
id, board_id, round, x, y, player | 落子记录 |
matches |
id, p1, p2, result, created_at | 对局总表 |
spectators |
id, room_id, user_id | 观战记录 |
七、验证指标(Metrics & KPI)
| 指标 | 目标值 | 说明 |
|---|---|---|
| 操作延迟 | < 100ms | 单步落子响应 |
| 合法性错误率 | 0% | 服务端防作弊 |
| 断线恢复成功率 | ≥99% | Snapshot |
| 回放一致性哈希 | 100% 一致 | Log 验证 |
| 观战延迟 | ≤500ms | 延迟广播 |
八、扩展功能(Extensions)
-
排行榜
- 基于 Elo 算法;
- 每局胜者 +K,败者 -K。
-
悔棋系统
- 双方同意方可撤销;
- 服务端验证动作序列。
-
断线托管
- AI 代行落子;
- 确保游戏不中断。
-
棋盘回放编辑
- 导出
.jsonlog文件; - 支持“逐步播放”、“回合分析”。
- 导出
-
自定义规则
-
可通过 DSL 定义棋盘大小与胜利条件:
{"grid": [10,10], "winCondition": 5}
-
九、技术选型与实现建议
| 模块 | 技术栈 | 理由 |
|---|---|---|
| BoardEngine | Go + Struct FSM | 高性能计算 |
| Validator | Go + SHA256 | 一致性校验 |
| ReplayLogger | Redis Stream + PostgreSQL | 事件顺序保证 |
| Gateway | Gorilla WS / Tokio | 稳定连接 |
| 观战系统 | Kafka Topic 分发 | 延迟广播 |
| 客户端 | WebGL + Canvas | 动画演示 |
| 存储 | JSONB + Gzip | 高压缩比快照 |
十、压测与运维(Load & Ops)
| 项目 | 指标 | 目标 |
|---|---|---|
| 房间并发 | 10 万对局 | 服务器负载线性 |
| 事件写入 | 每秒 2 万步落子 | 无丢失 |
| 快照生成 | 每秒 5 千次 | CPU < 80% |
| Redis Stream 消费延迟 | <50ms | |
| 回放一致性 | SHA256 校验一致 |
监控指标:
board_move_totalroom_active_countsnapshot_restore_totalspectator_online_total
十一、设计反思与演化(Reflection & Evolution)
11.1 核心经验
- 棋盘游戏是世界状态同步的雏形;
- 它定义了一个「由服务器维护的确定性宇宙」;
- 一致性 Hash 是反作弊与验证的基础;
- 观战延迟机制可以直接迁移到 MOBA、SLG 等实时对战中。
11.2 设计挑战
- 快照频率与性能平衡;
- 观战广播的带宽优化;
- 日志系统的幂等写入。
11.3 下一步演化方向
| 能力 | 对应原型 |
|---|---|
| 时间窗口控制 | → #4 快速问答抢答 |
| 并发冲突处理 | → #9 协作扫雷 |
| 状态锁步验证 | → #17 战棋对战 |
| 回放验证体系 | → #37 战斗回放引擎 |
十二、总结
井字棋 / 四子棋的实现,是从“回合”迈向“状态空间”的关键一步。 在这里,服务器第一次成为“世界的唯一真相”: 每一个格子、每一个动作、每一次广播, 都被记录、可重放、可验证。
从此之后,我们的世界不再只是聊天和回合, 而是一个能被还原、能被验证、能被观战的数字宇宙。
这就是“状态的起源(The Genesis of State)”。