-1

EDIT: SOLVED

I am having problems with getting my Scanner to work properly. I have googled a lot about this and they suggest putting a hasNextInt() but this just skips the nextLine and so it keeps using the default value of choice which spams the output. If I take the hasNextInt out, it gives a No Such Element Exception. The problem is in the fight method. The source code is below.

public static void game()
{
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println();
    StarterSword starterw = new StarterSword();
    weapons[0] = starterw;
    StarterArmour startera = new StarterArmour();
    armour[0] = startera;
    Heal heal = new Heal();
    items[0] = heal;

    System.out.println();
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("Lets start with an easy monster fight first.\nLater on it will be harder as monsters evolve.");

    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    int[] b = fight(a, starterw, startera, heal);
    a++;
    int coin = b[0];
    coins = coins + coin;
    System.out.println("You now have " + coins + " coins");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    contGame();
}

public static void contGame(){
    System.out.println("Now a slightly harder boss!");
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    Scanner choose = new Scanner(System.in);
    while(a <= 40)
    {
        Weapon weapon = PVMGame.weapons[0];
        Armour armour = PVMGame.armour[0];
        Items heal = PVMGame.items[0];
        int[] b = fight(a, weapon, armour, heal);
        int coin = b[0];
        coins = coins + coin;
        System.out.println("You now have " + coins + " coins");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if(b[1] == 1)
        {

            System.out.println("You won! You can go to the next level!");
            a++;
        }
        else
        {

            System.out.println("You lost!");

        }
        choose.close();

    }

}

