4
\$\begingroup\$

I'm extremely new to Java, and I had a bit of an attempt at making something that you could call lotto. I've still got a lot more to go on it, but things are becoming tedious, and I am sure there is a simpler way to do what I am doing. How can this code be changed to have less repetitive code/optimized?

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


public class Lotto {

    //Pick 6 numbers from 1 to 100
    //If all of your numbers gets called out, you win

    public static void wait (int n) {
        long t0,t1;
        t0=System.currentTimeMillis();
        do{
            t1=System.currentTimeMillis();
        }
        while (t1-t0<1000);
    }

    public static void main(String[] args) {
        Random rand = new Random();
        Scanner numScan1 = new Scanner(System.in);
        Scanner numScan2 = new Scanner(System.in);
        Scanner numScan3 = new Scanner(System.in);
        Scanner numScan4 = new Scanner(System.in);
        Scanner numScan5 = new Scanner(System.in);
        Scanner numScan6 = new Scanner(System.in);
        boolean num1Cor = false;
        boolean num2Cor = false;
        boolean num3Cor = false;
        boolean num4Cor = false;
        boolean num5Cor = false;
        boolean num6Cor = false;

        System.out.print("Pick 6 numbers from 0 to 25. Pick your first number: ");
        int num1 = numScan1.nextInt();
        System.out.println();
        System.out.print("Pick your second number: ");
        int num2 = numScan2.nextInt();
        System.out.println();
        System.out.print("Pick your third number: ");
        int num3 = numScan3.nextInt();
        System.out.println();
        System.out.print("Pick your fourth number: ");
        int num4 = numScan4.nextInt();
        System.out.println();
        System.out.print("Pick your fifth number: ");
        int num5 = numScan5.nextInt();
        System.out.println();
        System.out.print("Pick your final number: ");
        int num6 = numScan6.nextInt();
        System.out.println("Numbers will now start to be drawn, if all of your numbers are called, you win.");

        while (true) {
            int random = rand.nextInt(25);
            System.out.println("Number " + random + ".");

            if (random == num1) {
                num1Cor = true;
                System.out.println("Your number, " + num1 + ", has been called.");
            }
            else if (random == num2) {
                num2Cor = true;
                System.out.println("Your number, " + num2 + ", has been called.");
            }
            else if (random == num3) {
                num3Cor = true;
                System.out.println("Your number, " + num3 + ", has been called.");
            }
            else if (random == num4) {
                num4Cor = true;
                System.out.println("Your number, " + num4 + ", has been called.");
            }
            else if (random == num5) {
                num5Cor = true;
                System.out.println("Your number, " + num5 + ", has been called.");
            }
            else if (random == num6) {
                num6Cor = true;
                System.out.println("Your number, " + num6 + ", has been called.");
            }


            if (num1Cor == true && num2Cor == true && num3Cor == true && num4Cor == true && num5Cor == true && num6Cor == true) {
                System.out.println("You win!!");
                break;
            }

            wait(100);
        }
    }
}
\$\endgroup\$
3
  • 3
    \$\begingroup\$ You could do it using only one Scanner \$\endgroup\$
    – Jigar Joshi
    Dec 26, 2011 at 5:45
  • \$\begingroup\$ You can make your numScan and numCor into arrays and use a for loop to access them. \$\endgroup\$ Dec 26, 2011 at 5:45
  • 1
    \$\begingroup\$ I am not able to figure out what u do with the parameter in the wait method \$\endgroup\$
    – Abhay Kumar
    Dec 26, 2011 at 5:51

7 Answers 7

8
\$\begingroup\$

First, you need just one Scanner.

Second, you could store the number choose by the user in an array.

Third, you could iterate the array to find the number there, instead of doing a lot of if and else if.

Forth, the user always wins. This looks like a bug. The while(true) ensures that the numbers are choosen in a way that eventually all the choosen numbers will be drawn. More, nothing stops the user from choosing a number more than once.

