1
\$\begingroup\$

Hangman game coded in Java (at a beginner's level) where Hangman.java can be run with one or more arguments.

Hangman.java:

package hangman;
import hangman.Game;
import hangman.Prompter;

public class Hangman {
    public static String normalizeArgs(String[] array) {
        String result = "";

        switch (array.length) {
            case 0:
                System.out.println("Usage:  java Hangman <answer>");
                System.err.println("answer is required");
                System.exit(1);
                break;
            case 1:
                result = array[0];
                break;
            default:
                for (int i = 0; i < array.length; i++) {
                    result += array[i];

                    if (i != array.length-1) {
                        result += ' ';
                    }
                }   
        }

        return result;
    }

    public static void main(String[] args) {
        Game game = new Game(normalizeArgs(args));
        Prompter prompter = new Prompter(game);

        while (game.getRemainingTries() > 0 && !game.isWon()) {
            prompter.displayProgress();
            prompter.promptForGuess();
        }

        prompter.displayOutcome();
    }
}

Prompter.java:

package hangman;
import java.util.Scanner;

public class Prompter {
    private Game game;

    public Prompter(Game game) {
        this.game = game;
    }

    public boolean promptForGuess() {
        Scanner scanner = new Scanner(System.in);
        boolean isHit = false;
        boolean isAcceptable = false;

        do {
            System.out.printf("Enter a letter:  ");
            String guessInput = scanner.nextLine().toLowerCase();

            try {
                isHit = game.applyGuess(guessInput);
                isAcceptable = true;
            } catch (IllegalArgumentException iae) {
                System.out.printf("%s.  Please try again. %n", 
                                  iae.getMessage());
            }
        } while (!isAcceptable);

        return isHit;
    }

    public void displayProgress() {
        System.out.printf("You have %d tries left to solve: %s%n", 
                           game.getRemainingTries(),
                           game.getCurrentProgress());
    }

    public void displayOutcome() {
        if (game.isWon()) {
            System.out.printf("Congratlations! You won with %d tries left.%n", game.getRemainingTries());
        } else {
            System.out.printf("Bummer! The word was %s.  :(%n", game.getAnswer());
        }
    }
}

Game.java:

package hangman;

public class Game {
    public static final int MAX_TRIES = 7;
    private String answer;
    private String hits;
    private String misses;

    public Game(String answer) {
        this.answer = answer.toLowerCase();
        hits = "";
        misses = "";
    }

    private char normalizeGuess(char letter) {
        if (!Character.isLetter(letter)) {
            throw new IllegalArgumentException("Guess is not a letter");
        }

        if (hits.indexOf(letter) != -1 || misses.indexOf(letter) != -1) {
            throw new IllegalArgumentException("Letter already guessed");
        }

        return letter;
    }

    public boolean applyGuess(String letters) {
        if (letters.length() == 0) {
            throw new IllegalArgumentException("No letters found");
        }

        return applyGuess(letters.charAt(0));
    }

    public boolean applyGuess(char letter) {
        normalizeGuess(letter);
        boolean isHit = answer.indexOf(letter) != -1; 

        if (isHit) {
            hits += letter;
        } else {
            misses += letter;
        }

        return isHit;
    }

    public int getRemainingTries() {
        return MAX_TRIES - misses.length();
    }

    public String getCurrentProgress() {
        String progress = "";

        for (char letter : answer.toCharArray()) {
            if (hits.indexOf(letter) != -1) {
                progress += letter;
            } else if (letter == ' ') {
                progress += ' '; 
            } else {
                progress += '-';
            }
        }

        return progress;
    }

    public boolean isWon() {
        return getCurrentProgress().indexOf('-') == -1;
    }

    public String getAnswer() {
        return answer;
    }
}
\$\endgroup\$
3
\$\begingroup\$

Nice code overall, doesnt feel like beginner. A few points:

  • case for single argument in your normalizeArgs switch can be covered by default branch

  • I don't like your main game loop conditions. Basically first half compares number of remaining tries, that effectively means asking if game is lost. Second half asks if game is won. Then can change to checking for joined win/loss conditions, but you can put it one step further and make boolean method in Game, that will tell you, if game still runs/continues and use that as your loop condition.

  • feels like Strings for displayProgress and displayOutcome should be in class Game. Create something like progressMessage and outcomeMessage methods there, that will return String. String.format has same functionality as printf. Then you are more flexible and correct class has the responsibility. You just print messages in Prompt class.

  • Not sure about using System.err that one time, while not using it to display exception messages. But I cant really say if its good or bad.

  • Too many public methods in Game class. I'd leave only single method for applyGuess - the one that accepts char. It describes more what you want - single character and is cleaner API. Other one also accepts strings longer than one char and imho that functionality shouldn't be here, but in prompter - it is input checking. Extracting that loop condition (mentioned above) also allows more methods to be possibly private.

  • max tries could be constructor parameter to add more flexibility.

  • Excellent exception usage imho.
|improve this answer|||||
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.