2

编辑:这是一个不同的问题,如何在 Java 中生成特定范围内的随机整数?因为我要求解决方案使用方法

public int getRandomNumber(int start,int end)
{
int normal = Greenfoot.getRandomNumber(end-start+1);
return normal+start;
}

getRandomNumber(int, int)

下午好。我一直在用 Java 开发 Greenfoot 的一个项目,其中主角在 7x7 屏幕上,有 3 个硬币。我写了这段代码:

public class FirstLevel extends World
{
public int getRandomNumber(int start,int end)
{
   int normal = Greenfoot.getRandomNumber(end-start+1);
   return normal+start;
}

/**
 * Constructor for objects of class FirstLevel.
 * 
 */
public FirstLevel()
{    
    // Create a new world with 600x400 cells with a cell size of 1x1 pixels.
    super(9, 9, 60); 
    MainCharacter theDuckDude = new MainCharacter ();
   addObject(theDuckDude, 4, 4);
    coin coin1 = new coin();
    coin coin2 = new coin();
    coin coin3 = new coin();
   addObject(coin1, getRandomNumber(1, 7), getRandomNumber(1, 7));
   addObject(coin2, getRandomNumber(1, 7), getRandomNumber(1, 7));
   addObject(coin3, getRandomNumber(1, 7), getRandomNumber(1, 7));
}
}

因此,如您所见,三个硬币和鸭子角色将随机出现在屏幕上。这是我的 theDuckDude 角色的代码片段:

Actor actor = getOneIntersectingObject(coin.class);
getWorld().removeObject(actor);

显然,这段代码显示当我的 theDuckDude 角色接触到硬币演员时,硬币被移除。正如你可能已经看到的,这带来了一个相当大的问题:如果 theDuckDude 和硬币演员在同一个方格上生成,游戏将无法正常运行: 在此处输入图像描述

那么,有没有一种方法可以生成这些随机整数,使用

public int getRandomNumber(int start,int end)
{
   int normal = Greenfoot.getRandomNumber(end-start+1);
   return normal+start;
}

getRandomNumber(1, 7)

方法,如何使它生成一个随机位置,将5 和 5 一起排除?

4

4 回答 4

3

有 49 个可见方块,但有 48 个有效方块。选择一个从 0 到 47 的整数(包括 0 到 47),加 1 以排除中间的正方形,然后从中推导出xy

static final int ROWS = 7;
static final int COLS = 7;
static final int EXCLUDE_X = 5;
static final int EXCLUDE_Y = 5;

int index = ThreadLocalRandom.current().nextInt(ROWS * COLS - 1); // range: [0, 47]
if (index >= ((EXCLUDE_Y * ROWS) + EXCLUDE_X)) {        // offset the center square
  index++;
}
int x = (index % COLS);
int y = (index / ROWS);

我在这里坚持使用 ThreadLocalRandom,但您可以轻松地改写相同的内容以使用您的 Greenfoot 助手。

于 2017-03-08T18:55:09.337 回答
2

基本上有两种方法,真的。

简单的方法是,您选择两个随机整数。如果你击中了duckDude的位置,你再选。再一次,直到你得到一个不同的位置:

    int x;
    int y;
    do {
        x = getRandomNumber(1, 7);
        y = getRandomNumber(1, 7);
    } while (x == duckDudeX && y == duckDudeY);
    addObject(character, x, y);

有用。不太令人满意的是,即使它最终会终止,我们也不知道它所需要的迭代次数的上限。

另一种选择是您在选择方块时已经排除了禁止方块。这也是其他几个答案的基本思想。我的版本使用一个有效的方坐标列表,所以它需要一些初始化:

List<Pair> validPairs = new ArrayList<>(49);

    for (int x = 1; x <= 7; x++) {
        for (int y = 1; y <= 7; y++) {
            validPairs.add(new Pair(x, y));
        }
    }
    validPairs.remove(new Pair(duckDudeX, duckDudeY));

现在选择硬币的正方形很简单:

    Pair where = validPairs.get(getRandomNumber(0, validPairs.size() - 1));
    addObject(character, where.getX(), where.getY());

但是,辅助Pair类会在您的项目中添加一些行:

public class Pair {
    private int x;
    private int y;

    public Pair(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Pair other = (Pair) obj;
        if (x != other.x)
            return false;
        if (y != other.y)
            return false;
        return true;
    }

}

编辑:我希望你自己填写缺失的部分,如果有任何不符合你的代码的地方,也可以纠正。在我的代码中,我有:

static final int duckDudeX = 4;
static final int duckDudeY = 4;

从您的问题和代码中不清楚 (4, 4) 或 (5, 5) 是否是禁区。您当然可以在我的代码中填写 4 或 5duckDudeXduckDudeY. 如果是我的代码,我会坚持声明变量或常量。您最清楚常量是否合适,并且您可能还可以找到更好的名称。

于 2017-03-08T19:28:15.253 回答
0

如果我理解正确,位置 5,5 只是一个示例,您正在寻找一种在给定范围内生成不同随机数的算法。

通常,您会事先对一组索引进行洗牌,然后一个接一个地检索洗牌后的索引。但是,如果您想在两者之间手动选择索引,这将不起作用(例如:生成随机硬币 -> 移除特定硬币 -> 生成另一个随机硬币)。

解决这个问题的方法是实现 Fisher-Yates shuffle 算法的替代版本:

