const { POWER_CALC } = require('../config/constants'); /** * 战力值计算服务 */ class PowerCalculator { /** * 计算单场比赛战力值变动 * @param {Object} winner - 胜者信息 { powerScore, level, protectedMatches } * @param {Object} loser - 败者信息 { powerScore, level, protectedMatches } * @param {number} matchWeight - 比赛权重 * @returns {Object} { winnerChange, loserChange } */ static calculate(winner, loser, matchWeight = 1.0) { const { BASE_WIN, BASE_LOSE, UNDERDOG_THRESHOLD, UNDERDOG_RATE, MAX_CHANGE, NEWBIE_PROTECTION, NEWBIE_LOSE_RATE } = POWER_CALC; // 计算分差 const diff = loser.powerScore - winner.powerScore; // 基础得分 let winnerChange = BASE_WIN; let loserChange = BASE_LOSE; // 以下克上奖励 if (diff >= UNDERDOG_THRESHOLD) { const bonus = Math.ceil(diff * UNDERDOG_RATE); winnerChange += bonus; } // 应用比赛权重 winnerChange = Math.round(winnerChange * matchWeight); loserChange = Math.round(loserChange * matchWeight); // 新手保护(Lv1和Lv2,前5场) if (loser.level <= 2 && loser.protectedMatches < NEWBIE_PROTECTION) { loserChange = Math.round(loserChange * NEWBIE_LOSE_RATE); } // 封顶限制 winnerChange = Math.min(winnerChange, MAX_CHANGE); loserChange = Math.max(loserChange, -MAX_CHANGE); return { winnerChange, loserChange }; } /** * 检查挑战赛冷却期 * @param {Date} lastMatchTime - 上次比赛时间 * @returns {boolean} 是否可以挑战 */ static canChallenge(lastMatchTime) { if (!lastMatchTime) return true; const cooldownDays = POWER_CALC.CHALLENGE_COOLDOWN; const cooldownMs = cooldownDays * 24 * 60 * 60 * 1000; const timeDiff = Date.now() - new Date(lastMatchTime).getTime(); return timeDiff >= cooldownMs; } /** * 获取冷却剩余天数 * @param {Date} lastMatchTime - 上次比赛时间 * @returns {number} 剩余天数 */ static getCooldownDays(lastMatchTime) { if (!lastMatchTime) return 0; const cooldownDays = POWER_CALC.CHALLENGE_COOLDOWN; const cooldownMs = cooldownDays * 24 * 60 * 60 * 1000; const timeDiff = Date.now() - new Date(lastMatchTime).getTime(); if (timeDiff >= cooldownMs) return 0; return Math.ceil((cooldownMs - timeDiff) / (24 * 60 * 60 * 1000)); } /** * 判断升降级(排位赛结束后) * 规则: * - 只有冠军晋级(+1 段位,最高不超过 5 段) * - 只有最后一名且当前段位为 4 或 5 时降级(-1 段位) * @param {number} rank - 排名 (1-based) * @param {number} totalPlayers - 总人数 * @returns {string} 'promote' | 'demote' | 'stay' */ static determinePromotion(rank, totalPlayers) { if (rank === 1) { return 'promote'; // 仅冠军晋级 } if (rank === totalPlayers) { return 'demote'; // 仅最后一名有降级资格(具体是否降,看段位) } return 'stay'; // 其它名次保持不变 } /** * 计算消费积分 * @param {number} amount - 消费金额 * @returns {number} 积分 */ static calculateConsumePoints(amount) { return Math.floor(amount / 10); } } module.exports = PowerCalculator;