Reputation:
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
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
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
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
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
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
Reputation: 86651
The Fisher Yates Shuffle is rapidly becoming my goto answer for everything on Stackoverflow.
You should do the following:
0 <= r0 < 42
1 <= r1 < 42
2 <= r2 < 42
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