联机五子棋开发
本文档对应 market-apps/gomoku 的真实路由、SQLite 状态和实时事件。示例使用占位 Token,不包含真实凭据。当前五子棋前端优先使用房间 HTTP API 与全局 HTTP 长轮询,旧 WebSocket 房间事件仅作为兼容协议保留。
联机模型
Gomoku 市场应用通过 /api/gomoku 挂载。房间使用 6 位大写房间码,棋盘支持 15、19、21 三种规格。成员按加入顺序获得黑棋、白棋;第三位及之后的成员为观战者。房主退出时,最早留下的成员成为新房主。
状态对象核心字段:
{
"roomCode": "ABC123",
"size": 15,
"board": [[null]],
"turn": "black",
"winner": null,
"status": "active",
"gameId": 1,
"members": [{"user_id":"USER_ID","role":"owner","color":"black"}]
}房间 API
BASE_URL="http://localhost:9001"
TOKEN="TOKEN_FROM_LOGIN_RESPONSE"创建房间:
curl -X POST "$BASE_URL/api/gomoku/rooms" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"size":15}'成功返回 HTTP 201,从 data.roomCode 取得房间码:
ROOM_CODE="ABC123"
curl "$BASE_URL/api/gomoku/rooms/$ROOM_CODE" \
-H "Authorization: Bearer $TOKEN"加入、观战与退出:
curl -X POST "$BASE_URL/api/gomoku/rooms/$ROOM_CODE/join" -H "Authorization: Bearer $TOKEN"
curl -X POST "$BASE_URL/api/gomoku/rooms/$ROOM_CODE/watch" -H "Authorization: Bearer $TOKEN"
curl -X POST "$BASE_URL/api/gomoku/rooms/$ROOM_CODE/leave" -H "Authorization: Bearer $TOKEN"落子坐标从 0 开始:
curl -X POST "$BASE_URL/api/gomoku/rooms/$ROOM_CODE/move" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"row":7,"col":7}'历史、换色、重开和关闭:
curl "$BASE_URL/api/gomoku/rooms/$ROOM_CODE/history" -H "Authorization: Bearer $TOKEN"
curl -X POST "$BASE_URL/api/gomoku/rooms/$ROOM_CODE/color" -H "Authorization: Bearer $TOKEN"
curl -X POST "$BASE_URL/api/gomoku/rooms/$ROOM_CODE/reset" -H "Authorization: Bearer $TOKEN"
curl -X POST "$BASE_URL/api/gomoku/rooms/$ROOM_CODE/close" -H "Authorization: Bearer $TOKEN"close、reset 要求房主;color 只允许玩家在没有进行中对局时交换黑白。旧版个人接口 /api/gomoku/state、/api/gomoku/move、/api/gomoku/reset 保留兼容,但新集成应使用房间 API。
fetch 调用示例
async function gomokuRequest(path, options) {
var response = await fetch(BASE_URL + path, Object.assign({
headers: { Authorization: 'Bearer ' + TOKEN, 'Content-Type': 'application/json' }
}, options || {}))
var result = await response.json()
if (!response.ok || result.code < 200 || result.code >= 300) {
var error = new Error(result.message || 'Gomoku 请求失败')
error.status = response.status
error.data = result.data
throw error
}
return result.data
}
var room = await gomokuRequest('/api/gomoku/rooms', {
method: 'POST', body: JSON.stringify({ size: 19 })
})
await gomokuRequest('/api/gomoku/rooms/' + room.roomCode + '/join', { method: 'POST' })全局 HTTP 实时同步
五子棋市场应用应通过市场应用上下文中的 context.realtime 接入全局实时通道,不要自行创建 WebSocket。该通道不依赖 Chat 应用,腾讯 X5、TBS 和旧版 Android WebView 也可以使用。
var unsubscribe = context.realtime.subscribe('gomoku.room.changed', function(message) {
if (message.roomCode === roomCode) renderState(message.state);
});
context.realtime.publish('gomoku.room.changed', {
roomCode: roomCode,
state: state
}, context.appName);
unsubscribe();实时接口包括 connect()、subscribe(event, handler)、publish(event, payload, appName)、disconnect() 和 isReady()。底层接口为 /api/realtime/poll/register、/api/realtime/poll、/api/realtime/publish 和 /api/realtime/poll/unregister。
五子棋的创建、加入、观战、落子、重开和离开都使用 /api/gomoku/rooms/... HTTP API。HTTP 响应是最终状态来源,事件丢失时重新 GET 房间即可恢复。
WebSocket 房间同步(兼容协议)
先按 账号与 API 教程 连接 ws://localhost:10001,发送 connect 完成认证,再订阅房间:
var socket = new WebSocket('ws://localhost:10001')
socket.addEventListener('open', function () {
socket.send(JSON.stringify({ type: 'connect', user_id: 'YOUR_USER_ID', token: TOKEN }))
socket.send(JSON.stringify({ type: 'gomoku_subscribe', room_code: ROOM_CODE }))
})
socket.addEventListener('message', function (event) {
var message = JSON.parse(event.data)
if (message.type === 'gomoku_room_state') renderState(message.state)
if (message.type === 'gomoku_room_changed') renderState(message.state)
if (message.type === 'gomoku_move_rejected') showError(message.reason)
})落子和取消订阅:
socket.send(JSON.stringify({ type: 'gomoku_move', room_code: ROOM_CODE, row: 7, col: 7 }))
socket.send(JSON.stringify({ type: 'gomoku_unsubscribe', room_code: ROOM_CODE }))事件说明:
| 事件 | 说明 |
|---|---|
gomoku_room_state | 订阅成功后的完整状态 |
gomoku_room_changed | 合法落子后的房间状态与 move |
gomoku_move_rejected | 房间不存在、非成员、观战者、回合不符或坐标非法 |
gomoku_game_continued | 收到继续对局操作后的状态 |
房间状态以 HTTP GET 为最终恢复来源。旧版 WebSocket 客户端仍可重新认证、订阅并接收房间事件,但新市场应用不应依赖该协议。
规则与错误恢复
- 只允许当前
turn对应颜色落子。 - 坐标必须是整数且位于
0 <= row,col < size。 - 已有棋子、结束对局、观战者落子分别返回
409或403。 - 任意横、竖、斜线连续五子即获胜。
- 房间关闭后不能继续使用;状态接口返回
404。 - 网络超时不应直接重放落子;先 GET 状态确认该步是否已经落库。
推荐处理流程:
- 用户点击棋盘后立即锁定重复提交。
- 收到
gomoku_room_changed或 HTTP 成功响应后更新棋盘。 - 收到
gomoku_move_rejected或409时使用响应中的状态恢复。 - 连接关闭时显示离线状态并退避重连。
- 重连成功后调用
/rooms/:roomCode,再发送gomoku_subscribe。
调试清单
- 确认市场应用已安装且
/api/gomoku已挂载。 - 确认账号 Token 未过期,HTTP 实时请求携带
Authorization: Bearer <TOKEN>。 - 检查
server/src/migrations/004_add_gomoku_rooms.js已运行。 - 使用两个不同账号验证黑棋、白棋和观战角色。
- 分别验证 15×15、19×19、21×21 坐标边界。
- 不在浏览器控制台、抓包文件或 Issue 中粘贴真实 Cookie、Bearer Token 或密码。

