C#为按钮随机分配位置时避免随机输出重复的更高效实现方法?
现有代码的隐藏问题
你贴的代码存在一处书写bug:生成location3的while循环中,你错误给location2重新赋值,而非修改location3,会导致location3永远停留在初始随机值,运气不好时会触发无限死循环,需要先修正该问题。
更高效的防重复实现方案
你现在用的循环重试法只适合极少数量的随机值场景,值越多重试概率越高、性能越低,还容易写出死循环bug,推荐用下面两种更稳定的方案:
方案1:Fisher-Yates 洗牌算法(扩展性最优,推荐)
原理是先把所有可用的位置索引放到集合中,直接打乱集合顺序,之后按打乱后的顺序依次取值即可,完全不会出现重复值,也没有重试开销:
Random r = new Random(); // 生成0、1、2三个可用位置索引 int[] locations = Enumerable.Range(0, 3).ToArray(); // 洗牌算法打乱数组顺序 for (int i = locations.Length - 1; i > 0; i--) { int j = r.Next(i + 1); (locations[i], locations[j]) = (locations[j], locations[i]); } // 按打乱后的顺序分配位置即可 btnCorrect.Location = new Point(xCoordinates[locations[0]], positionY); btnIncorrect1.Location = new Point(xCoordinates[locations[1]], positionY); btnIncorrect2.Location = new Point(xCoordinates[locations[2]], positionY);
这个方案后续新增按钮不需要修改逻辑,只要调整索引生成范围、新增对应赋值语句即可,维护成本很低。
方案2:随机取值后移除(新手友好,适合少量元素)
如果觉得洗牌算法不好理解,可以把可用索引放到列表里,每次随机取一个下标后就把该值从列表中移除,天然避免重复取值:
Random r = new Random(); List<int> availableLocations = Enumerable.Range(0, 3).ToList(); // 分配正确按钮位置 int selectIdx = r.Next(availableLocations.Count); btnCorrect.Location = new Point(xCoordinates[availableLocations[selectIdx]], positionY); availableLocations.RemoveAt(selectIdx); // 分配第一个错误按钮位置 selectIdx = r.Next(availableLocations.Count); btnIncorrect1.Location = new Point(xCoordinates[availableLocations[selectIdx]], positionY); availableLocations.RemoveAt(selectIdx); // 分配第二个错误按钮位置 btnIncorrect2.Location = new Point(xCoordinates[availableLocations[0]], positionY);
这个方案逻辑非常直白,不容易写出bug,适合入门阶段使用。
内容的提问来源于stack exchange,提问作者carp200
相关产品推荐
相关产品推荐