Fifth, the wait(100) will fail. You should use Thread.sleep(100) instead. EDIT, oops, I thought you were using Object.wait. It currently works, but Thread.sleep is better.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ I think most would agree with the last point, but you should nevertheless provide a reason why his approach is worse than Thread.sleep. \$\endgroup\$
    – Adam
    Dec 27, 2011 at 16:06
  • 1
    \$\begingroup\$ @codesparkle I think you have the wrong approach. If the system already provides something, you shouldn't roll your own unless the provided one isn't sufficient for some reason. That said, Thread.sleep is better because it sleeps the thread for at least the specified amount of time, rather than actively spinning in a tight loop for that amount of time; that's going to waste CPU time. (Further, the wait() method as implemented ignores its parameter.) \$\endgroup\$ Mar 19, 2012 at 21:31
7
\$\begingroup\$

What I'd made and make sense for me, hope it'll help you:
You named it Lotto, and unless the rules changed, we can't replay when we've lost, so the loop while(true) is useless in your code ;)

public class Lotto {

    private static final int INPUT_SIZE = 6;

    private static final int MIN_NUMBER_POSSIBLE = 0;

    private static final int MAX_NUMBER_POSSIBLE = 25;

    private Set<Integer> userNumbers = new HashSet<Integer>();

    private Set<Integer> randomNumbers = new HashSet<Integer>();

    public static void main(String[] args) {
        Lotto c = new Lotto();
        c.generateRandomNumbers();
        System.out.println("Pick " + INPUT_SIZE + " numbers from " +  MIN_NUMBER_POSSIBLE +  " to " + MAX_NUMBER_POSSIBLE + ".");
        c.readUserNumbers();
        if (c.doUserNumbersMatchRandomNumbers()) {
            System.out.println("You win :) !");
        } else {
            System.out.println("Sorry you failed :( !");
            c.showRandomNumbersToUser();
        }
    }

    private void generateRandomNumbers() {
        Random random = new Random();
        for (int i = 0; i < INPUT_SIZE; i++) {
            randomNumbers.add(random.nextInt(MAX_NUMBER_POSSIBLE));
        }
    }

    private void showRandomNumbersToUser() {
        System.out.println("\nRandom numbers where : ");
        for (Integer randomNumber : randomNumbers) {
            System.out.println(randomNumber + "\t");
        }
    }

    private void readUserNumbers() {
        Scanner input = new Scanner(System.in);
        int inputSize = 1;
        while (input.hasNextInt() && inputSize < INPUT_SIZE) {
            int numberChoosen = input.nextInt();
            if (numberChoosen < MIN_NUMBER_POSSIBLE || numberChoosen > MAX_NUMBER_POSSIBLE) {
                System.out.println("Your number must be in " + MIN_NUMBER_POSSIBLE + " - " + MAX_NUMBER_POSSIBLE + " range.");
            } else {
                userNumbers.add(numberChoosen);
                inputSize++;
            }
        }
    }

    private boolean doUserNumbersMatchRandomNumbers() {
        for (Integer userNumber : userNumbers) {
            if (!randomNumbers.contains(userNumber)) {
                return false;
            }
            printMatchingNumber(userNumber);
        }
        return true;
    }

    private void printMatchingNumber(int num) {
        System.out.println("Your number, " + num + ", has been called.");
    }
}
\$\endgroup\$
8
  • \$\begingroup\$ Advantage : can enter 6 numbers directly without one by one. No need status variables, (works with contains() method of Collection) and validation of inputs in the beginning. And of course, no duplicates, the horror for a developer :) \$\endgroup\$
    – Mik378
    Dec 26, 2011 at 7:10
  • \$\begingroup\$ +1 for the pleasant short functions, meaningful names and effort. Two suggestions: you can move the HashSet initializing code out of the constructor: private Set<Integer> userNumbers = new HashSet<Integer>(); - then you can delete the empty constructor. Next, in the sysout calls, don't use the magic numbers 0 and 25 - use your named constants instead. \$\endgroup\$
    – Adam
    Dec 26, 2011 at 23:53
  • 1
    \$\begingroup\$ You're right. I've just made changes. And I place a StringBuilder for two sysout instead of repetitive concatenations for avoiding reinstanciating new String Class. \$\endgroup\$
    – Mik378
    Dec 27, 2011 at 5:41
  • \$\begingroup\$ Wouldn't the compiler generate the equivalent StringBuilder implementation from the original string concatenation code? (java.sun.com/developer/technicalArticles/Interviews/community/…) \$\endgroup\$ Dec 27, 2011 at 15:24
  • 2
    \$\begingroup\$ In fact, since all of the pieces of the string are either literal strings or constant integers, the compiler can/will construct the final string at compile time, so the original code just using string concatenation with + would be better. (znetdevelopment.com/blogs/2009/04/06/java-string-concatenation) \$\endgroup\$ Dec 27, 2011 at 15:35
