Search code examples
javaarraysstringcharstring-length

What is the best method to get the index of a String or Char Array?


I would like to know what is the best way to get the index of a specific letter in a word. The reason i am doing this, is because i am making and modifying a Hangman game. I am already done with the game and it works good, however i want to implement a score based system. I created a method called keepScore() that takes a boolean value to see if the answer is right or wrong. If it is right, i am going to add 10 points for each letter found. If its wrong, i will deduct 10 points. My method keepScore() is implemented incorrectly any help?

Hangman.java

import Game.Game;
import Prompter.Prompter;

/* This class is the main class that starts the game.
 * It instantiates the Game and Prompter objects.
 */
public class Hangman {

    public static void main(String[] args) {
        //Check if an argument has been passed, we expect the answer to be passed
        if(args.length == 0) {
            System.out.println("Expected:   Java Hangman <answer>");
            System.err.println("Answer is required!");
            System.exit(1);
        }

        System.out.println("Welcome to Hangman!");

        //Create an instance of our game
        Game game = new Game(args[0]);
        //Create an instance of our prompter
        Prompter prompter = new Prompter(game);

        //Starts the game
        while (game.getRemainingTries() > 0 && !game.isWon()) {
            prompter.displayProgress();
            prompter.promptForGuess();
        }
        //Displays the outcome of the game
        prompter.displayOutcome();
    }
}

Game.java

package Game;

/* This class is responsible for implementing the game
 * logic.
 */
public class Game {
    //Declare our member variables
    public final static int TOTAL_TRIES = 3;
    public final static int MAX_SCORE_POINTS = 10;
    private String mAnswer;
    private String lettersHit;
    private String lettersMissed;
    private int score;

    //Default constructor
    public Game(String answer) {
        //Initialize our member variables
        mAnswer = answer.toLowerCase();
        lettersHit = "";
        lettersMissed = "";
    }

    //This method checks to see if the letter was a hit or a miss
    public boolean checkLetter(char letter){
        letter = validateGuess(letter);
        boolean isHit = mAnswer.indexOf(letter) != -1;
        //If correct
        if (isHit) {
            //Add the letter to the lettersHit pool
            lettersHit += letter;
            keepScore(isHit);
            System.out.println("Hit! Score: " + score);

        }else {
            //Add the letter to the lettersMissed pool
            lettersMissed += letter;
            keepScore(isHit);
            System.out.println("Missed! Score: " + score);
        }
        return isHit;
    }

    private void keepScore(boolean isHit) {
        if(isHit) {
            for (int i = 0; i < lettersHit.length(); i++) {
                score += MAX_SCORE_POINTS;
            }
        } else {
            for (int i = 0; i < lettersMissed.length(); i++ ) {
                score -= MAX_SCORE_POINTS;
            }
        }
    }

    /*
    This method handles an empty string input. For example,
    if the user were to press enter on input a 0 length String
    will cause the program to crash.
     */
    public boolean checkLetter(String letters) {
        if (letters.length() == 0) {
            throw new IllegalArgumentException("No letter entered");
        }
        return checkLetter(letters.charAt(0));
    }

    //This method validates the user guess
    private char validateGuess(char letter) {
        //If the character is not a letter
        if (!Character.isLetter(letter)) {
            //Ask user for a valid letter
            throw new IllegalArgumentException("A letter is required!");
        }
        //If entry was valid, convert character to lowercase
        letter = Character.toLowerCase(letter);

        //Check if the letter has been guessed already
        if (lettersHit.indexOf(letter) != -1 || lettersMissed.indexOf(letter) != -1) {
            throw new IllegalArgumentException("The letter " + letter + " has already been guessed");
        }
        return letter;
    }

    //This method keeps track of the user's game progress
    public String getCurrentProgress() {
        String progress = "";
        //For each character in the array of strings of mAnswer
        for (char letter : mAnswer.toCharArray()) {
            char display = '-';
            if (lettersHit.indexOf(letter) != -1){
                display = letter;
            }
            progress += display;
        }
        return progress;
    }

    //Get the current remaining tries
    public int getRemainingTries() {
        return TOTAL_TRIES - lettersMissed.length();
    }

    //Get the current answer
    public String getAnswer() {
        return mAnswer;
    }

    //This method checks if the game is won.
    public boolean isWon() {
        return getCurrentProgress().indexOf('-') == -1;
    }


    public int getScore(){
        return score;
    }
}

Prompter.java

package Prompter;
import Game.Game;
import java.util.Scanner;

/* This class is responsible for displaying instructions and information to the user
 * regarding the game.
 */
public class Prompter {
    //The game object
    private Game mGame;
    private boolean isHit;
    private boolean acceptable;

    //Default constructor
    public Prompter(Game game) {
        //Get the instance of our game
        mGame = game;
        isHit = false;
        acceptable = false;
    }

    //This method prompts the user for a guess
    public boolean promptForGuess() {
        //Create an instance of scanner
        Scanner scanner = new Scanner(System.in);

        //Loop for input
        do {
            System.out.println("Please enter a letter: ");
            String guess = scanner.nextLine();

            try {
                isHit = mGame.checkLetter(guess);
                acceptable = true;
            }catch (IllegalArgumentException iae) {
                System.out.printf("%s. Please try again!%n", iae.getMessage());
            }
        } while (!acceptable);
        return isHit;
    }

    //This method displays the progress
    public void displayProgress() {
        System.out.printf("You have %d tries to guess the answer" +
                " before you are taken to the gallows. Try to solve:  %s%n", mGame.getRemainingTries(),
                mGame.getCurrentProgress());
    }

    //This method displays the outcome of the game
    public void displayOutcome() {
        if( mGame.isWon()) {
            System.out.printf("Congratulations! you won with %d tries remaining.%n" +
                    "Your total score: %d%n", mGame.getRemainingTries(), mGame.getScore());
        }else {
            System.out.printf("Bummer! The answer was: %s", mGame.getAnswer());
        }
    }
}

Solution

  • Look at this method of yours:

    private void keepScore(boolean isHit) {
        if(isHit) {
            for (int i = 0; i < lettersHit.length(); i++) {
                score += MAX_SCORE_POINTS;
            }
        } else {
            for (int i = 0; i < lettersMissed.length(); i++ ) {
                score -= MAX_SCORE_POINTS;
            }
        }
    }
    

    It doesn't add MAX_SCORE_POINTS times the number of good letters you just found, it does so with the number of good letters in lettersHit. Now, what is in lettersHit ? Well, there is all the letters you found since the start.

    So you'll have :

    word to guess: anaconda
    
    letter: a
    lettersHit = "a", score += (lettersHit.length * 10) = 10
    letter: c
    lettersHit = "ac", score += (lettersHit.length * 10) = 30
    

    You could just use StringUtils.countMatches(mAnswer, letter); to get the number of occurence, hence the score.