4

In my (Java Android) game, I spawn coins at random positions.

Coins can appear at one of 6 positions horizontally across the screen (2 max per horizontal level).

What I do is create a random number between 0 and 5 for the first coin, then I want generate another random number excluding the position of the first coin.

So, for example, coin 1 is spawned at a random position between 0 and 5 - so let's say 4.

Then the next coin needs to be able to choose between 0-3 or 5. (basically 0-5 excluding 4).

I have managed to do it, but it's not very elegant and I'm sure there must be a better/cleaner way to achieve this, however, it escapes me.

The random(int number) method in the code below simply returns a random int from 0 to number-1 (uses nextInt) and randomBool() just returns a random boolean

Also, please bear in mind that I don't want to use any technique that keeps re-generating a random number if the one it produces is equal to the one we are trying to avoid.

code

 //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);
 }
 }
asked May 31, 2015 at 14:57
3
  • 1
    Use a set of possible values, removing each as it's selected. Commented May 31, 2015 at 15:01
  • 3
    One way is to fill a list with the valid values, shuffle it, and return the first two elements. Commented May 31, 2015 at 15:01
  • I like this idea, I'm guessing this would be in the form of an array of length 5 and maybe a switch on excludedNumber, which would populate the array with the relevant values (so, case 0 would populated with 1,2,3,4 & 5, case 1 with 0,2,3,4 & 5 etc), and then just generate a random number between 0 and 5 and go to that index of the array to retrieve the value?! maybe you could post your idea as an answer if there is a better way to put it into action than my interpretation?! Thanks!!!! – Commented May 31, 2015 at 20:18

3 Answers 3

6

You could populate a list and shuffle it:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Collections.shuffle(numbers);
int coin1 = numbers.get(0);
int coin2 = numbers.get(1);
answered May 31, 2015 at 21:30
Sign up to request clarification or add additional context in comments.

1 Comment

You may want to use shuffle(numbers, new SecureRandom) for an optimal distribution, often important for a game.
1

Try this solution:

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

It simply generates the random number from 0 to 4 and if it's great or equal to the excluded number, it adds one. This way all five possible numbers are uniformly distributed (if your RNG produces uniformly distributed numbers).

answered May 31, 2015 at 14:58

3 Comments

... This is broken in multiple ways; it can go out of range, and isn't iterative. A better solution would just use a set of possible values.
Out of which range? And why it should be iterative? There's nothing about iterativeness in the question.
I missed the "only two numbers" part, although I dread magic numbers. I think the solution actually works since you're only generating 0-4, so apologies. I don't think it's particularly random, though, since you always increment. I think the canonical solutions (shuffling or a set) are still better, and better suited for generality.
0

Solution: (you can change List<Integer> excludes to int... excludes if you prefer this type of input)

 /**
 * 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;
 }
answered Jan 13, 2021 at 14:44

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.