Ryan Sayles
Ryan Sayles

Reputation: 3431

Stackoverflow from method calling

I was really hoping I would get a problem like this solved ironically on SO. Anyway I'm making a blackjack program using java and I'm running into an error with trying to handle how an ACE is used. For those that don't know the game an ACE can count as 11 or 1 and for the sake of this program I am making it automatically count as 11 unless you bust (your score is over 21). My problem is I have 3 methods:

public int getPlayerScore() {

    int pScore = 0;

    for (int i = 0; i < playerHand.size(); i++) {
        pScore = pScore + getCardScore(playerHand.get(i), "P");
    }

    return pScore;


public int getCardScore(Card c, String s) {

    int cardScore = 0;
    // gets the score of the card based on value
    switch (c.getValue()) {
    case TWO:
        cardScore = 2;
        break;
    case THREE:
        cardScore = 3;
        break;
    case FOUR:
        cardScore = 4;
        break;
    case FIVE:
        cardScore = 5;
        break;
    case SIX:
        cardScore = 6;
        break;
    case SEVEN:
        cardScore = 7;
        break;
    case EIGHT:
        cardScore = 8;
        break;
    case NINE:
        cardScore = 9;
        break;
    case TEN:
        cardScore = 10;
        break;
    case JACK:
        cardScore = 10;
        break;
    case QUEEN:
        cardScore = 10;
        break;
    case KING:
        cardScore = 10;
        break;
    case ACE:
        cardScore = getAceScore(s);
        break;
    }

    return cardScore;
}


public int getAceScore(String s) {
    int aceScore = 0;
    int tempScore = 0;
    if(s.equals("P")){
        tempScore = getPlayerScore() + 11;
    }
    else{
        tempScore = getDealerScore() + 11;
    }
    // if an ace as 11 doesn't bust player
    if (tempScore <= 21) {
        aceScore = 11;
    }
    // if an ace as 11 busts player
    else if (tempScore >= 21) {
        aceScore = 1;
    }

    return aceScore;
}

I know why I am getting the stack overflow error, my getAceScore() is calling getPlayerScore() which in turn is calling getAceScore() ect. I tried having an int playerScore global variable that updates when necessary, the problem with that was it would update and change the ACE score when it shouldn't. For example if I had ACE, NINE for a score of 20, it would then say my Score is 10 because it would say if the ACE was 11 then my score would be 31. I was thinking about making another method separately from getCardScore, remove the ACE case from that method and then constantly check the players hand for an ACE and then call a getAceScore. That seems too much though. Can anyone provide a simpler solution to this?

Upvotes: 0

Views: 119

Answers (3)

Bob Kuhar
Bob Kuhar

Reputation: 11110

Get rid of the recursion and you'll be fine. The getAceScore method could take as an argument the player's score without the Ace. Then it would just return either 1 or 11 based upon whether 11 would bust him or not

public int getAceScore( int playerScoreWithoutAce ) {
    int aceScore = ( playerScoreWithoutAce + 11 <= 21 ) ? 11 : 1;
    return aceScore;
}

I think I would model this whole solution differently in any event. You should just have Player objects and avoid the whole "if Dealer/if Player" distinction. The Player object at some point has a method to calculate the score of his hand. That is the method that determines the value of the Ace

public int handScore( List<Card> cards ) {
    int handScore = 0;
    // This assumes cards come in sorted with Ace last
    for( Card card : cards ) {
        int cardValue = ( card == ACE ) ? aceValue( handScore ) ? card.getValue();
        handScore += cardValue;
    }
    return handScore;
}

private int aceValue( int handScore ) {
    return ( handScore + 11 <= 21 ) ? 11 : 1;
}

Upvotes: 1

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48600

You can handle all the logic in an enum class. Of course, CardRank would be an attribute of a Card.

Output:

Ace  1: 12
Ace 11: 21

Code:

public enum CardRank {
    ACE(1),
    KING(10),
    QUEEN(10),
    JACK(10),
    TEN(10),
    NINE(9),
    EIGHT(8),
    SEVEN(7),
    SIX(6),
    FIVE(5),
    FOUR(4),
    THREE(3),
    TWO(2);

    private int value;

    private CardRank(int value) {
        this.value = value;
    }

    public static int caculateScore(int currentScore, CardRank rank) {
        if (currentScore <= 10 && rank == CardRank.ACE) {
            return currentScore + 11;
        }

        return currentScore + rank.value;
    }

    @Override
    public String toString() {
        return String.format("Rank: %s, Value: %d", name(), value);
    }

    public static void main(String[] args) {
        System.out.printf("Ace  1: %d%n", CardRank.caculateScore(11, CardRank.ACE));
        System.out.printf("Ace 11: %d%n", CardRank.caculateScore(10, CardRank.ACE));
    }
}

Upvotes: 0

Dylan
Dylan

Reputation: 540

Pass the current score (player or dealer) into the getCardScore() and then into getAceScore() methods. You should be able to do away completely with the String argument with the P business.

Upvotes: 0

Related Questions