# 代码框架总结 ## 📋 文档概述 本文档对进贤麻将子游戏代码框架进行全面总结,包括: - **架构总览** - 整体架构设计和分层结构 - **模块依赖** - 各模块间的依赖关系和调用链 - **设计模式** - 使用的设计模式和最佳实践 - **扩展指南** - 如何扩展和定制功能 - **最佳实践** - 开发规范和注意事项 **文档目标**:帮助开发者从宏观角度理解整个代码框架,掌握系统设计思想和扩展方法。 --- ## 🏗️ 整体架构设计 ### 三层架构模型 ``` ┌─────────────────────────────────────────────────────────────┐ │ 接口层 (Interface Layer) │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Export.js │◄────框架────┤ Import.js │ │ │ │ (框架→游戏) │ │ (游戏→框架) │ │ │ └──────────────┘ └──────────────┘ │ │ ↕ ↕ │ │ 14个框架接口 13个框架接口 │ └─────────────────────────────────────────────────────────────┘ ↕ ┌─────────────────────────────────────────────────────────────┐ │ 业务层 (Business Layer) │ │ ┌──────────────────────────────────────────────┐ │ │ │ RpcHandler (RPC路由器) │ │ │ │ • 客户端→服务器RPC调用路由 │ │ │ │ • 34个RPC方法实现 │ │ │ └───────┬──────────────────────────────────────┘ │ │ ↓ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ GameController (游戏流程控制器) │ │ │ │ • 游戏生命周期管理 (开始、发牌、精牌、结算) │ │ │ │ • 状态转换协调 │ │ │ │ • 服务编排 │ │ │ └───┬─────────────┬─────────────┬────────────────────┘ │ │ ↓ ↓ ↓ │ │ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │ │ │Operation │ │Mahjong │ │AI Manager │ │ │ │Manager │ │Game │ │(AI托管) │ │ │ │(操作管理)│ │Service │ └─────────────┘ │ │ └──────────┘ │(胡牌计分)│ │ │ └──────────┘ │ └─────────────────────────────────────────────────────────────┘ ↕ ┌─────────────────────────────────────────────────────────────┐ │ 数据层 (Data Layer) │ │ ┌──────────────────────────────────────────────┐ │ │ │ GameStateManager (游戏状态管理器) │ │ │ │ • 游戏状态对象 (gameState) │ │ │ │ • 状态机管理 (7个游戏阶段) │ │ │ │ • 玩家状态管理 │ │ │ │ • 操作历史记录 │ │ │ └──────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ 共享模块 (Shared Modules) │ │ │ │ ┌────────────┐ ┌────────────┐ │ │ │ │ │MahjongCard │ │Jing │ │ │ │ │ │(牌对象) │ │Algorithm │ │ │ │ │ └────────────┘ └────────────┘ │ │ │ │ ┌────────────┐ ┌────────────┐ │ │ │ │ │WinDetection│ │Score │ │ │ │ │ │Factory │ │Calculation │ │ │ │ │ └────────────┘ └────────────┘ │ │ │ └──────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ 配置与常量 (Config & Constants) │ │ │ │ • RoomConfigUtils (房间配置解析) │ │ │ │ • GameConstants (12个常量模块) │ │ │ │ • ErrorMessages (错误消息定义) │ │ │ └──────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ### 架构分层职责 | 分层 | 职责 | 核心组件 | |------|------|----------| | **接口层** | 框架与游戏双向通信 | Export.js, Import.js | | **业务层** | 游戏逻辑实现和流程控制 | RpcHandler, GameController, Services | | **数据层** | 状态管理、数据存储、算法实现 | GameStateManager, Shared Modules, Config | --- ## 🔗 模块依赖关系 ### 完整依赖图 ``` mod.js (模块入口) ↓ require ┌───────────────────────────────────────────────────┐ │ 接口层加载 │ │ ├─ export.js ────────────┐ │ │ └─ import.js │ │ └───────────────────────────┼───────────────────────┘ │ ┌───────────────────────────┼───────────────────────┐ │ 业务层加载 │ │ │ ├─ RpcHandler.js ────────┤ │ │ ├─ GameController.js │ │ │ ├─ OperationManager.js │ │ │ ├─ MahjongGameService.js │ │ │ └─ AIManager.js │ │ └───────────────────────────┼───────────────────────┘ │ ┌───────────────────────────┼───────────────────────┐ │ 数据层加载 (被业务层依赖)│ │ │ ├─ GameStateManager.js ──┘ │ │ ├─ shared/dataStructures/ │ │ │ └─ MahjongCard.js │ │ ├─ shared/algorithms/ │ │ │ ├─ JingAlgorithm.js │ │ │ ├─ WinDetectionFactory.js │ │ │ ├─ ScoreCalculation.js │ │ │ └─ PatternFactory.js │ │ ├─ shared/config/ │ │ │ ├─ RoomConfigUtils.js │ │ │ └─ RuleConfigParser.js │ │ └─ shared/constants/ │ │ └─ index.js (导出12个常量模块) │ └───────────────────────────────────────────────────┘ ``` ### 核心依赖关系详解 #### 1️⃣ 接口层依赖 ```javascript // export.js 依赖 export.js ├─ GameController (业务流程控制) ├─ RoomConfigUtils (配置解析) ├─ ErrorMessages (错误消息) └─ Logger (日志记录) // import.js 依赖 import.js └─ 无内部依赖 (纯粹封装框架接口) ``` #### 2️⃣ 业务层依赖 ```javascript // RpcHandler.js 依赖 RpcHandler ├─ GameController (委托业务逻辑) ├─ OperationManager (操作验证) ├─ ErrorHandler (错误处理) └─ Logger (日志记录) // GameController.js 依赖 GameController ├─ GameStateManager (状态管理) ├─ MahjongGameService (胡牌计分) ├─ OperationManager (操作管理) ├─ AIManager (AI托管) ├─ DiceService (掷骰子) ├─ CardUtils (牌工具) └─ JingAlgorithm (精牌算法) // OperationManager.js 依赖 OperationManager ├─ GameStateManager (状态查询) ├─ WinDetectionFactory (胡牌检测) ├─ CardUtils (牌型检查) └─ GameConstants (常量) // MahjongGameService.js 依赖 MahjongGameService ├─ WinDetectionFactory (胡牌检测) ├─ ScoreCalculation (计分计算) ├─ JingAlgorithm (精分计算、比精) ├─ PatternFactory (牌型分析) └─ BiJingSystem (比精系统) ``` #### 3️⃣ 数据层依赖 ```javascript // GameStateManager.js 依赖 GameStateManager ├─ GameConstants (游戏常量) ├─ RoomConfigUtils (房间配置) └─ ErrorMessages (错误消息) // WinDetectionFactory.js 依赖 WinDetectionFactory ├─ MahjongCard (牌对象) ├─ JingAlgorithm (精牌处理) ├─ PatternFactory (牌型检测) └─ GameConstants (牌型常量) // ScoreCalculation.js 依赖 ScoreCalculation ├─ JingAlgorithm (精分计算) ├─ GameConstants (分数常量) └─ PatternFactory (牌型信息) // JingAlgorithm.js 依赖 JingAlgorithm ├─ MahjongCard (牌对象操作) └─ GameConstants (精牌规则常量) // MahjongCard.js 依赖 MahjongCard └─ 无依赖 (基础数据结构) ``` ### 依赖层级图 ``` Level 0 (基础层 - 无依赖) ├─ MahjongCard ├─ GameConstants └─ ErrorMessages Level 1 (算法层 - 依赖Level 0) ├─ JingAlgorithm (依赖: MahjongCard) ├─ RoomConfigUtils (依赖: GameConstants) ├─ PatternFactory (依赖: MahjongCard) └─ CardUtils (依赖: MahjongCard) Level 2 (服务层 - 依赖Level 0-1) ├─ WinDetectionFactory (依赖: MahjongCard, JingAlgorithm, PatternFactory) ├─ ScoreCalculation (依赖: JingAlgorithm, PatternFactory) ├─ GameStateManager (依赖: GameConstants, RoomConfigUtils) └─ DiceService (依赖: GameConstants) Level 3 (业务层 - 依赖Level 0-2) ├─ OperationManager (依赖: GameStateManager, WinDetectionFactory) ├─ MahjongGameService (依赖: WinDetectionFactory, ScoreCalculation, JingAlgorithm) └─ AIManager (依赖: OperationManager, GameStateManager) Level 4 (控制层 - 依赖Level 0-3) └─ GameController (依赖: GameStateManager, OperationManager, MahjongGameService, AIManager) Level 5 (RPC层 - 依赖Level 0-4) └─ RpcHandler (依赖: GameController, OperationManager) Level 6 (接口层 - 依赖Level 0-5) └─ export.js (依赖: GameController, RoomConfigUtils) ``` --- ## 🎨 设计模式应用 ### 1. 工厂模式 (Factory Pattern) #### 应用场景 - **MahjongCard创建** - 统一牌对象创建 - **WinDetectionFactory** - 胡牌检测策略工厂 - **PatternFactory** - 牌型分析工厂 #### 实现示例 ```javascript // MahjongCard.js - 工厂方法 MahjongCard.create = function(code) { return new MahjongCard(code); }; MahjongCard.createBatch = function(codes) { return codes.map(function(code) { return MahjongCard.create(code); }); }; // WinDetectionFactory.js - 策略工厂 WinDetectionFactory.detectWin = function(handTiles, jingInfo, gameState) { // 根据不同牌型策略检测 var strategies = [ this._checkPinghu, // 平胡策略 this._checkQidui, // 七对策略 this._checkSipeng, // 四碰策略 this._checkShisanlan, // 十三烂策略 this._checkQixingShisanlan // 七星十三烂策略 ]; var results = []; for (var i = 0; i < strategies.length; i++) { var result = strategies[i].call(this, handTiles, jingInfo); if (result.canWin) { results.push(result); } } return this._selectBestPattern(results); }; ``` **优势**: - ✅ 统一对象创建接口 - ✅ 封装复杂创建逻辑 - ✅ 支持策略扩展 ### 2. 单例模式 (Singleton Pattern) #### 应用场景 - **Logger** - 全局日志记录器 - **ErrorHandler** - 全局错误处理器 - **Constants** - 常量定义模块 #### 实现示例 ```javascript // Logger.js - 单例实现 var Logger = (function() { var instance; function createLogger() { var config = { level: 'INFO', maxHistorySize: 1000, enableConsole: true }; var history = []; var statistics = { DEBUG: 0, INFO: 0, WARN: 0, ERROR: 0 }; return { log: function(level, message, data) { // 实现日志记录 }, getHistory: function() { return history; }, getStatistics: function() { return statistics; } }; } return { getInstance: function() { if (!instance) { instance = createLogger(); } return instance; } }; })(); // 使用 var logger = Logger.getInstance(); logger.log('INFO', '游戏开始'); ``` **优势**: - ✅ 全局唯一实例 - ✅ 统一访问入口 - ✅ 资源共享 ### 3. 观察者模式 (Observer Pattern) #### 应用场景 - **游戏状态变化通知** - GameStateManager通知状态变化 - **操作事件通知** - OperationManager通知操作完成 #### 实现示例 ```javascript // GameStateManager.js - 观察者模式 GameStateManager.transitionToPhase = function(gameState, newPhase, transitionData) { var oldPhase = gameState.phase; // 1. 状态转换 gameState.previousPhase = oldPhase; gameState.phase = newPhase; // 2. 通知观察者 this._notifyPhaseChange(gameState, oldPhase, newPhase, transitionData); return { success: true, oldPhase: oldPhase, newPhase: newPhase }; }; GameStateManager._notifyPhaseChange = function(gameState, oldPhase, newPhase, data) { // 触发状态变化事件 if (typeof gameState.onPhaseChange === 'function') { gameState.onPhaseChange({ oldPhase: oldPhase, newPhase: newPhase, data: data, timestamp: Date.now() }); } }; ``` **优势**: - ✅ 解耦状态变化和业务响应 - ✅ 支持多个观察者 - ✅ 灵活的事件处理 ### 4. 策略模式 (Strategy Pattern) #### 应用场景 - **胡牌检测** - 不同牌型检测策略 - **AI决策** - 不同难度AI策略 #### 实现示例 ```javascript // AIManager.js - 策略模式 AIManager.decideOperation = function(gameState, playerId) { var aiLevel = this._getAILevel(playerId); // 根据AI等级选择策略 var strategy; switch (aiLevel) { case 'easy': strategy = this._easyStrategy; break; case 'medium': strategy = this._mediumStrategy; break; case 'hard': strategy = this._hardStrategy; break; default: strategy = this._mediumStrategy; } return strategy.call(this, gameState, playerId); }; // 简单策略 - 随机操作 AIManager._easyStrategy = function(gameState, playerId) { var availableOps = this._getAvailableOperations(gameState, playerId); if (availableOps.length === 0) return null; var randomIndex = Math.floor(Math.random() * availableOps.length); return availableOps[randomIndex]; }; // 中等策略 - 优先高价值操作 AIManager._mediumStrategy = function(gameState, playerId) { var availableOps = this._getAvailableOperations(gameState, playerId); if (availableOps.length === 0) return null; // 按优先级排序: 胡 > 杠 > 碰 > 吃 availableOps.sort(function(a, b) { return a.priority - b.priority; }); return availableOps[0]; }; ``` **优势**: - ✅ 算法独立封装 - ✅ 易于切换和扩展 - ✅ 符合开闭原则 ### 5. 适配器模式 (Adapter Pattern) #### 应用场景 - **RoomAdapter** - 适配友乐平台房间接口 - **ConfigAdapter** - 适配不同版本配置格式 #### 实现示例 ```javascript // RoomAdapter.js - 适配器模式 var RoomAdapter = { /** * 将友乐平台房间对象转换为游戏内部格式 */ adaptRoom: function(o_room) { return { roomcode: o_room.roomcode, roomtype: o_room.roomtype, players: this._adaptPlayers(o_room.players), config: this._parseRoomConfig(o_room.roomtype) }; }, _adaptPlayers: function(platformPlayers) { return platformPlayers.map(function(player, index) { return { id: player.playerid, seat: index, nickname: player.nickname, avatar: player.avatar, score: player.gameinfo ? player.gameinfo.score : 0 }; }); }, _parseRoomConfig: function(roomtype) { return RoomConfigUtils.parse(roomtype); } }; ``` **优势**: - ✅ 隔离平台差异 - ✅ 简化业务逻辑 - ✅ 提高可移植性 ### 6. 模板方法模式 (Template Method Pattern) #### 应用场景 - **GameController.startGame** - 游戏开始流程模板 - **RpcHandler.handleOperation** - RPC处理流程模板 #### 实现示例 ```javascript // RpcHandler.js - 模板方法 RpcHandler.prototype.handleOperation = function(pack, room, callback) { // 模板流程 // 1. 前置验证 var validationResult = this._validateRequest(pack, room); if (!validationResult.valid) { return callback({ error: validationResult.error }); } // 2. 权限检查 var authResult = this._checkPermission(pack, room); if (!authResult.authorized) { return callback({ error: 'PERMISSION_DENIED' }); } // 3. 执行操作 (子类实现) var result = this._performOperation(pack, room); // 4. 后置处理 this._afterOperation(pack, room, result); // 5. 返回结果 callback(result); }; // 子类实现具体操作 RpcHandler.prototype._performOperation = function(pack, room) { // 由具体RPC方法实现 throw new Error('_performOperation must be implemented'); }; ``` **优势**: - ✅ 统一处理流程 - ✅ 强制执行规范 - ✅ 减少重复代码 --- ## 🔧 扩展指南 ### 1. 添加新的RPC方法 #### 步骤1: 在RpcHandler中定义方法 ```javascript // rpc/RpcHandler.js /** * 新增RPC: 玩家请求换牌 (示例) */ RpcHandler.prototype.player_swap_card = function(pack, room, callback) { var playerId = pack.playerid; var cardToSwap = pack.data.card; var gameState = room.gameState; // 1. 验证操作合法性 if (gameState.phase !== 'playing') { return callback({ error: 'INVALID_PHASE', message: '当前阶段不允许换牌' }); } // 2. 执行换牌逻辑 var result = this._performCardSwap(gameState, playerId, cardToSwap); // 3. 广播换牌消息 if (result.success) { room.import.broadcast_operation(room, { type: 'card_swap', playerId: playerId, card: cardToSwap }); } callback(result); }; RpcHandler.prototype._performCardSwap = function(gameState, playerId, card) { // 实现换牌逻辑 return { success: true }; }; ``` #### 步骤2: 在mod.js中注册RPC方法 ```javascript // mod.js mod_jinxianmahjong.player_swap_card = function(pack) { return mod_jinxianmahjong.rpcHandler.player_swap_card( pack, mod_jinxianmahjong.room, function(result) { return result; } ); }; ``` #### 步骤3: 客户端调用 ```javascript // 客户端代码 SendPack({ cmd: "DoPack", gameid: "jinxianmahjong", rpc: "player_swap_card", data: { card: "3m" } }); ``` ### 2. 添加新的游戏规则 #### 步骤1: 在RoomConfigUtils中定义规则位 ```javascript // shared/config/RoomConfigUtils.js RoomConfigUtils.parse = function(roomtype) { // ... 现有解析逻辑 // 新增规则位解析 (假设使用第14位) var enableCardSwap = roomtype.charAt(13) === '1'; return { // ... 现有配置 specialRules: { enableCardSwap: enableCardSwap, // 新规则 // ... 其他规则 } }; }; ``` #### 步骤2: 在操作验证中使用规则 ```javascript // game/OperationManager.js OperationManager.validateCardSwap = function(gameState, playerId, card) { // 检查规则是否启用 if (!gameState.rules.specialRules.enableCardSwap) { return { valid: false, error: 'CARD_SWAP_DISABLED', message: '当前房间规则不允许换牌' }; } // ... 其他验证逻辑 return { valid: true }; }; ``` ### 3. 添加新的共享算法模块 #### 步骤1: 创建算法模块 ```javascript // shared/algorithms/NewAlgorithm.js /** * 新算法模块 (示例: 牌型强度评估) */ var NewAlgorithm = { /** * 评估手牌强度 * @param {Array} handCards - 手牌 * @param {Object} jingInfo - 精牌信息 * @returns {Object} 评估结果 */ evaluateHandStrength: function(handCards, jingInfo) { var strength = { score: 0, level: 'low', // low/medium/high factors: [] }; // 1. 计算精牌数量 var jingCount = this._countJingCards(handCards, jingInfo); strength.score += jingCount * 10; strength.factors.push({ type: 'jing', count: jingCount }); // 2. 计算刻子数量 var keziCount = this._countKezi(handCards); strength.score += keziCount * 15; strength.factors.push({ type: 'kezi', count: keziCount }); // 3. 计算顺子数量 var shunziCount = this._countShunzi(handCards); strength.score += shunziCount * 10; strength.factors.push({ type: 'shunzi', count: shunziCount }); // 4. 确定等级 if (strength.score >= 50) { strength.level = 'high'; } else if (strength.score >= 30) { strength.level = 'medium'; } return strength; }, _countJingCards: function(handCards, jingInfo) { var count = 0; for (var i = 0; i < handCards.length; i++) { if (handCards[i].code === jingInfo.zhengJing || handCards[i].code === jingInfo.fuJing) { count++; } } return count; }, // ... 其他辅助方法 }; // 导出 (Node.js) if (typeof module !== 'undefined' && module.exports) { module.exports = NewAlgorithm; } // 导出 (浏览器) if (typeof window !== 'undefined') { window.NewAlgorithm = NewAlgorithm; } ``` #### 步骤2: 在mod.js中加载模块 ```javascript // mod.js function loadGameModules() { // ... 现有模块加载 // 加载新算法模块 require('./shared/algorithms/NewAlgorithm.js'); console.log("[mod_jinxianmahjong] NewAlgorithm.js 加载成功"); // ... 继续加载其他模块 } ``` #### 步骤3: 在业务代码中使用 ```javascript // AIManager.js AIManager.decideDiscard = function(gameState, playerId) { var player = gameState.players[playerId]; var handCards = player.handCards; // 使用新算法评估手牌 var strength = NewAlgorithm.evaluateHandStrength( handCards, gameState.jingInfo ); console.log('手牌强度:', strength.level, '分数:', strength.score); // 根据评估结果做决策 // ... }; ``` ### 4. 添加新的常量模块 #### 步骤1: 创建常量文件 ```javascript // shared/constants/NewConstants.js /** * 新功能常量定义 (示例: 换牌功能) */ var NewConstants = { // 换牌规则 SWAP_RULES: { MAX_SWAPS_PER_ROUND: 3, // 每局最多换牌次数 SWAP_TIME_LIMIT: 10000, // 换牌时限(毫秒) SWAP_COST: 1 // 换牌消耗(房卡) }, // 换牌状态 SWAP_STATUS: { AVAILABLE: 'available', // 可以换牌 IN_PROGRESS: 'in_progress', // 换牌中 COMPLETED: 'completed', // 已完成 TIMEOUT: 'timeout' // 超时 } }; // 导出 if (typeof module !== 'undefined' && module.exports) { module.exports = NewConstants; } ``` #### 步骤2: 在constants/index.js中注册 ```javascript // shared/constants/index.js var NewConstants = require('./NewConstants.js'); module.exports = { // ... 现有常量 NewConstants: NewConstants }; ``` --- ## 📝 最佳实践 ### 1. 代码组织原则 #### ✅ 单一职责原则 (SRP) 每个模块只负责一个功能: ```javascript // ❌ 不好的实践: 一个类做太多事情 var GameManager = { dealCards: function() {}, checkWin: function() {}, calculateScore: function() {}, updateDatabase: function() {}, sendNotification: function() {} }; // ✅ 好的实践: 职责分离 var GameController = { dealCards: function() {} }; var WinDetection = { checkWin: function() {} }; var ScoreCalculation = { calculateScore: function() {} }; ``` #### ✅ 开闭原则 (OCP) 对扩展开放,对修改关闭: ```javascript // ✅ 使用策略模式扩展牌型检测 WinDetectionFactory.registerPattern = function(patternName, checkFunction) { this.patterns[patternName] = checkFunction; }; // 添加新牌型无需修改核心代码 WinDetectionFactory.registerPattern('custom_pattern', function(handCards) { // 自定义牌型检测逻辑 }); ``` #### ✅ 依赖倒置原则 (DIP) 依赖抽象而非具体实现: ```javascript // ✅ 通过接口依赖 GameController.setGameService = function(gameService) { // gameService可以是任何实现了胡牌检测接口的对象 this.gameService = gameService; }; ``` ### 2. 错误处理规范 #### 统一错误返回格式 ```javascript // 所有方法返回统一格式 function someOperation() { try { // 操作逻辑 return { success: true, data: result }; } catch (error) { return { success: false, error: error.code || 'UNKNOWN_ERROR', message: error.message, details: error.details }; } } ``` #### 使用ErrorHandler统一处理 ```javascript // 使用ErrorHandler记录和处理错误 var ErrorHandler = require('./shared/utils/ErrorHandler.js'); function riskyOperation() { try { // ... 可能出错的代码 } catch (error) { ErrorHandler.handle(error, { context: 'riskyOperation', severity: 'high', additionalInfo: { /* ... */ } }); return { success: false, error: 'OPERATION_FAILED' }; } } ``` ### 3. 日志记录规范 #### 关键节点记录日志 ```javascript var Logger = require('./shared/utils/Logger.js'); function startGame(room) { Logger.info('游戏开始', { roomcode: room.roomcode, playerCount: room.playerCount, timestamp: Date.now() }); try { // 游戏逻辑 Logger.debug('发牌完成', { cards: dealedCards }); Logger.info('精牌确定', { jingCard: jingCard }); } catch (error) { Logger.error('游戏开始失败', { error: error.message, stack: error.stack }); } } ``` #### 日志级别使用规范 | 级别 | 使用场景 | 示例 | |------|---------|------| | **TRACE** | 最详细的调试信息 | 每次牌型检测的详细步骤 | | **DEBUG** | 开发调试信息 | 中间变量值、函数调用参数 | | **INFO** | 重要业务流程节点 | 游戏开始、发牌完成、胡牌 | | **WARN** | 潜在问题警告 | 配置缺失使用默认值、性能警告 | | **ERROR** | 错误但程序可继续 | 玩家操作失败、数据验证失败 | | **FATAL** | 致命错误需要停止 | 数据库连接失败、核心模块加载失败 | ### 4. 性能优化建议 #### ✅ 避免重复计算 ```javascript // ❌ 不好: 重复计算 function checkWin(handCards, jingInfo) { var jingCards = getJingCards(jingInfo); // 每次调用都计算 // ... } // ✅ 好: 缓存计算结果 GameStateManager.createGameState = function(roomcode, roomtype, players) { var gameState = { // ... jingInfo: null, _jingCardsCache: null // 缓存精牌列表 }; // 添加getter缓存精牌列表 Object.defineProperty(gameState, 'jingCards', { get: function() { if (!this._jingCardsCache && this.jingInfo) { this._jingCardsCache = getJingCards(this.jingInfo); } return this._jingCardsCache; } }); return gameState; }; ``` #### ✅ 减少对象创建 ```javascript // ❌ 不好: 频繁创建临时对象 for (var i = 0; i < 1000; i++) { var result = { success: true, data: someData }; process(result); } // ✅ 好: 复用对象 var result = { success: false, data: null }; for (var i = 0; i < 1000; i++) { result.success = true; result.data = someData; process(result); } ``` #### ✅ 使用对象池 ```javascript // MahjongCard对象池 var MahjongCardPool = { pool: [], maxSize: 200, acquire: function(code) { var card = this.pool.pop(); if (card) { card.code = code; card.reset(); return card; } return new MahjongCard(code); }, release: function(card) { if (this.pool.length < this.maxSize) { card.reset(); this.pool.push(card); } } }; ``` ### 5. 测试规范 #### 单元测试结构 ```javascript // tests/units/test_module_name.js console.log('\n========================================'); console.log('模块名称 单元测试'); console.log('========================================\n'); // 加载模块 var ModuleName = require('../../path/to/ModuleName.js'); // 测试用例1: 基础功能 console.log('【测试1】基础功能测试\n'); var result1 = ModuleName.someFunction(input1); if (result1.success) { console.log('✅ 测试通过'); } else { console.log('❌ 测试失败:', result1.error); } // 测试用例2: 边界条件 console.log('\n【测试2】边界条件测试\n'); // ... // 测试用例3: 错误处理 console.log('\n【测试3】错误处理测试\n'); // ... console.log('\n========================================'); console.log('测试完成'); console.log('========================================\n'); ``` ### 6. 命名规范 #### 变量命名 ```javascript // ✅ 好的命名: 清晰表达意图 var handCards = []; // 手牌 var jingInfo = {}; // 精牌信息 var isWinDetected = false; // 是否检测到胡牌 var totalScore = 0; // 总分数 // ❌ 不好的命名: 含义不明 var hc = []; var ji = {}; var flag = false; var num = 0; ``` #### 函数命名 ```javascript // ✅ 好的命名: 动词+名词,清晰描述功能 function dealCards(players, dealer) {} function checkWinPattern(handCards) {} function calculateJingScore(jingCards) {} function validateOperation(operation) {} // ❌ 不好的命名 function deal() {} function check() {} function calc() {} function validate() {} ``` #### 常量命名 ```javascript // ✅ 大写字母+下划线 var MAX_PLAYERS = 4; var DEFAULT_HAND_SIZE = 13; var JING_BASE_SCORE = 2; // ❌ 小写或驼峰 var maxPlayers = 4; var defaultHandSize = 13; ``` --- ## 🚨 常见问题与解决方案 ### 问题1: 模块加载顺序错误 **症状**: 提示"XXX is not defined"或"Cannot read property of undefined" **原因**: 依赖的模块还未加载就使用了 **解决方案**: ```javascript // 检查mod.js中的加载顺序 // 确保被依赖的模块先加载 // ✅ 正确顺序 require('./shared/dataStructures/MahjongCard.js'); // 基础 require('./shared/algorithms/JingAlgorithm.js'); // 依赖MahjongCard require('./shared/algorithms/WinDetectionFactory.js'); // 依赖JingAlgorithm // ❌ 错误顺序 require('./shared/algorithms/WinDetectionFactory.js'); // 依赖未加载! require('./shared/algorithms/JingAlgorithm.js'); require('./shared/dataStructures/MahjongCard.js'); ``` ### 问题2: 状态不一致 **症状**: gameState中的数据与预期不符,操作验证失败 **原因**: 多处修改gameState但未同步更新 **解决方案**: ```javascript // ✅ 使用GameStateManager统一管理状态 GameStateManager.updatePlayerState(gameState, playerId, { handCards: newHandCards, score: newScore }); // ❌ 直接修改可能导致不一致 gameState.players[playerId].handCards = newHandCards; gameState.players[playerId].score = newScore; // 可能忘记更新其他相关字段 ``` ### 问题3: 精牌计算错误 **症状**: 精分计算结果与预期不符 **原因**: 没有正确识别精牌或计算逻辑错误 **解决方案**: ```javascript // ✅ 使用JingAlgorithm统一处理 var jingScore = JingAlgorithm.calculateJingScore( handCards, jingInfo, { includeZhengJing: true, includeFuJing: true, excludeUsedCards: true // 排除已用于组合的精牌 } ); // ❌ 手动计算容易出错 var jingScore = 0; for (var i = 0; i < handCards.length; i++) { if (handCards[i].code === jingInfo.zhengJing) { jingScore += 2; } // 可能遗漏副精、杠精等特殊情况 } ``` ### 问题4: 内存泄漏 **症状**: 服务器运行一段时间后内存持续增长 **原因**: 游戏结束后未清理gameState或事件监听器 **解决方案**: ```javascript // ✅ 游戏结束后清理 GameController.endGame = function(room) { // 1. 保存游戏记录 this._saveGameRecord(room.gameState); // 2. 清理事件监听器 room.gameState.onPhaseChange = null; room.gameState.onOperationComplete = null; // 3. 清理定时器 if (room.gameState.operationTimer) { clearTimeout(room.gameState.operationTimer); } // 4. 释放gameState引用 room.gameState = null; }; ``` ### 问题5: RPC调用超时 **症状**: 客户端请求超时,无响应 **原因**: 服务端处理时间过长或callback未调用 **解决方案**: ```javascript // ✅ 确保所有分支都调用callback RpcHandler.prototype.player_operation = function(pack, room, callback) { try { // 验证 if (!this._validate(pack)) { return callback({ error: 'INVALID_REQUEST' }); // 及时返回 } // 处理 var result = this._process(pack, room); // 返回结果 callback(result); } catch (error) { // 错误处理也要调用callback callback({ error: 'INTERNAL_ERROR', message: error.message }); } }; // ❌ 可能遗漏callback导致超时 RpcHandler.prototype.player_operation = function(pack, room, callback) { if (!this._validate(pack)) { return; // 忘记调用callback! } // ... }; ``` --- ## 📚 相关文档链接 - **上一篇**: [08-游戏流程概述.md](08-游戏流程概述.md) - 完整游戏流程 - **下一篇**: [10-快速入门指南.md](../development/10-快速入门指南.md) - 开发入门指南 - **参考文档**: - [00-框架基础概述.md](../framework/00-框架基础概述.md) - 框架基础 - [04-游戏核心服务.md](../core/04-游戏核心服务.md) - 核心服务详解 - [05-共享代码模块.md](../core/05-共享代码模块.md) - 算法模块详解 --- ## 📝 附录 ### A. 模块清单 完整的模块列表和文件路径: | 模块分类 | 模块名称 | 文件路径 | |---------|---------|----------| | **入口** | mod.js | `/server/games2/jinxianmahjong/mod.js` | | **接口** | Export | `/server/games2/jinxianmahjong/export.js` | | **接口** | Import | `/server/games2/jinxianmahjong/import.js` | | **RPC** | RpcHandler | `/server/games2/jinxianmahjong/rpc/RpcHandler.js` | | **控制** | GameController | `/server/games2/jinxianmahjong/game/GameController.js` | | **服务** | OperationManager | `/server/games2/jinxianmahjong/game/OperationManager.js` | | **服务** | MahjongGameService | `/server/games2/jinxianmahjong/game/MahjongGameService.js` | | **服务** | AIManager | `/server/games2/jinxianmahjong/game/AIManager.js` | | **数据** | GameStateManager | `/server/games2/jinxianmahjong/shared/dataStructures/GameStateManager.js` | | **数据** | MahjongCard | `/server/games2/jinxianmahjong/shared/dataStructures/MahjongCard.js` | | **算法** | JingAlgorithm | `/server/games2/jinxianmahjong/shared/algorithms/JingAlgorithm.js` | | **算法** | WinDetectionFactory | `/server/games2/jinxianmahjong/shared/algorithms/WinDetectionFactory.js` | | **算法** | ScoreCalculation | `/server/games2/jinxianmahjong/shared/algorithms/ScoreCalculation.js` | | **算法** | PatternFactory | `/server/games2/jinxianmahjong/shared/algorithms/PatternFactory.js` | | **配置** | RoomConfigUtils | `/server/games2/jinxianmahjong/shared/config/RoomConfigUtils.js` | | **配置** | RuleConfigParser | `/server/games2/jinxianmahjong/shared/config/RuleConfigParser.js` | | **常量** | Constants (12个模块) | `/server/games2/jinxianmahjong/shared/constants/` | | **工具** | Logger | `/server/games2/jinxianmahjong/shared/utils/Logger.js` | | **工具** | ErrorHandler | `/server/games2/jinxianmahjong/shared/utils/ErrorHandler.js` | ### B. 接口清单 #### Export接口 (14个) 1. `makewar` - 创建房间 2. `get_needroomcard` - 获取所需房卡数 3. `get_smallroundnumber` - 获取小局数 4. `get_roomtype` - 获取房间类型 5. `get_deskinfo` - 获取牌桌信息 6. `smallround_prepare` - 小局准备 7. `check_canhuprocess` - 检查胡牌过程 8. `check_canhupai` - 检查能否胡牌 9. `get_hu_describe` - 获取胡牌描述 10. `check_baopai` - 检查报牌 11. `check_baopai_process` - 检查报牌过程 12. `check_canhupai_fanpai` - 检查翻牌胡牌 13. `check_operate_fanpai` - 检查翻牌操作 14. `recieve_match_result` - 接收比赛结果 #### Import接口 (13个) 1. `smallround_finish` - 小局结束 2. `bigroom_finish` - 大局结束 3. `sendcards` - 发牌 4. `send_eachother_operate` - 发送玩家间操作 5. `send_hupai_broadcast` - 广播胡牌 6. `send_gangpai_broadcast` - 广播杠牌 7. `send_message` - 发送消息 8. `save_grade` - 保存战绩 9. `random` - 随机数 10. `get_trusteeship_level` - 获取托管等级 11. `get_ip_address` - 获取IP地址 12. `get_match_config` - 获取比赛配置 13. `finish_gametask` - 完成游戏任务 ### C. 关键算法复杂度 | 算法 | 时间复杂度 | 空间复杂度 | 说明 | |------|-----------|-----------|------| | **平胡检测** | O(n²) | O(n) | n为手牌数量,需要尝试多种组合 | | **七对检测** | O(n) | O(n) | 线性扫描即可 | | **精分计算** | O(n) | O(1) | 遍历手牌一次 | | **比精算法** | O(n) | O(n) | 需要构建牌型组合 | | **操作优先级** | O(m log m) | O(m) | m为可用操作数量,需要排序 | --- **文档版本**: v1.0 **最后更新**: 2025年10月15日 **维护者**: 进贤麻将开发团队