What is a Java hangman game?

278    Asked by Aashishchaursiya in Java , Asked on Oct 12, 2022

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 ");
                System.err.println("answer is required");
                System.exit(1);
                break;
            case 1:
                result = array[0];
                break;
            default:
                for (int i = 0; i < array>                    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("Congratulations! 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 chat 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;
    }
}


Answered by Dorine Hankey

Nice code overall, doesn't feel like a 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 the first half compares the number of remaining tries, that effectively means asking if the Java hangman game is lost. Second half asks if the game is won. Then can change to checking for joined win/loss conditions, but you can put it one step further and make a boolean method in Game, that will tell you, if the 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 the same functionality as printf. Then you are more flexible and the 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 can't really say if it's good or bad.

Too many public methods in Game class. I'd leave only a 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 a constructor parameter to add more flexibility.

Excellent exception usage imho.



Your Answer

Interviews

Parent Categories