public static int[] fight(int level, Weapon weapon, Armour armour, Items heal){

    int[] a = new int[2];
    int b = 0;
    int c = 0;
    int damage;
    int health ;
    health = level * 30;
    damage = (level * 4) - 1;
    System.out.println("\nThis Monster has " + health + " health and " + damage + " damage.\n1)Attack\n2)Use Heal(You can only have one of each type of item)\n3)QUIT THIS WHOLE PROGRAMME!!");
    boolean isAlive = true;
    boolean isPAlive = true;
    boolean win = false;
    int pHealth = armour.hp;
    int attack = weapon.damage;
    int healing = heal.healHP;
    String weaponT = weapon.name;
    String armourT = armour.name;
    String healT = heal.name;
    int max = pHealth;
    int totalD = 0;
    int choice = 1;
    @SuppressWarnings("resource")
    Scanner userInput = new Scanner(System.in);
    while(isAlive && isPAlive){

        if(userInput.hasNextInt()){
            choice = userInput.nextInt(); //This is where it goes wrong
        }
        if(choice == 1)
        {

            health = health - attack;

            System.out.println("\nYou inflicted " + attack + " damage on the enemy with your" + weaponT + "\nHe now only has " + health + " health left.");
            if(health <= 0){

                b = (level * 40) - 5;
                System.out.println("You defeated the monster! You won " + b + " coins.");
                a[0] = b;
                win = true;
                isAlive = false;
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            pHealth = pHealth - damage;
            System.out.println("\nThe Monster inflicted " + damage + " damage on your" + armourT + "\nYou only have " + pHealth + " health left.");
            totalD = totalD + damage;
            if(pHealth <= 0){

                System.out.println("You failed.");
                    isPAlive = false;
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            System.out.println("\n1)Attack\n2)Use Heal\n3)QUIT THIS WHOLE PROGRAMME!!");

        }
        else if(choice == 2)
        {
            pHealth = pHealth + healing;
            if(pHealth > max){
                healing = totalD;
                pHealth = max;
            }
            if(healing != 0){
                System.out.println("\nYou healed " + healing + " health on yourself with your" + healT + "\nYou have " + pHealth + " health left.");
            }
            else{
                System.out.println("You have no healing potions left!");
            }
            healing = 0;

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            pHealth = pHealth - damage;
            System.out.println("\nThe Monster inflicted " + damage + " damage on your" + armourT + "\nYou only have " + pHealth + " health left.");
            totalD = totalD + damage;
            if(pHealth <= 0){

                System.out.println("You failed.");
                    isPAlive = false;
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            System.out.println("\n1)Attack\n2)Use Heal\n3)QUIT THIS WHOLE PROGRAMME!!");

        }
        else if(choice == 3)
        {
            System.exit(0);
        }
        else
        {
            System.out.println("TYPE EITHER 1, 2, OR 3");
            fight(level,weapon,armour,heal);
        }

    }
    if(win){

        c = 1;

    }
    if(win == false){

        c = 0;

    }
    a[1] = c;
    return a;
}
slavoo
  • 4,967
  • 63
  • 33
  • 38
pri2003
  • 1
  • 1
  • try to debug it: treat it as String and print it to system.out to see what scanner returns... – vathek Sep 02 '15 at 11:57
  • You've posted 220 lines of code - and that's still incomplete. It's really important to learn the skill of narrowing down where a bug is... that's part of the research you should perform before asking a question.. Please edit your question showing a *short but complete* program demonstrating the problem. – Jon Skeet Sep 02 '15 at 12:00
  • `hasNextInt()` scanns for the next Integer token. If there is none it skips the line. – SWiggels Sep 02 '15 at 12:00
  • @SWiggels it doesn't skip the line. According to the javadoc "The scanner does not advance past any input." – Dakshinamurthy Karra Sep 02 '15 at 12:09
  • Thanks for clarification. – SWiggels Sep 02 '15 at 12:11
  • This is a duplicate of [this](http://stackoverflow.com/questions/15443383/scanner-nosuchelementexception) question. In short use only a single instance of scanner to read from `System.in`. – Master_ex Sep 02 '15 at 12:14

2 Answers2

0

The problem is here:

if(userInput.hasNextInt()){
    choice = userInput.nextInt(); //This is where it goes wrong
}

You are not handling the else case. Change it to something like this:

if(userInput.hasNextInt()){
    choice = userInput.nextInt(); //This is where it goes wrong
} else {
    System.out.println("Invalid input");
    userInput.nextLine(); // Ignore till the end of line
    continue; // Continue again
}
Dakshinamurthy Karra
  • 4,969
  • 1
  • 13
  • 25
  • The current problem is not reading the input once a bad input is given. And then `close` comes into picture. His problem is with `fight` method - he did not even reach `cont` method. – Dakshinamurthy Karra Sep 02 '15 at 12:39
  • hey @KDM, I down voted because I found the answer misleading. You claim that the problem is that the asker didn't check for invalid input and you didn't pay any attention that the code threw a `NoSuchElementException` (which btw is the title of the question). You are addressing a possible issue but not the issue that made the asker to post the question. This and the fact that you have received an up vote which makes the answer more misleading made me to down vote it. I find your answer a very valuable suggestion but not a fitting answer for this question. I hope that you'll agree with me :) – Master_ex Sep 02 '15 at 18:34
  • Look at the description. He gets the exception only when he removes the hasNextInt method. So I don't agree with you. – Dakshinamurthy Karra Sep 02 '15 at 18:38
  • You are correct. @pri2003 doesn't get an error because he uses the `hasNextInt()` which returns false even if the stream is closed. I find this strange. By reading `hasNext()` [doc](http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#hasNext%28%29) and [code](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b27/java/util/Scanner.java#Scanner.hasNext%28%29) I understand that it should throw an `IllegalStateException` which clearly doesn't. – Master_ex Sep 02 '15 at 20:07
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/88623/discussion-between-master-ex-and-kdm). – Master_ex Sep 02 '15 at 20:09
0

As I have mentioned in the comments this happens because you are closing once the System.in stream and if the System.in stream is closed then you cannot re-open it. You can see that this is the case from the error which is NoSuchElementException. If you enter something else as input instead of integer as expected you are going to get an InputMismatchException.

See this and this relevant questions.

So you better use a global Scanner and close the stream once when you exit the program which is the best and easiest solution.

You may as well ingore any warnings from your IDE and just never close the System.in streams that you open.

Finally, another idea which is demonstrated in the second link that I have cited is to create a FileInputStream wrapper to the System.in and never call close. Here is an example:

Scanner sc = new Scanner(new FilterInputStream(System.in){public void close(){}});

Later,you may do sc.close(), but System.in will remain open as sc.close() doesn't do anything.

This seems overkill to me. I would go with the global Scanner way.

Finally, expecting other kind of values is a wise choice, so I would keep @KDM's suggestion in mind.

Community
  • 1
  • 1
Master_ex
  • 779
  • 7
  • 12