从 Java RNG 的范围中删除一个数字?

Removing a number from a Java RNG's range?

我目前正在使用 Java 的 RNG Random r = new Random(),并让它在 while 循环中生成一个介于 0 和 5 之间的新整数。

while (someBoolean == false) {
        int i = r.nextInt(6);
           ....
 }

我想做的是从范围中删除一个数字(例如 4),以便 RNG 仍然生成一个介于 0 和 5 之间的新数字,不包括其中一个值。

我目前最好的选择如下:

 while (someBoolean == false) {
        int i = r.nextInt(6);
           if (i == removedInt) { continue; }
          ....
 }

但是我担心这会导致我的代码长时间运行,其中 RNG 不断返回我不想要的数字。

[为清楚起见; 返回的数字是 Connect4 网格中的一列,或 2D int 数组。该方法是在列中随机放置移动,直到列填满,此时我不再希望能够在该列中进行游戏。 ]

感谢任何帮助:)

虽然您可以使用 List 枚举您想要生成的数字和 exclude/remove 您想要排除的数字,但这仅对小范围有效。如果要生成大范围内的随机数,这个方案就变得相当低效不可行.

仅使用 1 Random.nextInt() 调用的解决方案

如果您想生成 0..5 范围内的随机数,您可以使用 r.nextInt(6)

如果您想排除一个数字,例如4,这意味着范围小了1,所以使用r.nextInt(5),如果结果是被排除的数字,那么return允许的最大值是5(因为它永远不会生成,因为你使用了 max - 1).

看起来像这样:

// Returns a random number in the range 0..5 (0 and 5 included), 4 excluded
public int nextRand() {
    int i = r.nextInt(5);
    return i == 4 ? 5 : i;
}

一般解决方案

这里有一个通用的解法,以minmax和可排除的数字为参数:

/**
 * Returns a random number in the range min..max both included, but never the excluded.
 */
public int nextRand(int min, int max, int excluded) {
    if (max <= min || excluded < min || excluded > max)
        throw new IllegalArgumentException(
                "Must be: min <= excluded <= max AND min < max");

    int i = min + r.nextInt(max - min);  // r is a java.util.Random instance
    return i == excluded ? max : i;
}

因此,例如,如果您调用 nextRand(0, 5, 3),它只会 return 一个随机数,它是 0, 1, 2, 4, 5 之一。

ArrayList<Integer> myInts = new ArrayList<Integer>();
myInts.add(1);
myInts.add(2);
myInts.add(3);
myInts.add(4);
int i = myInts.get(r.nextInt(myInts.size())); // 1,2,3,4
myInts.remove(3);
int j = myInts.get(r.nextInt(myInts.size())); // 1,2,4

代码从允许的整数列表中选择随机条目。

PS请注意,如果您的数字范围很大,那么创建一个包含成千上万个整数的 ArrayList 可能不是最好的主意。

希望这对您的情况有所帮助。它并没有真正排除任何数字,而是制作 根据随机数赋予它的初始值决定在哪个位置移动。

    //Change these to what you want
    int numberColumns = 7;
    int numberRows = 6;
    /**
    * A way for my snippet to determine what column has a piece in its very top spot.
    */
    boolean[][] hasPiece = new boolean[numberRows][numberColumns];
    /**
    * Get a random number between 0 and numberColumns - 1 and set it equal 
    * to the column you want the computer to place it in.
    */
    int columnToPlace = (int) (0 +Math.random()*numberColumns);
    /**
    * A boolean check to determine what side of the chosen column to check first.
    * This way it doesn't always check to the left or right first.
    */
    if(Math.random() < 0.5){
        //Forwards for loop to start at the initial random number given.
        for(int runner = columnToPlace; runner < numberColumns; runner++){
            if(!hasPiece[0][runner]){/**Check First Row And Next Column To The Right For A Piece.*/
                columnToPlace = runner;/**If there is no piece their set it equal to that number/empty column.*/
                break;/**Break out of the loop*/
            }
        }
    }else{
        //Reversed for loop to start at the initial random number given.
        for(int backwardsRunner = columnToPlace; backwardsRunner > 0; backwardsRunner--){
            if(!hasPiece[0][backwardsRunner]){/**Check First Row And Next Column To The Left For A Piece.*/
                columnToPlace = backwardsRunner;/**If there is no piece their set it equal to that number/empty column.*/
                break;/**Break out of the loop*/
            }
        }
    }
    //The final number/empty column the computer will make it's move in.
    System.out.println(columnToPlace);

使用这种方法,您可能会得到一个不错的 AI,它不仅会随机移动。 这是开始注意 "runner" 循环的好地方。如果你有办法检查它是否 随机列左侧或右侧的计算机部分,您可以添加逻辑 会做出更明智的决定。

您的大脑固执地认为 random() 中的数字必须与您实际用于行或其他内容的数字相同。使用小数组将纯序数与其表示的内容分开:

Vector validColumns = new Vector(6);
for (int i = 0; i < 6; i += 1) { validColumns.add(i); }
. . .
c = validColumns[r.nextInt(validColumns.size())]

在 ... 中,您可以根据需要删除和添加列。