Files
doucan/AGENTS.md
2026-02-19 21:18:12 +08:00

3.4 KiB
Raw Blame History

斗地主残局版 - AGENTS.md

1. 项目结构

doudizhu-server/
├── app/                    # Go后端
│   ├── cmd/main.go         # 程序入口
│   ├── internal/
│   │   ├── models/         # 数据模型Card, Room, Player等
│   │   ├── game/           # 游戏逻辑(牌型判断、对局管理)
│   │   ├── handlers/       # HTTP API处理器
│   │   └── ws/             # WebSocket处理
│   ├── Dockerfile
│   └── go.mod
├── nginx/nginx.conf        # Nginx反向代理配置
├── nginx/html/             # 静态文件HTML/CSS/JS
├── compose.yaml
├── README.md
└── API.md

2. 构建与运行命令

# 本地开发
cd doudizhu-server/app && go mod tidy && go run ./cmd

# Docker部署
cd doudizhu-server && docker compose up -d --build

# 代码格式化
gofmt -w ./app

# 静态检查
go vet ./app/...

# 运行所有测试
go test ./app/...

# 运行单个包测试
go test ./app/internal/game/...

# 运行单个测试
go test ./app/internal/game/... -run TestCardType

# 带覆盖率
go test ./app/... -cover

3. Go代码风格规范

命名规范

  • 导出:大驼峰命名,如 GameManagerNewCardLogic
  • 模块内:小驼峰命名,如 userIdcardKey
  • 模块名:全小写,如 gamehandlersws
  • 常量:全大写下划线命名

Import规范

import (
    "encoding/json"    // 标准库
    "net/http"

    "github.com/gorilla/websocket"  // 第三方库

    "doudizhu-server/internal/game"  // 本地包
    "doudizhu-server/internal/models"
)

错误处理

使用哨兵错误模式:

// 定义 (internal/game/errors.go)
var (
    ErrRoomNotFound = errors.New("room not found")
    ErrNotYourTurn  = errors.New("not your turn")
)

// 使用:早返回
func (h *Handler) CreateRoom(w http.ResponseWriter, r *http.Request) {
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        h.writeError(w, http.StatusBadRequest, "invalid request")
        return
    }
}

并发安全

type GameManager struct {
    rooms map[string]*models.Room
    mu    sync.RWMutex
}

// 读操作用RLock
func (gm *GameManager) GetRoom(id string) (*models.Room, error) {
    gm.mu.RLock()
    defer gm.mu.RUnlock()
    // ...
}

// 写操作用Lock
func (gm *GameManager) CreateRoom(...) {
    gm.mu.Lock()
    defer gm.mu.Unlock()
    // ...
}

4. HTTP API响应格式

type ApiResponse struct {
    Status  int         `json:"status"`  // HTTP状态码
    Code    int         `json:"code"`    // 0=成功, 1=失败
    Message string      `json:"message"`
    Data    interface{} `json:"data"`
}

5. 游戏规则要点

  • 超人强第55张牌最大单牌可管一切
  • 简化牌型:三张可成顺子/炸弹,两对可成连对
  • 发牌每人初始5张一轮后摸1张
  • 无地主:上一轮获胜者先出

6. 开发注意事项

  1. 代码变动后同步更新文档README.md 和 API.md
  2. 后端API路由必须在 /api
  3. WebSocket路径/api/ws?roomId=xxx&playerId=xxx
  4. 前端不使用npm/react采用HTML+CSS+JS
  5. JSON字段用下划线命名,如 room_id,但尽量用单词

7. 调试

# 查看日志
docker compose logs -f app

# 前端不生效?强制刷新 (Ctrl+F5)