如何为Geocaching游戏按Quest生成具有不同均值的随机数?
问题描述
我需要为Geocaching游戏生成随机数据,现有包含QuestId、StageId和测量值的QuestMeasurement列表。当前生成的随机数各Quest的均值均接近范围中位数,希望实现每个Quest在指定大范围内生成属于自己的随机子区间的随机数。
现有生成随机数的代码如下:
public static int getValueForMeasurementType(String measurementType) { Random random = new Random(); return switch (measurementType) { case HARTSLAG -> (int) (random.nextDouble() * (125 - 60 + 1) + 60) ; case ZWEETNIVEAU -> (int) (random.nextDouble() * 101); case GELUID -> (int) (random.nextDouble() * (100 - 30 + 1) + 30); default -> 0; }; }
当前各Quest的HARTSLAG均值(可见都接近60-125的中位数92.5左右):
Average HARTSLAG for quest 06541BCC50F2451EA5088464E6A6CD9C: 89.41176470588235 Average HARTSLAG for quest 08BC162BBC5A456A8BE9E24E76EEBF79: 95.11764705882354 Average HARTSLAG for quest 082DC01CC9D74CF0AEA7C79EAF616EEE: 89.79411764705883 Average HARTSLAG for quest 096AE1335FD648018A95968AFC8FBB12: 91.3529411764706 Average HARTSLAG for quest 0A5C24368F084608B0506ABB61138218: 92.38235294117646 Average HARTSLAG for quest 0A2934DD6996453E84826F7A703BCBC1: 90.13725490196079 Average HARTSLAG for quest 0870A3CAD0754C3DAFA686D202024A36: 90.02941176470588 Average HARTSLAG for quest 05555A33124D4298820C6E40DDF94B4D: 88.8970588235294
调整方案
要实现每个Quest拥有专属的随机子区间,核心思路是为每个Quest预先分配一个固定的子区间边界(首次调用时生成并缓存),后续该Quest的所有测量值都在这个子区间内生成随机数,具体实现步骤如下:
1. 扩展函数参数,传入QuestId
原函数仅接收测量类型,需新增questId参数用于区分不同Quest,以此为依据分配专属子区间。
2. 缓存每个Quest的子区间边界
使用Map存储每个Quest对应各测量类型的子区间上下限,确保同一Quest的子区间固定,不会每次调用都重新生成,保证该Quest的测量值均值稳定在子区间范围内。
3. 为每个Quest生成专属子区间
首次处理某个Quest的某类测量值时,在全局范围内随机生成合法的子区间上下限(保证下限≤上限),后续该Quest的此类测量值均在此子区间内生成随机数。
修改后的代码示例
import java.util.HashMap; import java.util.Map; import java.util.Random; public class MeasurementGenerator { // 缓存每个Quest对应各测量类型的子区间:key为"QuestId_MeasurementType",value为int[]{min, max} private static final Map<String, int[]> QUEST_SUBINTERVALS = new HashMap<>(); private static final Random RANDOM = new Random(); // 定义各测量类型的全局范围常量,便于维护 private static final int HARTSLAG_MIN = 60; private static final int HARTSLAG_MAX = 125; private static final int ZWEETNIVEAU_MIN = 0; private static final int ZWEETNIVEAU_MAX = 100; private static final int GELUID_MIN = 30; private static final int GELUID_MAX = 100; public static int getValueForQuestMeasurement(String questId, String measurementType) { String cacheKey = questId + "_" + measurementType; int[] subInterval = QUEST_SUBINTERVALS.get(cacheKey); // 若该Quest的此测量类型无缓存子区间,随机生成并缓存 if (subInterval == null) { subInterval = generateSubInterval(measurementType); QUEST_SUBINTERVALS.put(cacheKey, subInterval); } // 在子区间内生成包含上下限的随机整数 int min = subInterval[0]; int max = subInterval[1]; return RANDOM.nextInt(max - min + 1) + min; } private static int[] generateSubInterval(String measurementType) { int globalMin, globalMax; switch (measurementType) { case "HARTSLAG": globalMin = HARTSLAG_MIN; globalMax = HARTSLAG_MAX; break; case "ZWEETNIVEAU": globalMin = ZWEETNIVEAU_MIN; globalMax = ZWEETNIVEAU_MAX; break; case "GELUID": globalMin = GELUID_MIN; globalMax = GELUID_MAX; break; default: return new int[]{0, 0}; } // 先随机子区间下限,再生成不小于下限的上限,保证子区间有效 int subMin = RANDOM.nextInt(globalMax - globalMin + 1) + globalMin; int subMax = RANDOM.nextInt(globalMax - subMin + 1) + subMin; return new int[]{subMin, subMax}; } }
代码说明
- 缓存机制:通过
QUEST_SUBINTERVALS确保同一Quest的测量值始终在固定子区间内,避免所有Quest的均值都趋同于全局范围中位数。 - 子区间生成逻辑:先随机子区间下限,再生成不小于下限的上限,保证子区间的合法性和随机性。
- 全局常量定义:将各测量类型的范围抽离为常量,后续修改范围时无需改动核心逻辑,提升可维护性。
调整后,每个Quest的测量值会集中在自己的专属子区间内,不同Quest的均值会拉开明显差距,满足需求。
内容的提问来源于stack exchange,提问作者Mendi Sterenfeld
相关产品推荐
相关产品推荐

