如何为rand_skill列表随机分配skill_points且总和固定,支持tag_list加权?
问题描述
需要将skill_points随机分配给rand_skill列表的元素,确保所有元素之和严格等于skill_points;同时要通过tag_list影响分配权重,让rand_skill中的指定元素更大概率获得较高点数。此前采用循环逐个给随机元素加1的方法,低效且粗糙,寻求更优实现方案。
现有roll_talents函数代码如下:
def roll_talents(skill_points, tag_list): talents = [] # FIGHT talents[0] = 0 + get_attribute_mod(attributes[3]) + get_attribute_mod(attributes[4]) + rand_skill [0] talents[1] = 0 + get_attribute_mod(attributes[4]) + rand_skill [1] talents[2] = 0 + get_attribute_mod(attributes[3]) + rand_skill [2] talents[3] = 0 + get_attribute_mod(attributes[0]) + rand_skill [3] talents[4] = 0 + get_attribute_mod(attributes[5]) + rand_skill [4] talents[5] = 0 + rand_skill [5] # COMMUNIKATION talents[6] = 0 + get_attribute_mod(attributes[2]) + rand_skill [6] talents[7] = 0 + get_attribute_mod(attributes[3]) + rand_skill [7] talents[8] = 0 + get_attribute_mod(attributes[6]) + rand_skill [8] talents[9] = 0 + get_attribute_mod(attributes[1]) + rand_skill [9] # [...] return talents
解决方案
核心思路
采用加权多项式分布实现点数分配:先根据tag_list为目标技能设置更高权重,再基于权重随机分配skill_points,既保证总和恒定,又满足权重偏向需求。
方案1:基于Numpy的高效实现(推荐)
利用Numpy的multinomial函数,底层优化的算法能快速生成符合要求的整数分配结果,适合大点数场景。
- 生成加权权重
import numpy as np def generate_skill_weights(skill_count, tag_list): # 初始化所有技能默认权重为1 weights = np.ones(skill_count) # 为tag_list中的目标技能提升权重(这里设置为3倍,可按需调整) for skill_idx in tag_list: if 0 <= skill_idx < skill_count: weights[skill_idx] *= 3 # 归一化权重为概率分布 return weights / weights.sum()
- 分配技能点数
def allocate_skill_points(skill_points, skill_count, tag_list): weights = generate_skill_weights(skill_count, tag_list) # 生成总和为skill_points的随机分配数组 rand_skill = np.random.multinomial(skill_points, weights) # 转为Python列表适配原有代码 return rand_skill.tolist()
- 整合到原有函数
def roll_talents(skill_points, tag_list): # 确定技能总数,根据现有代码这里暂设为10,需与实际talents数量一致 skill_count = 10 rand_skill = allocate_skill_points(skill_points, skill_count, tag_list) talents = [] # FIGHT模块 talents.append(get_attribute_mod(attributes[3]) + get_attribute_mod(attributes[4]) + rand_skill[0]) talents.append(get_attribute_mod(attributes[4]) + rand_skill[1]) talents.append(get_attribute_mod(attributes[3]) + rand_skill[2]) talents.append(get_attribute_mod(attributes[0]) + rand_skill[3]) talents.append(get_attribute_mod(attributes[5]) + rand_skill[4]) talents.append(rand_skill[5]) # COMMUNIKATION模块 talents.append(get_attribute_mod(attributes[2]) + rand_skill[6]) talents.append(get_attribute_mod(attributes[3]) + rand_skill[7]) talents.append(get_attribute_mod(attributes[6]) + rand_skill[8]) talents.append(get_attribute_mod(attributes[1]) + rand_skill[9]) # [...] 补充其他技能计算逻辑 return talents
方案2:纯Python实现(无依赖)
如果无法引入Numpy,可使用标准库的random.choices实现,通过多次加权选择统计次数完成分配。
import random def allocate_skill_points_pure_python(skill_points, skill_count, tag_list): # 初始化权重列表 weights = [1] * skill_count # 为目标技能提升权重 for skill_idx in tag_list: if 0 <= skill_idx < skill_count: weights[skill_idx] = 3 # 权重倍数可调整 # 随机选择skill_points次技能索引,统计每个技能被选中的次数 selections = random.choices(range(skill_count), weights=weights, k=skill_points) rand_skill = [selections.count(i) for i in range(skill_count)] return rand_skill
方案优势
- 效率远高于逐个加1的循环方法,尤其是当
skill_points数值较大时 - 权重控制精准,标签指定的技能能稳定获得更高的点数分配概率
- 天然保证所有元素之和严格等于
skill_points,无需额外校验
内容的提问来源于stack exchange,提问作者aGuyCalledT
相关产品推荐
相关产品推荐

