如何将JavaScript胜率计算循环代码转为高效Python代码?
问题:优化英雄胜率计算的Python代码性能
我编写了一段JavaScript代码,用于计算英雄与敌人的胜率——遍历双方能力值±10%区间内的所有整数,统计英雄能力值≥敌人的次数占总次数的比例。但将其转为Python(纯循环+Numpy实现)后,效率远不如JS版本。输入的HERO_POWER和ENEMY_POWER范围在100000-300000之间,希望优化Python代码,使其执行效率接近原JS代码。
原JavaScript代码(winchance.js)
function combat_simulate(char_power, enemy_power) { var h = 0 var g = 0 var i = char_power var l = i * 0.9 var u = enemy_power * 1.1 var d = enemy_power * 0.9 for (let e = Math.floor(l); e <= i; e++) for (let t = Math.floor(d); t <= u; t++) e >= t ? h++ : g++ var z = h / (h + g) * 100; return z } var out = combat_simulate(parseInt(arguments[2]), parseInt(arguments[3])) console.log(out)
原Python实现及测试结果
import subprocess, itertools, math, time import numpy as np def calc_iter(array): w=0 l=0 for x,y in array: if x >= y: w +=1 else: l +=1 return w,l ### 输入参数 ### HERO_POWER=120000 ENEMY_POWER=110000 w=0 l=0 h_l = HERO_POWER * 0.9 e_h = ENEMY_POWER * 1.1 e_l = ENEMY_POWER * 0.9 # 修正:np.arange左闭右开,需+1匹配JS的<=逻辑 hp = np.arange(math.floor(h_l), math.floor(HERO_POWER) + 1) ep = np.arange(math.floor(e_l), math.floor(e_h) + 1) print('process using itertools') start_time = time.time() array = itertools.product(hp, ep) w,l = calc_iter(array) print('win rate:{}%'.format(round((w/(w+l))*100,2))) end_time = time.time() print('time elapsed', end_time-start_time) print() print('process using numpy') start_time = time.time() x,y = np.meshgrid(hp, ep) n = x >= y # 修正:匹配JS的e>=t逻辑 w,l = (np.count_nonzero(n), np.count_nonzero(n==0)) print('win rate:{}%'.format(round((w/(w+l))*100,2))) end_time = time.time() print('time elapsed', end_time-start_time) print() print('process using nodejs') start_time = time.time() result = subprocess.run('node winchance.js {} {}'.format(HERO_POWER, ENEMY_POWER), capture_output=True, text=True) print('win rate:{}%'.format(round(float(result.stdout),2))) end_time = time.time() print('time elapsed', end_time-start_time)
测试结果
process using itertools
win rate:68.18%
time elapsed 30.484147787094116process using numpy
win rate:68.18%
time elapsed 2.0294463634490967process using nodejs
win rate:68.18%
time elapsed 0.799668550491333
优化方案:数学公式直接计算
遍历所有组合的本质是统计二维矩形区域内满足x≥y的点的数量,完全可以通过几何分段求和直接计算结果,无需循环或生成数组,时间复杂度降至O(1),效率远超JS版本。
优化后的Python代码
import math, time def calculate_win_rate(hero_power, enemy_power): # 英雄能力值区间:[h_low, h_high] h_low = math.floor(hero_power * 0.9) h_high = hero_power h_count = h_high - h_low + 1 # 敌人能力值区间:[e_low, e_high] e_low = math.floor(enemy_power * 0.9) e_high = math.floor(enemy_power * 1.1) e_count = e_high - e_low + 1 total = h_count * e_count win = 0 # 情况1:英雄最小值 >= 敌人最大值,全赢 if h_low >= e_high: win = total # 情况2:英雄最大值 < 敌人最小值,全输 elif h_high < e_low: win = 0 else: # 分段计算满足x≥y的数量 # 段1:e_low ≤ x ≤ e_high,对应获胜数为等差数列求和 b_start = max(h_low, e_low) b_end = min(h_high, e_high) if b_start <= b_end: b_item_count = b_end - b_start + 1 first_win = b_start - e_low + 1 last_win = b_end - e_low + 1 win += (first_win + last_win) * b_item_count // 2 # 段2:x > e_high,每个x对应全部敌人都能赢 c_start = max(h_low, e_high + 1) if c_start <= h_high: c_item_count = h_high - c_start + 1 win += c_item_count * e_count return (win / total) * 100 # 测试 HERO_POWER=120000 ENEMY_POWER=110000 start_time = time.time() win_rate = calculate_win_rate(HERO_POWER, ENEMY_POWER) print('win rate:{}%'.format(round(win_rate, 2))) end_time = time.time() print('time elapsed', end_time - start_time)
优化后测试效果
运行这段代码,耗时通常在0.0001秒以内,彻底解决了大数值下的效率问题,且结果与原代码完全一致。
优化原理
通过分析二维区间的重叠关系,将英雄能力值分为三段分别计算获胜次数:
- 英雄值完全大于敌人最大值:直接取总次数为获胜数
- 英雄值完全小于敌人最小值:获胜数为0
- 区间重叠部分:用等差数列求和计算每个英雄值对应的获胜敌人数量,再累加
这种方法无需生成任何数组或遍历组合,计算时间与输入数值大小无关,性能远超循环实现。
内容的提问来源于stack exchange,提问作者Skulty
相关产品推荐
相关产品推荐

