user7963567
user7963567

Reputation:

Creating A Lottery Machine

I am having difficulties with a project which is creating a lottery machine that prints 6 numbers between 1 and 42 at random where no 2 numbers are the same. The user must also insert 6 numbers. If any number is the same as the one randomly selected by the computer, the computer must print it. If not, the computer prints you are such a loser. Now, the problem is I'm not sure about how to make sure that no 2 randomly selected numbers are the same. The program should also ask for a different number if a number less than 1, greater than 42, or equal to a previous number inserted, and scan it. (user cannot enter 2 identical numbers) PS: I am only a beginner who knows the for loop while loop and if statement so I would love it if the answers were very simple and basic. Please check my code and tell me if there is anything that doesn't work or is illogical. Thank you in advance

 import java.util.Scanner;
 import java.util.Random;

 public class LotoMachine {

public static void main(String[] args) {

    System.out.println("Please enter 6 numbers between 1 and 42.");
    Scanner scan = new Scanner(System.in);

    int[] marks = new int[6];
    Random ran = new Random();
    int[] x = new int[6];
    boolean winner = false;

    for (int i = 0; i < 6; i++) {
        marks[i] = scan.nextInt();
    }
    for (int j = 0; j < 6; j++) {
        x[j] = ran.nextInt(42) + 1;
        for (int y = 0; y < j; y++) {
            if (x[j] == x[y]) {
                x[j] = ran.nextInt(42) + 1;
                j=0;
            }
        }
    }

    for (int m = 0; m < 6; m++) {
        System.out.println(x[m]);
    }
    for (int i = 0; i < 6; i++) {
        for (int j = 0; j < 6; j++) {
            if (marks[i] == x[j]) {
                winner = true;
                System.out.println("Number(s) that matched: " + marks[i]);
            }
        }
    }
    if (winner != true) {
        System.out.println("You are such a loser");
       }
   }
}

Upvotes: 1

Views: 761

Answers (6)

slim
slim

Reputation: 41223