5
\$\begingroup\$

One small thing I noticed is the call to rand.nextInt(25). The player is told to select a number between 1 and 25, but rand.nextInt(25) will only generate 0 - 24. Change it to one of the following:

  • rand.nextInt(25) + 1
  • rand.nextInt(26) (if you want to include the 0 =))
\$\endgroup\$
2
\$\begingroup\$

What not to do:

Using single numbered variables that have the same function... This works but it becomes tedious as the program gets larger and more complex.

What to do:

-> Favor the use of "arrays" instead.

Arrays are explained here for use in Java: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html

\$\endgroup\$
3
  • \$\begingroup\$ -1: Read up on How to Answer \$\endgroup\$
    – Adam
    Dec 27, 2011 at 11:19
  • \$\begingroup\$ @codesparkle update Thanks for learning things to new users :) I edited now the answer in favor of the community and the asker.. \$\endgroup\$
    – Karel
    Dec 27, 2011 at 22:23
  • \$\begingroup\$ I removed my downvote. \$\endgroup\$
    – Adam
    Dec 27, 2011 at 22:26
1
\$\begingroup\$

I have modified the code, executed and played too. Good game :)

I have used ArrayList because it has enough built-in methods to handle this scenario easily.

You should also validate if user is entering a number outside of 0 and 25. That's very important. This will force user to enter the nth number only between 0 to 25 otherwise it will not go for next number.

public static void main(String[] args) throws InterruptedException {
    Random rand = new Random();
    Scanner scan = new Scanner(System.in);
    System.out.print("Enter 6 numbers from 0 to 25 separating.\n");
    List<Integer> list = new ArrayList<Integer>();
    for (int i = 0; i < 6; i++) {
        boolean flag = false;
        do {
            System.out.println("Enter " + (i+1) + "th number :");
            int num = scan.nextInt();
            if (num > -1 && num < 26) {
                list.add(new Integer(num));
                flag = false;
            } else {
                System.out.println("not valid number.");
                flag = true;
            }
        } while(flag);
    }
    System.out.println("Numbers will now start to be drawn, you win if all of your numbers are called.");
    for (int i = 0; i < 6; i++) {
        Integer random = new Integer(rand.nextInt(25));
        if (list.contains(random)) {
            System.out.println("Your number, " + random +", has been called.");
            list.remove(random);
        }
        Thread.sleep(1000);
    }
    if (list.size() == 0) {
        System.out.println("You won...");
    } else {
        System.out.println("You didn't win...");
    }
}

OUTPUT:

Enter 6 numbers from 0 to 25 separating.
Enter 1th number :
12
Enter 2th number :
34
not valid number.
Enter 2th number :
54
not valid number.
Enter 2th number :
15
Enter 3th number :
-23
not valid number.
Enter 3th number :
4
Enter 4th number :
5
Enter 5th number :
-100
not valid number.
Enter 5th number :
34
not valid number.
Enter 5th number :
10
Enter 6th number :
9
Numbers will now start to be drawn, you win if all of your numbers are called.
Your number, 9, has been called.
Your number, 4, has been called.
You didn't win...
\$\endgroup\$
2
  • \$\begingroup\$ I also made an improvment of it. See above ;) \$\endgroup\$
    – Mik378
    Dec 26, 2011 at 6:59
  • 2
    \$\begingroup\$ There are a few issues here, aside from having one giant main method--biggest is that nextInt(25) will never return 25 ;) \$\endgroup\$ Dec 27, 2011 at 2:35
1
\$\begingroup\$

I'm no java expert but you could start unitizing things. Your code needs to be less repetitive.

Like this, write functions for what you need to keep doing.

int AcceptInt()
{
    Scanner numSc = new Scanner(System.in);
    return numSc.NextInt();
}

Untested code, I don't even have Java on my PC. But it should give you some direction. Hope I haven't made any silly typos, I used notepad.

public class Lotto {

    //Pick 6 numbers from 1 to 100
    //If all of your numbers gets called out, you win

