基于游戏难度动态调整Elixir结构体概率属性并随机选房
动态调整Sandbox随机选房概率的重构方案
原来的代码把概率区间写死在结构体里,每次调整概率都要手动计算区间范围,确实维护成本很高。咱们可以改成基于权重+动态系数的方案,既能根据外部指标(比如游戏难度)灵活调整概率,又能大幅降低维护成本。
改造思路
- 把固定的
chance区间换成base_weight(基础权重),用权重比例来表示默认概率,比区间更直观 - 新增难度对应的权重调整系数,根据外部传入的难度动态缩放每个Sandbox的权重
- 实现基于权重的随机选择逻辑,替代原来的区间匹配,支持任意权重值
完整改造代码
defmodule Sandbox do defstruct description: nil, base_weight: nil # 定义所有Sandbox的基础权重,对应原来的概率比例(比如40对应原来40%的概率) def all, do: [ %Sandbox{description: "Description 1", base_weight: 40}, %Sandbox{description: "Description 2", base_weight: 20}, %Sandbox{description: "Description 3", base_weight: 40}, ] # 定义不同难度下的权重调整系数,你可以根据实际需求自由修改 # 这里假设三个Sandbox分别对应「简单」「中等」「困难」类型的房间 defp difficulty_multipliers(:easy), do: %{1 => 1.5, 2 => 1.0, 3 => 0.5} defp difficulty_multipliers(:medium), do: %{1 => 1.0, 2 => 1.0, 3 => 1.0} defp difficulty_multipliers(:hard), do: %{1 => 0.5, 2 => 1.0, 3 => 1.5} # 新增带难度参数的随机选择函数,默认中等难度 def random(difficulty \\ :medium) do all() # 给每个Sandbox绑定索引,对应难度系数的key |> Enum.with_index(1) # 计算最终权重:基础权重 × 难度调整系数 |> Enum.map(fn {sandbox, idx} -> multiplier = difficulty_multipliers(difficulty)[idx] %{sandbox | base_weight: sandbox.base_weight * multiplier} end) # 调用基于权重的随机选择逻辑 |> weighted_random() end # 核心:基于权重的随机实现 defp weighted_random(sandboxes) do total_weight = Enum.reduce(sandboxes, 0, fn sb, acc -> acc + sb.base_weight end) rand = :rand.uniform() * total_weight # 累加权重找到随机数对应的Sandbox Enum.reduce_while(sandboxes, 0, fn sb, current_sum -> new_sum = current_sum + sb.base_weight if rand <= new_sum, do: {:halt, sb}, else: {:cont, new_sum} end) end end
怎么用?
# 简单模式:更容易选中「Description 1」(简单房间) Sandbox.random(:easy) # 困难模式:更容易选中「Description 3」(困难房间) Sandbox.random(:hard) # 默认中等模式:和原来的概率完全一致 Sandbox.random()
方案优势
- 维护成本低:要调整概率只需要修改
difficulty_multipliers里的系数,或者修改base_weight,再也不用手动计算区间范围 - 扩展性强:不止支持游戏难度,还可以根据玩家等级、胜率等任意外部指标调整权重,只需要扩展系数生成逻辑
- 灵活性高:权重可以是任意正数,不需要局限在1-100的区间,计算逻辑更简单
内容的提问来源于stack exchange,提问作者RdnCdn
相关产品推荐
相关产品推荐

