0

I'm trying to write a program that essentially evaluates a 5 card poker hand that is user-generated. One part of the program is that users can choose one variable to randomly change. The issue lies with setting a value for one of my instance variables, right now, my setCards, getCards, and changeOne methods are:

public void setCards(String str) {
    this.cards = str;
    calculateScore();
    history = history + cards + score + changes;
    changes++;
}

public String getCards() {
    return this.cards;
}

public void changeOne(int pos) {
    
    getCards();
    
    calculateScore();
    history = history + cards + score + changes;
    
    randomChar = allCards.charAt((int)(Math.random()*cards.length()));
    this.cards = cards.substring(0, pos) + randomChar + cards.substring(pos + 1, cards.length());
    
    changes++;
    
} 

In a separate class, I'm using:

cards = in.nextLine().toUpperCase();
myCards.setCards(cards);

I'm not sure why but whenever I try to use the changeOne method, keeps giving me the error: Exception in thread "main" java.lang.StringIndexOutOfBoundsException: begin 0, end 3, length 0 Which I assume is because it takes cards to be an empty string. I'm not sure what is happening and why it isn't getting the proper value of cards, help would be greatly appreciated.

Entire code: First class:

import java.util.Scanner;
public class Assignment4{

public static void main(String[] args) {
    
    Scanner in = new Scanner(System.in);
    FiveCards myCards = new FiveCards();
    
    int position;
    String choice, cards;
    char charChoice;
    
    final char NEW = 'A';
    final char CHANGE = 'B';
    final char DISPLAY = 'C';
    final char QUIT = 'Q';
    
    do {
        
        System.out.println("Choose (A: Make New Cards), (B: Change One Card), (C: Display Data), or (Q: Quit)");
        choice = in.next();
        charChoice = choice.toUpperCase().charAt(0);
        
        switch(charChoice) {
            case NEW:
                System.out.println("*** Make New FiveCards ***");
                System.out.println("Type five letters without space: ");
                in.next();
                cards = in.nextLine().toUpperCase();
                myCards.setCards(cards);
                System.out.println("[Cards] [Score] [Changes]");
                myCards.displayData();
                break;
            case CHANGE:
                System.out.println("*** Change One Card ***");
                System.out.println("Type one position to change (0-4): ");
                position = in.nextInt();
                myCards.changeOne(position);
                System.out.println("[Cards] [Score] [Changes]");
                myCards.displayData();
                break;
            case DISPLAY:
                System.out.println("[Cards] [Score] [Changes]");
                myCards.displayData();
                break;
            case QUIT:
                System.out.println("*** End of Program ***");
                break;
            default:
                System.out.println("Invalid input. Try Again");
                break;
        }
        
    }while(charChoice!=QUIT);
    
}

}

Second class is:

public class FiveCards {
private String cards, history;
private int score, changes, counter;
private String allCards = "1234567890JQK";
private char randomChar;

public FiveCards() {
}

public void setCards(String str) {
    this.cards = str;
    calculateScore();
    history = history + cards + score + changes;
    changes++;
}

public String getCards() {
    return this.cards;
}

public void changeOne(int pos) {
    

    
    calculateScore();
    history = history + cards + score + changes;
    
    randomChar = allCards.charAt((int)(Math.random()*cards.length()));
    this.cards = cards.substring(0, pos) + randomChar + cards.substring(pos + 1, cards.length());
    
    System.out.println(cards);
    
    changes++;
    
}

public void calculateScore() {
    for(int i = 0; i<cards.length(); i++) {
        for(int j = 0; j<cards.length(); j++) {
            if((cards.charAt(i) == cards.charAt(j)) && (i != j)) {
                counter++;
            }
        }
    }
    if(counter == 2) {
        score = 1;
    }
    else if(counter == 4) {
        score = 2;
    }
    else if(counter == 6) {
        score = 3;
    }
    else if(counter == 8) {
        score = 4;
    }
    else {
        score = 0;
    }
}

public String displayData() {
    
    calculateScore();
    history = history + cards + score + changes;
    
    if(cards.length()<=1) {
    return cards + "    " + score + "   " + changes;
    }
    else {
        return "Empty" + "  " + score + "   " + changes;
    }
    
}

}

GS1221
  • 11
  • 4
  • It's very hard to tell when we can only see part of the code (we can't see what's calling `changeOne`) and we don't know what you're entering for `cards`. Please provide a [mcve] - I'd suggest using a hard-coded input instead of user input, so that we can all use *exactly* the same value when running the code. – Jon Skeet Oct 03 '21 at 07:32
  • I tried to include all of the relevant parts, the initialization for cards was towards the bottom of the post, it was user-inputted. This is what was calling changeOne: – GS1221 Oct 03 '21 at 07:34
  • position = in.nextInt(); myCards.changeOne(position); – GS1221 Oct 03 '21 at 07:34
  • But it still isn't a [mcve]. We can't copy/paste/compile/run your code - we have to *guess* at various things, which makes it harder to help you. – Jon Skeet Oct 03 '21 at 07:39
  • Okay, I edited it to include everything towards the bottom – GS1221 Oct 03 '21 at 07:45
  • Try change `cards = in.nextLine().toUpperCase(); myCards.setCards(cards);` to, `cards = in.nextLine(); myCards.setCards(cards.toUpperCase());` – navnath Oct 03 '21 at 08:01

1 Answers1

0

First problem:

allCards.charAt(...). In the setCards you assign string to cards, but here you pick character from allCards. What is content of allCards? When it is assigned? I it assigned at all? (your code doesn't show this).

And the second problem:

Math.random()*cards.length()

Valid indexes of characters in the String are from 0 to length() - 1 inclusive, but the way you generate random index, you can give you index from 0 to length() inclusive. Change it to the Math.random()*(cards.length() - 1).

ivan.ukr
  • 2,853
  • 1
  • 23
  • 41
  • Sorry, forgot to include it: private String allCards = "1234567890JQK"; – GS1221 Oct 03 '21 at 07:40
  • Your second point isn't correct - `Math.random()` never returns 1, so the result of the multiplication can never be `cards.length()`. With your change, the result would never be the last card. It would be better to use `Random` though. – Jon Skeet Oct 03 '21 at 07:40
  • Also, I changed it to your variation and now I am getting the error: Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1 – GS1221 Oct 03 '21 at 07:40
  • @GS1221: "Forgot to include it" is precisely the problem with not providing a [mcve]. I suspect if you'd done so, we'd have solved the problem by now. – Jon Skeet Oct 03 '21 at 07:40
  • @GS1221: I strongly suspect that `cards` is an empty string. But because you've only given us snippets of code (for example, we don't know when you're calling `in.nextInt()` compared with when you're calling `in.nextLine()`) we can't see the whole picture. I strongly suspect the problem is actually this: https://stackoverflow.com/questions/13102045 - but we can't tell for sure without a complete example. – Jon Skeet Oct 03 '21 at 07:41
  • That was the first thing I thought as well but I put an in.next(); in front of where I initialized cards and it still wasn't working properly. – GS1221 Oct 03 '21 at 07:47
  • Oh god I needed to use nextLine();, I think it is working now – GS1221 Oct 03 '21 at 07:48