The easiest and most efficient thing is to put the possible numbers in a List, then remove a random element from the list until you have as many as you need:

 // create a list containing 1 .. 42
 List<Integer> available = new ArrayList<>();
 for(int i=1; i<=42; i++) {
     available.add(i);
 }

 // pull 6 numbers from `available` at random
 List<Integer> picks = new ArrayList<>();
 for(int i=0; i<6; i++) {
     picks.add(available.remove(random.nextInt(available.size());
 }

You can do something similar with arrays, but it's more complicated because you'd have to write your own array equivalent of List.remove(). Perhaps you've not encountered List yet in your studies -- but if you want a simple solution, you need to use the appropriate tools, and lists are easier to use than arrays.


Alternatively, you can just use arrays if you want to make life slightly harder for yourself.

// create an array containing 1..42
int[] available = new int[42];
for(int i=0; i<42;i++) {
    available[i] = i+1;
}

// pull out 6 numbers
int[] picks = new int[6];
int availableSize = 6;
for(i=0; i<6;i++) {
    int r = random.nextInt(availableSize);
    // grab the pick
    picks[i] = available[r];
    // move an unused number over the picked one
    availableSize--;
    available[r] = available[availableSize];
}

Each time we take a number, we reduce availableSize by one, and overwrite the number we've taken from available with an unused one from the top of what's left of the numbers. So for example, at the start (let's go with 6 candidates instead of 42):

available == [1,2,3,4,5,6]
availableSize == 6
r = 3 // for example
picks[0] becomes available[3] == 3
availableSize becomes 5
available becomes [1,2,6,4,5,6]

... but the second 6 in available is irrelevant, because next time around we'll only pick from the first 5 elements.

Upvotes: 0

Viktor Mellgren
Viktor Mellgren

Reputation: 4506

To be a bit more easy for the eye and using modern Java8 streams you could use the Collections API to shuflle to be a bit more clear:

private static Set<Integer> generateXuniqueNumbersFromRange(int unique, int start, int end) {
    List<Integer> availableLotteryNumbers = IntStream.rangeClosed(start, end).boxed().collect(Collectors.toList());
    Collections.shuffle(availableLotteryNumbers);
    Set<Integer> lotteryNumbers = availableLotteryNumbers.stream().limit(unique)
            .collect(Collectors.toCollection(TreeSet::new));
    return lotteryNumbers;
}

//// Rest of the code (also rewritten)

public static void main(String[] args) {
    Set<Integer> lotteryNumbers = generateXuniqueNumbersFromRange(6, 1, 42);

    Set<Integer> userSelection = new TreeSet<>();

    try (Scanner scan = new Scanner(System.in)) {
        while (userSelection.size() < 6) {
            int nextInt = scan.nextInt();
            if (nextInt <= 42 && nextInt >= 1) {
                userSelection.add(nextInt);
            } else {
                System.out.println("Select between 1 - 42");
            }
        }
    }

    System.out.println("You had these numbers " + userSelection);
    System.out.println("The lottery selected " + lotteryNumbers);
    userSelection.retainAll(lotteryNumbers);

    if (userSelection.isEmpty()) {
        System.out.println("You are such a loser");
    } else {
        System.out.println("You had " + userSelection.size() + " correct ones " + userSelection);
    }

}

Upvotes: 0

Westranger
Westranger

Reputation: 1367

There are two different ways how you can solve this. In both you need to make trade of either for using more memory or to perform more computations.

The first one uses more memory but is computationally efficient

int[] numbers = new int[42];
int len = 42;
for (int i = 0; i < 42; i++) {
    numbers[i] = i + 1;
}

for (int i = 0; i < 6; i++) {
    int pos = rng.nextInt(len);
    x[i] = numbers[pos];

    for (int j = pos + 1; j < len; j++) {
        numbers[j - 1] = numbers[j];
    }
    pos--;
}

The second approach is computationally more expensive but memory efficient

int pos = 0;
while (pos < 6) {
    int number = rng.nextInt(42) + 1;
    boolean duplicate = false;
    for (int i = 0; i < pos; i++) {
        if (x[i] == number) {
            duplicate = true;
        }
    }

    if (!duplicate) {
        x[pos++] = number;
    }
}

The first one creates a list of unique number and draw from this list. Afterwards the drawn number is removed form the list. the second approach draw random numbers and checks if the drawn number already exists, if so it is discarded.

Upvotes: 0

Black Flicka
Black Flicka

Reputation: 31

There I fixed it. You had to reset your j to 0 when you find matching numbers AND you can't start from 0 in both for's because then you'll always be comparing the same numbers at index 0.

P.S. Learn while loop

import java.util.Scanner;
import java.util.Random;

 public class LotoMachine {

public static void main(String[] args) {

    System.out.println("Please enter 6 numbers between 1 and 42.");
    Scanner scan = new Scanner(System.in);

    int[] marks = new int[6];
    Random ran = new Random();
    int[] x = new int[6];
    boolean winner = false;

    for (int i = 0; i < 6; i++) {
        marks[i] = scan.nextInt();
    }
    for (int j = 0; j < 6; j++) {
        x[j] = ran.nextInt(42) + 1;
        for (int y = 0; y < j; y++) {
            if (x[j] == x[y]) {
                x[j] = ran.nextInt(42) + 1;
                j=0;
            }
        }
    }

    for (int m = 0; m < 6; m++) {
        System.out.println(x[m]);
    }
    for (int i = 0; i < 6; i++) {
        for (int j = 0; j < 6; j++) {
            if (marks[i] == x[j]) {
                winner = true;
                System.out.println("Number(s) that matched: " + marks[i]);
            }
        }
    }
    if (winner != true) {
        System.out.println("You are such a loser");
       }
   }
}

Upvotes: 0

qry
qry

Reputation: 457

answer from Creating random numbers with no duplicates

The code (for you) is:

Random rng = new Random(); // Ideally just create one instance globally
// Note: use LinkedHashSet to maintain insertion order
Set<Integer> generated = new LinkedHashSet<Integer>();
while (generated.size() < 6) //repeat as long as generated.size() < 6 -> means you dont have 6 unique integers
{
    Integer next = rng.nextInt(42) + 1;
    // As we're adding to a set, this will automatically do a containment        check
generated.add(next);
}
int[] lottery_numbers =  generated.toArray();
//Do want you want to do with the 6 lottery numbers

Upvotes: -1

JeremyP
JeremyP

Reputation: 86651

The Fisher Yates Shuffle is rapidly becoming my goto answer for everything on Stackoverflow.

You should do the following:

  • create an array with the 42 numbers in it in ascending order. The array is indexed between 0 and 41.
  • Generate a random number r0 where 0 <= r0 < 42
  • swap the number at index 0 with the number at index r0.
  • Generate a random number r1 where 1 <= r1 < 42
  • swap the number at index 1 with the number at index r1.
  • Generate a random number r2 where 2 <= r2 < 42
  • swap the number at index 2 with the number at index r2.

and so on until you have swapped the number at index 5. Obviously it is trivial to put the above steps in a loop. Also note that it is not a bug to swap a number with itself.

The first six numbers in your array (indexes 0 through 5) are the selected lottery numbers.

The algorithm can be generalised to select any n unique items from m objects. For instance, having an array of 52 items and going through all 52 is a handy way to model shuffling a pack of cards.

Here's some code to implement the algorithm (I haven't compiled or tested it so there might be mistakes

Random random = new java.util.Random();

int numbers[] = new int[42];

// create the initial array
for (int i = 0 ; i < 42 ; ++i)
{
    numbers[i] = i + 1;
}

// shuffle
for (int i = 0 ; i < 6 ; ++i)  
{
    int ri = random.nextInt(42 - i) + i; // generates a random index between i and 42
    int tmp = numbers[ri];
    numbers[ri] = numbers[i];
   numbers[i] = tmp;
}

// your six lottery numbers are in numbers[0] to numbers[5]

Upvotes: 3

Related Questions