本文档为 FakeLua 服务(server/)对齐用的 HTTP 接口契约(源自原 Go go/web 实现)。
- 实现:
server/lua/(http_server.lua、game.lua、huutil.lua、aiutil.lua等) - 前端:
server/static/(app.js直接调用下列路径) - 参考:旧 Go 源码副本在
server/ref_go_web/ - 线上:
http://majiang.esrrhs.xyz(nginx →:8888) - 会话模型:进程内单局
current;真人固定 座位 0,1/2/3 为 AI(观战模式下四人皆 AI) - 协议:HTTP + JSON;CORS 允许
*;多数写接口支持OPTIONS→204 - 错误:panic/异常 →
500 {"error":"..."};业务失败通常仍200,用success:false等字段表示
与 go/def.go / Java MaJiangDef 一致(对局用 1–34,花牌 35–42 本服未入墙):
| ID | 牌 |
|---|---|
| 1–9 | 一万 … 九万 |
| 10–18 | 一筒 … 九筒 |
| 19–27 | 一条 … 九条 |
| 28–31 | 东 南 西 北 |
| 32–34 | 中 发 白 |
中文串格式:"1万,2万,东"(StringToCards / CardsToString)。
| 值 | 含义 |
|---|---|
DISCARD |
当前座位出牌(庄家开局已摸第 14 张) |
RESPONSE |
他人打牌后,AI 侧响应结算中(前端一般看不到停留) |
WAITING_USER |
等待座位 0 对上家打出的牌做吃/碰/杠/胡/过 |
GAME_OVER |
已结算(胡或荒庄) |
| Method | Path | 作用 |
|---|---|---|
| GET/任意 | /api/status |
健康检查 |
| POST | /api/game/new |
新开一局,返回完整 GameStateView |
| GET/任意 | /api/game/state |
拉取当前局视图 |
| POST | /api/game/spectator |
切换观战(4 AI)模式 |
| POST | /api/game/discard |
座位 0 出牌 |
| POST | /api/game/action |
座位 0 对他人打牌响应 |
| POST | /api/game/self_action |
座位 0 自摸回合:自摸胡 / 暗杠补杠 |
| POST | /api/game/step |
推进 AI 一步 |
| POST | /api/game/auto_run |
连续推进最多 N 步 |
| POST | /api/algo/test |
算法实验室(不改对局状态) |
| GET | /、/* |
静态资源(index.html、app.js、tiles/*.svg 等) |
响应
{ "status": "ok", "ready": true }请求体
{
"guiMode": "random_flip",
"customGuiCard": 0,
"spectator": false
}| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
guiMode |
string | "random_flip" |
鬼牌规则,见下表 |
customGuiCard |
int | 0 |
guiMode=="card" 时指定鬼牌 ID(1–34) |
spectator |
bool | false |
true=四人皆 AI,可 auto step |
guiMode
| 值 | 行为 |
|---|---|
random_flip / "" |
翻指示牌,鬼=下一张(如翻 5 万则鬼为 6 万) |
card |
鬼=customGuiCard |
bai |
白板当鬼 |
zhong |
红中当鬼 |
none 及其它 |
无鬼 |
响应:完整 GameStateView(HTTP 200,非 {view:...} 包装)。
前端实际只传 guiMode + spectator(radio:random_flip / bai / zhong / none)。
响应:当前局 GameStateView。
请求体
{ "spectator": true }响应:更新后的 GameStateView。
座位 0 在 phase==DISCARD 且 currentSeat==0 时出牌。
请求体
{ "card": 9 }响应
{ "success": true, "view": { /* GameStateView */ } }座位 0 在 phase==WAITING_USER 时响应上家打出的牌。
请求体
{
"action": "chi",
"card": 0,
"chi1": 10,
"chi2": 11
}| 字段 | 说明 |
|---|---|
action |
"hu" / "peng" / "gang" / "chi" / "pass" |
card |
杠时可选目标牌;吃/碰/胡/过可传 0 |
chi1,chi2 |
吃时手中两张牌的 ID(与 lastDiscard 组成顺子) |
响应:{ "success": bool, "view": GameStateView }
座位 0 在自己出牌回合:自摸胡或暗杠/补杠。
请求体
{ "action": "gang", "card": 1 }action |
说明 |
|---|---|
"hu" |
自摸胡 |
"gang" |
暗杠或补杠,card 为杠牌 ID |
响应:{ "success": bool, "view": GameStateView }
推进 AI / 自动逻辑一步(观战或 AI 座位时使用)。
请求体:可空。
响应
{ "stepped": true, "view": { /* GameStateView */ } }stepped=false 表示无法再推进(例如在等真人,或已 GAME_OVER)。
请求体
{ "maxSteps": 10 }| 字段 | 默认 | 说明 |
|---|---|---|
maxSteps |
10 |
最多连续 Step() 次数 |
响应
{ "executedSteps": 7, "view": { /* GameStateView */ } }算法实验室,不修改当前对局。
请求体(cards / guiCards 可为 int 数组或中文串)
{
"cards": [1,1,1,2,3,4,5,6,7,8,9,28,28,28],
"guiCards": [],
"gui": 0
}兼容:guiCards 为空且 gui>0 时当作单鬼。
响应示例
{
"cards": [1,1,1,2,3,4,5,6,7,8,9,28,28,28],
"cardsStr": "1万,1万,1万,2万,3万,4万,5万,6万,7万,8万,9万,东,东,东,",
"guiCards": [],
"isHu": true,
"huTimeMicros": 762.241,
"tingCards": [],
"tingCardsStr": "",
"tingTimeMicros": 1972.055,
"recommendedOut": 9,
"recommendedOutStr": "9万",
"aiScore": 60,
"aiTimeMicros": 4602.042
}规则:
isHu:仅当len(cards)%3==2时调用IsHuExtratingCards:IsTingExtrarecommendedOut/aiScore:仅当len(cards)%3==2时OutAI+ 打出后Calc
从 embed 的 static/ 提供文件;/ → index.html。禁止 .. 路径。
对局相关接口的核心载荷(new / state / spectator 直接返回;其余包在 view 里)。
{
"gameId": 1001,
"wallCount": 83,
"guiCards": [23],
"guiIndicator": 22,
"dealerSeat": 0,
"currentSeat": 0,
"phase": "DISCARD",
"lastDiscard": 0,
"lastDiscardSeat": -1,
"players": [ /* PlayerView x4 */ ],
"availableActions": { /* AvailableActions */ },
"currentTingTargets": [ { "card": 5, "remainingCount": 2 } ],
"discardToTing": {
"9": [ { "card": 5, "remainingCount": 2 } ]
},
"aiRecommendation": { /* 可省略 */ },
"logs": [ "本局鬼牌(癞子)为: 【五条】" ],
"settlement": { /* 可省略,GAME_OVER 时有 */ },
"cardRemainCounts": { "1": 3, "2": 4, "...": 0 },
"spectatorMode": false
}| 字段 | 类型 | 说明 |
|---|---|---|
seat |
int | 0–3 |
name |
string | 如 "玩家 (南)" / "AI-东" |
isAi |
bool | |
tileCount |
int | 手牌张数 |
hand |
int[] | 始终下发完整手牌(明暗由前端控制) |
melds |
Meld[] | 吃碰杠副露 |
discards |
int[] | 弃牌河 |
lastDrawnCard |
int | 刚摸的牌,无则 0 |
isTing / isHu |
bool | |
score |
int | 初始 1000 |
| 字段 | 说明 |
|---|---|
type |
CHI / PENG / MING_GANG / AN_GANG / BU_GANG |
triggerCard |
触发牌 |
fromSeat |
来源座位;暗杠为 -1 |
cards |
3 或 4 张牌 ID |
| 字段 | 说明 |
|---|---|
canDiscard |
可否出牌 |
canHu / canPeng / canGang / canChi / canPass |
按钮开关 |
gangCards |
可杠的牌 ID 列表 |
chiOptions |
[[chi1,chi2], ...] 手中两张与 lastDiscard 成顺 |
| 字段 | 说明 |
|---|---|
recommendedAction |
discard / peng / gang / hu / chi / pass |
recommendedDiscard |
推荐打出的牌(discard 时) |
recommendedCard |
推荐相关单牌 |
recommendedCards |
相关牌列表 |
score |
浮点评分 |
reason |
中文说明 |
| 字段 | 说明 |
|---|---|
isDraw |
荒庄 |
winnerSeat |
赢家座位 |
providerSeat |
点炮者;自摸为 -1 |
isZimo |
是否自摸 |
winCard |
胡的那张牌 |
patterns |
番型字符串列表 |
totalFan / points |
番数 / 得分 |
scoreDeltas |
map[string]int,key 为座位号字符串 |
discardToTing:map[string][]TingTarget,key=打出牌 ID 字符串cardRemainCounts:map[string]int,key="1"…"34",值为场上剩余可见估计(4−已曝光)
TingTarget:{ "card": int, "remainingCount": int }
POST /api/game/new→ 渲染- 若观战:循环
POST /api/game/step或auto_run - 人机:
phase==DISCARD && currentSeat==0→discard或self_action phase==WAITING_USER→action(吃碰杠胡过)- AI 回合:
step/ 轮询state phase==GAME_OVER→ 读settlement- 实验室页独立调用
algo/test,与对局无关
- 路径与 JSON 字段名保持不变,现有
static/app.js可直接复用。 - 必须实现同一套牌 ID、阶段名、动作字符串。
- 单进程单局即可;若改为多会话,需另加
gameId/session,前端也要改。 - 对局 / HTTP 在 Lua;胡牌与 AI 经
native_majiang.cpp调用同仓库cpp/库(与 Go/Java 查表行为一致)。 - 查表数据:
data/majiang_clien_*.txt、majiang_ai_*.txt(及 feng/jian 变体),由majiang::Load()加载。 - 冒烟:
MAJIANG_SMOKE=1 flua lua --once(校验查表库 + IsHu/OutAI + 观战至 GAME_OVER)。
| 内容 | 文件 |
|---|---|
| 路由与 handler | server/lua/http_server.lua |
| 对局规则引擎 | server/lua/game.lua |
| 胡 / 听 | server/lua/huutil.lua |
| AI | server/lua/aiutil.lua |
| 番型结算 | server/lua/fan.lua |
| 查表加载入口 | server/lua/tables.lua 校验 data/majiang.db(由 tools/gen_majiang_db.py 生成) |
| C++ 算法桥 | server/native_majiang.cpp + cpp/ |
| 入口 | server/lua/main.lua + server/main.cpp |
| 前端调用 | server/static/app.js |
| 旧 Go 参考 | server/ref_go_web/ |