    public static void wait (int n) throws InterruptedException 
    {
        Thread.sleep(n*1000);//*1000 for seconds?
    }

    static int[] nums = new int[6];
    static boolean[] states = new boolean[6];

    public static void main(String[] args) {
        Random rand = new Random();
        //set all to false.
        //dunno if java defaults boolean to false.
        int i = 0;
        while(i++<6) { states[i] = false; }

        System.out.print("Pick 6 numbers from 0 to 25.");
        for(int k=0; k<6; k++) {
            System.out.print("Gimme number :"+ k);   
            nums[k] = AcceptInt();//check for validity?
            System.out.println();
        }
        System.out.println("Numbers will now start to be drawn, if all of your numbers are called, you win.");

        while (true) {//Shouldn't this be finite?
            int random = rand.nextInt(25);
            System.out.println("Number " + random + ".");

            for(int l= 0;l<6; l++) {
                if (random == nums[l]) {
                    states[l] = true;
                    System.out.println("Your number, " + nums[l]+ ", has been called.");
                }
            }

            for(int j= 0;j<6; j++)
            {
                if(states[j] == false)
                {
                    break;
                }
                System.out.println("You win!!");
                //maybe set another flag here and break out of your 
                //while infinite loop.
            }
            wait(100);//assuming seconds?
        }
    }
    static int AcceptInt()
    {
     Scanner numSc = new Scanner(System.in);
     return numSc.NextInt();
    } 
}
\$\endgroup\$
5
  • 1
    \$\begingroup\$ -1, full of errors. Where have you defined the i for your first while loop? Why are you setting k=0 without ever incrementing it in your first for loop, and again using your non-existant i? rand doesn't exist, either - did you mean to call GetNextRand() instead? nums, states and AcceptInt() have to be static. Why are you creating a new Scanner for every int? Why are you creating a new Random for every call to GetNextRand()? Random uses System.nanoTime() as a starting seed, so it will return nearly the same values if you create a new instance every time! \$\endgroup\$
    – Adam
    Dec 27, 2011 at 11:09
  • \$\begingroup\$ sorry!! Fixed! Though, this was on stackoverflow when I answered it and I wanted to just give a simple idea about what he should do. \$\endgroup\$
    – gideon
    Dec 28, 2011 at 5:16
  • \$\begingroup\$ there are still two problems: because Thread.Sleep can throw a checked InterruptedException your code will not compile without adding a try-catch block or declaring public static void wait(int n) throws InterruptedException { /*...*/ }. And, if you define int i on the second line of code in main, you cannot re-define it in the first for loop inside your while(true). \$\endgroup\$
    – Adam
    Dec 28, 2011 at 8:19
  • \$\begingroup\$ @codesparkle thanks. =S Guess I really need to brush on java, haven't done it in years. Fixed again! \$\endgroup\$
    – gideon
    Dec 28, 2011 at 8:56
  • \$\begingroup\$ I removed my downvote, but note that random.nextInt(n) will never return n, but always something between [0|n-1]. You therefore need to do random.nextInt(26) \$\endgroup\$
    – Adam
    Dec 28, 2011 at 9:00
1
\$\begingroup\$

@Victor has pointed out that you keep generating random numbers until the user wins.

@wayne has pointed out that you generate random numbers between 0 and 24 (inclusive), while asking the user to enter numbers between 0 and 25. While inclusive-exclusive ranges such as [0, 25) are handy for programmers, humans will perceive it as an inconsistency.

Besides those bugs, your number generator is an unfaithful implementation of the Lotto ball-picking process. Lotto balls are drawn from the cage without replacement — once a number has been picked, it will not be picked again. Your code just keeps generating random integers under 25.

One way to produce six different numbers is to check each generated number against the list of previously generated numbers. Another method is to start with an array of all 24 (or 25) numbers, shuffle the array, and take the first six elements after shuffling.


To check for a win:

int[] userPicks = …;
int[] drawnNumbers = …;
Arrays.sort(userPicks);
Arrays.sort(drawnNumbers);
boolean isWinner = Arrays.equals(userPicks, drawnNumbers);

The probability of winning Lotto 6/24 is 1 in 134596. If you play 10 simulations per second, then the expected time until winning should be around 3.8 hours.

\$\endgroup\$

Your Answer

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