Как сделать 2 случайных целых числа от 1 до 7, не будучи 5?
РЕДАКТИРОВАТЬ: Это другой вопрос, как Как генерировать случайные целые числа в определенном диапазоне в Java? потому что я просил решение использует методы
public int getRandomNumber(int start,int end)
{
int normal = Greenfoot.getRandomNumber(end-start+1);
return normal+start;
}
а также
getRandomNumber(int, int)
Добрый день. Я работал над проектом в Greenfoot с Java, где главный герой находится на экране 7х7 с 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 касается актера монеты, монета удаляется. Как вы, вероятно, видели, это создает серьезную проблему: если DuckDude и субъект с монетами генерируются на одном квадрате, игра не будет работать должным образом:
Итак, есть ли способ, которым я могу генерировать эти случайные целые, используя
public int getRandomNumber(int start,int end)
{
int normal = Greenfoot.getRandomNumber(end-start+1);
return normal+start;
}
а также
getRandomNumber(1, 7)
методы, как я могу заставить его генерировать случайное местоположение, которое исключает 5 и 5 вместе?
4 ответа
Есть 49 видимых квадратов, но 48 действительных квадратов. Выберите целое число от 0 до 47 включительно, добавьте 1, чтобы исключить средний квадрат, а затем выведите x
а также y
оттуда.
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.
Есть два основных способа.
Простой способ, вы выбираете два случайных целых числа. Если вы попали в положение 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 или 5, где мой код говорит duckDudeX
или же duckDudeY
, Если бы это был мой код, я бы настаивал на объявлении переменных или констант. Вы лучше знаете, подходят ли константы, и, возможно, вы также можете найти более подходящие имена.
Если я вас правильно понимаю, позиция 5,5 - это просто пример, и вы ищете алгоритм, который генерирует различные случайные числа в заданном диапазоне.
Обычно вы заранее перемешиваете массив индексов, а затем извлекаете перемешанные индексы один за другим. Однако, если вы хотите выбрать индексы вручную между ними, это не сработает (например: сгенерировать случайную монету -> удалить конкретную монету -> сгенерировать другую случайную монету).
Решением этой проблемы является реализация альтернативной версии алгоритма тасования Фишера-Йейтса:
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
используется этими двумя методами и делает возможным быстрый поиск фактических индексов).
Использовать shuffler легко:
//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()
метод.
Ответ на этот вопрос довольно прост, но будьте осторожны! Есть кое-что, что вы пропустили. Соблюдайте код ниже.
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);
}