static void shuffle(int[] ar) {         
    Random rnd = ThreadLocalRandom.current();
    for (int i = ar.length - 1; i > 0; i--){
        int index = rnd.nextInt(i + 1);

        int a = ar[index];
        ar[index] = ar[i];
        ar[i] = a;
    }
}

正如你所看到的,一旦一个数组项被打乱到数组的末尾,它就不会再改变它的位置了。因此,我们可以删除循环并一一检索打乱的项目或索引,而不是得到相同的结果:

public class Shuffler { 
    private final int indexCount;
    private final int[] indexes;
    private final int[] indexIndexes;
    private int nextIndexI; 

    public Shuffler(int indexCount){
        this.indexCount = indexCount;
        indexes = new int[indexCount];
        indexIndexes = new int[indexCount];
        for(int i = 0; i < indexCount; i++){
            indexes[i] = i;
            indexIndexes[i] = i;
        }
        nextIndexI = indexCount - 1;
    }

    public int nextIndex(){         
        if(nextIndexI == -1){
            return -1;
        }

        Random rnd = ThreadLocalRandom.current();       
        int i = rnd.nextInt(nextIndexI + 1);

        swap(i, nextIndexI);

        return indexes[nextIndexI--];       
    }

    public boolean pickIndex(int index){        
        if(0 > index || index >= indexCount || indexIndexes[index] > nextIndexI){
            return false;
        }

        swap(indexIndexes[index], nextIndexI);      
        nextIndexI--;

        return true;        
    }

    public boolean reinsertIndex(int index){        
        if(0 > index || index >= indexCount || indexIndexes[index] <= nextIndexI){
            return false;
        }

        nextIndexI++;       
        swap(indexIndexes[index], nextIndexI);  

        return true;    
    }

    private void swap(int i1, int i2){
        indexIndexes[indexes[i1]] = i2;
        indexIndexes[indexes[i2]] = i1;

        int tmp = indexes[i1];
        indexes[i1] = indexes[i2];
        indexes[i2] = tmp;  
    }

} 

此修改提供了引入一种方法的机会,该方法使用户能够在两者之间选择和重新插入特定索引(indexIndexes这两种方法都使用辅助数组,并且可以快速查找实际索引)。

使用洗牌器很容易:

//demo
static final int ROWS = 7;
static final int COLS = 7;

Shuffler shuffler = new Shuffler(ROWS*COLS);        
for(int i = 0; i < ROWS*COLS; i++){
    int index = shuffler.nextIndex();
    int x = index % COLS;
    int y = index / ROWS;
    System.out.println(x + " " + y);
}

您当然可以替换以下行:

Random rnd = ThreadLocalRandom.current();       
int i = rnd.nextInt(nextIndexI + 1);

用你自己的getRandomNumber()方法。

于 2017-03-08T21:04:33.040 回答
0

这个问题的答案很简单,但要小心!你错过了一些东西。观察下面的代码。

public class FirstLevel extends World
{
public int getRandomNumber(int start,int end)
{
   int normal = Greenfoot.getRandomNumber(end-start+1);
   return normal+start;
}

public FirstLevel()
{    

    super(9, 9, 60); 
    int coin1x = 0;
    int coin2x = 0;
    int coin3x = 0;
    int coin1y = 0;
    int coin2y = 0;
    int coin3y = 0;
    MainCharacter theDuckDude = new MainCharacter ();
   addObject(theDuckDude, 4, 4);
    coin coin1 = new coin();
    coin coin2 = new coin();
    coin coin3 = new coin();
coin1x = getRandomNumber(1, 9);
coin1y = getRandomNumber(1, 9);
coin2x = getRandomNumber(1, 9);
coin2y = getRandomNumber(1, 9);
coin3x = getRandomNumber(1, 9);
coin3y = getRandomNumber(1, 9);

while (coin1x == 4 && coin1y == 4)
{
    coin1x = getRandomNumber(1, 9);
    coin1y = getRandomNumber(1, 9);

}
while (coin2x == 4 && coin2y == 4)
{
    coin2x = getRandomNumber(1, 9);
    coin2y = getRandomNumber(1, 9);
    while (coin2y == coin1y && coin2x == coin1x);
    { coin2x = getRandomNumber(1, 9);
      coin2y = getRandomNumber(1, 9);
    }
    while (coin2y == coin3y && coin2x == coin3x);
    {
        coin2x = getRandomNumber(1, 9);
        coin2y = getRandomNumber(1, 9);
    }
    while (coin1x == coin3x && coin1y == coin3y);
    {
        coin3x = getRandomNumber(1, 9);
        coin3y = getRandomNumber(1, 0);
    }
}
while (coin3x == 4 && coin3y == 4)
{
    coin3x = getRandomNumber(1, 9);
    coin3y = getRandomNumber(1, 9);
}


int x;
int y;
addObject(coin1, coin1x, coin1y);
   addObject(coin2, coin2x, coin2y);
   addObject(coin3, coin3x, coin3y);

请注意,此代码有两个您错过的新内容。首先,此代码将检查硬币是否放置在 4、4 方格上:

while (coin1x == 4 && coin1y == 4)
{
coin1x = getRandomNumber(1, 9);
coin1y = getRandomNumber(1, 9);

}

但也要注意代码将检查两个硬币是否在同一个正方形上:

while (coin2y == coin1y && coin2x == coin1x);
{ coin2x = getRandomNumber(1, 9);
  coin2y = getRandomNumber(1, 9);
}
于 2017-03-09T06:59:33.147 回答