Java:在固定范围内生成随机数,但不包括指定数字

4
在我的(Java Android)游戏中,我会在随机位置生成硬币。这些硬币可以出现在屏幕横向的 6 个位置之一(每个水平级别最多 2 个)。我创建了一个介于 0 和 5 之间的随机数来生成第一个硬币,然后我想要生成另一个随机数,但排除第一个硬币的位置。例如,硬币 1 生成在 0 到 5 之间的随机位置 - 假设是 4。接下来的硬币需要能够在 0-3 或 5 之间选择(基本上是 0-5 排除 4)。我已经实现了它,但它并不太优雅,我确定肯定有更好/更清晰的方法来实现此目的,但我还没想到。下面的代码中,random(int number)方法仅返回从 0 到 number-1 的随机 int(使用 nextInt),而 randomBool()仅返回随机 boolean。请注意,我不想使用任何技术,如果产生的随机数等于我们要避免的随机数,则不断重新生成随机数。
    //Return a random number between 0 and 5 excluding the specified number
    private int getRandomExcluding(int excludedNumber){

        //If previous position was 0 then generate a number between 1 and 5
        if (excludedNumber==0){
                return random(5)+1;
        }
        //If position was 5, then generate and return number from 0-4
        else if (excludedNumber==5){
                return random(5);
        }

        //If number isn't 0 or 5 (then it is in range of 1-4 use a random bool to determine
        // if we are going to get a number less than or greater than the number we are excluding

        //True - get number lower than excluded number
        else if(randomBool()){

            //Excluded number is 1
            if (excludedNumber==1){
                return 0;  //Only posibility
            }

            //Excluded number is > 1
            else {
                //Return a random number between 0 (inclusive) and the excluded number (exclusive)
                return random(excludedNumber);
                }

        //False - get number higher than the excluded number (between exludedNumber+1 (inclusive) and 6(exlusive))
        else {
                return random(6-(excludedNumber+1))+(excludedNumber+1);
        }
    }

1
使用一组可能的值,每次选择一个后将其删除。 - Dave Newton
3
一种方法是将一个列表填满有效值,然后对其进行混洗,并返回前两个元素。 - assylias
我喜欢这个想法,我猜这会以长度为5的数组形式呈现,再加上一个排除数字的开关,该开关将用相关值填充数组(例如,case 0将用1,2,3,4和5填充,case 1将用0,2,3,4和5填充等等),然后只需生成0到5之间的随机数并前往该索引以检索值?!如果有比我的解释更好的方法,请将您的想法发布为答案?!谢谢!!! - Zippy
3个回答

6

您可以创建一个列表并对其进行洗牌:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Collections.shuffle(numbers);
int coin1 = numbers.get(0);
int coin2 = numbers.get(1);

3
为了获得最佳的分布效果,你可能希望使用shuffle(numbers, new SecureRandom),这对于游戏通常非常重要。 - Maarten Bodewes

1
尝试这个解决方案:

private int getRandomExcluding(int excludedNumber){
    int num = random(5);
    return num >= excludedNumber ? num+1 : num;
}

它仅从0到4生成随机数,并且如果大于或等于被排除的数字,则会将其加1。这样,所有五个可能的数字都均匀地分布(如果您的RNG生成均匀分布的数字)。

1
这段代码存在多个问题:可能会超出范围,而且不是迭代的。更好的解决方案是使用一组可能的值。 - Dave Newton
在哪个范围内?为什么它应该是迭代的?问题中没有提到迭代性 - Tagir Valeev
2
我错过了“仅限两个数字”的部分,尽管我害怕魔法数字。我认为解决方案实际上是有效的,因为你只生成0-4,所以请原谅。然而,我不认为它特别随机,因为你总是在增加。我认为规范化的解决方案(洗牌或集合)仍然更好,更适合通用性。 - Dave Newton

0
解决方案:(如果您更喜欢这种类型的输入,可以将List<Integer> excludes更改为int... excludes
    /**
     * Get a random number between a range and exclude some numbers
     *
     * @param start start number
     * @param end end number
     * @param excludes list of numbers to be excluded
     * @return value between {@code start} (inclusive) and {@code end} (inclusive)
     */
    private int getRandomWithExclusion(int start, int end, List<Integer> excludes) {
        Collections.sort(excludes); // this method only works with sorted excludes

        int random = start + new Random().nextInt(end - start + 1 - excludes.size());
        for (int exclude : excludes) {
            if (random < exclude) {
                break;
            }
            random++;
        }
        return random;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接