7
\$\begingroup\$

I just created a Hangman app (same game mechanics mostly) using Java. I did this mainly to test my knowledge in OOP design/coding. I'd like to know your thoughts on my code

The whole project is on Github

I would really appreciate the comments and criticism!

public class Launcher {
private static BufferedReader consoleReader;

public static void main(String[] args) throws IOException {
    consoleReader = new BufferedReader(new InputStreamReader(System.in));
    System.out.println("***LET'S PLAY HANGMAN (w/o the actual \"man\")***");
    System.out.print("Enter name:");
    String username = consoleReader.readLine();

    Player P1 = new Player(username);
    String plyrName = P1.getUsername();
    System.out.println("Welcome " + plyrName + "!");

    int choice = 0;
    while (choice != 4) {
        try {
            System.out.println();
            System.out.println("1. Start game");
            System.out.println("2. Help");
            System.out.println("3. About this game");
            System.out.println("4. Quit");

            choice = Integer.parseInt(consoleReader.readLine());
            if (choice == 1) {

                AI a1 = new AI(P1);
                String answer = a1.getAnswer();
                P1.setGuess(P1.initGuess(a1));

                System.out.println();
                System.out.println("***Guess this " + answer.length() + " letter word!***");

                while (P1.getTries() != 0) {
                    try {
                        for (int x = 0; x < answer.length(); x++) {
                            System.out.print(P1.getGuess()[x] + " ");
                        }
                        System.out.println();
                        System.out.println("1. Guess a letter");
                        System.out.println("2. Guess the answer");
                        System.out.println("3. Concede");
                        System.out.println();
                        System.out.println("No. of tries remaining: " + "*" + P1.getTries() + "*");
                        int controls = Integer.parseInt(consoleReader.readLine());

                        if (controls == 1) {
                            System.out.print("Input letter: ");
                            String ltr = consoleReader.readLine();

                            if (a1.isLetterInWord(P1, answer, ltr.toLowerCase())) {
                                if (String.valueOf(P1.getGuess()).equals(answer)) {
                                    System.out.println("***\"" + String.valueOf(P1.getGuess())  + "\"" + " is correct!***");
                                    System.out.print("***You have beaten the game, " + plyrName + "!***");
                                    P1.setTries(0);
                                }
                                System.out.println();
                            } else {
                                P1.setTries(P1.getTries() - 1);
                                if (P1.getTries() != 0) {
                                    System.out.println("***Sorry try again!***");
                                }
                            }
                        }

                        else if (controls == 2) {
                            System.out.print("Input guess: ");
                            String word = consoleReader.readLine();
                            if (a1.isGuessCorrect(answer, word.toLowerCase())) {
                                P1.setGuess(word.toCharArray());
                                System.out.println("***\"" + word + "\"" + " is correct!***");
                                System.out.println("***You have beaten the game, " + plyrName + "!***");
                                P1.setTries(0);

                            } else {
                                System.out.println("***Sorry try again!***");
                                P1.setTries(P1.getTries() - 1);
                            }
                        }

                        else if (controls == 3) {
                            System.out.println("***Are you sure you want to concede?***");
                            System.out.print("Y/N: ");
                            String yn = consoleReader.readLine();
                            while (!yn.toLowerCase().equals("n")) {
                                if(yn.toLowerCase().equals("y")) {
                                    P1.setTries(0);
                                    break;
                                }
                                System.out.print("Y/N: ");
                                yn = consoleReader.readLine();
                            }
                        }
                    } catch (Exception e) {
                        System.out.println("***ERROR: Invalid input!***");
                    }
                }

                if (P1.getTries() == 0 && !String.valueOf(P1.getGuess()).equals(answer)) {
                    System.out.println("***GAME OVER, " + plyrName + "!***");
                    System.out.println("***The answer is " + "\"" + answer + "\"***");
                }
            }
            else if (choice == 2) {
                System.out.println("              ***Help***");
                System.out.println("You will be given a word to try and guess.");
                System.out.println("Your number of trials will depend on the length of the word.");
                System.out.println("You can guess it by letter or guess it directly.");
                System.out.println("Goodluck; Have fun!");
                System.out.println("              ***Help***");
            }
            else if (choice == 3) {
                System.out.println("          ***About this game***");
                System.out.println("This game was developed to check and exercise");
                System.out.println("zurcnay4's OOP knowledge using java. \n");
                System.out.println("Comments & suggestions on: ");
                System.out.println("- the application's overall design/code");
                System.out.println("- how to improve this game");
                System.out.println("are highly appreciated! \n");
                System.out.println("Fork on github: https://github.com/zurcnay4/Hangman");
                System.out.println("          ***About this game***");
            }
            else if (choice == 4) {
                System.out.println("***Are you sure you want to quit?***");
                System.out.print("Y/N: ");
                String yn = consoleReader.readLine();
                while (!yn.toLowerCase().equals("n")) {
                    if ((yn.toLowerCase().equals("y"))) {
                        choice = 4;
                        System.out.println("***Goodbye, " + plyrName + "***");
                        break;
                    }
                    System.out.print("Y/N: ");
                    yn = consoleReader.readLine();
                }
                if ((yn.toLowerCase().equals("n"))) {
                    choice = 0;
                }
            }
        } catch (Exception e) {
            System.out.println("***ERROR: Invalid input!***");
        }
    }
}
}

Couple of concerns

  • Is there a need to use an abstract class/Interface in my project?
  • Did I do abstraction correctly? Did I create the right classes/objects?
  • Is my code readable?
  • Am I following the right conventions?

Please do check the GitHub repo to see the whole application. Aside from the main class, I have these classes:

  • AI
  • AIService
  • Player
  • PlayerService
  • Dictionary
\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

Please split your code into different smaller functions. This is just impossible to understand. Here's my attempt, it probably doesn't compile but it does look much easier to understand :

public class Launcher {
    private static BufferedReader consoleReader;

    public static void main(String[] args) throws IOException {
        consoleReader = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("***LET'S PLAY HANGMAN (w/o the actual \"man\")***");
        System.out.print("Enter name:");
        String username = consoleReader.readLine();

        Player P1 = new Player(username);
        String plyrName = P1.getUsername();
        System.out.println("Welcome " + plyrName + "!");

        while (true) {
            System.out.println();
            System.out.println("1. Start game");
            System.out.println("2. Help");
            System.out.println("3. About this game");
            System.out.println("4. Quit");

            switch (askUserInteger(0)) {
                case 1: game(P1); break;
                case 2: help(); break;
                case 3: about(); break;
                case 4:
                    if (userWantsToQuit()) {
                        System.out.println("***Goodbye, " + plyrName + "***");
                        return;
                    }
                    break;
                default: System.out.println("***ERROR: Invalid input!***");
            }
        }
    }


    public static void game (Player P1)
    {
        AI a1 = new AI(P1);
        String answer = a1.getAnswer();
        P1.setGuess(P1.initGuess(a1));

        System.out.println();
        System.out.println("***Guess this " + answer.length() + " letter word!***");

        while (P1.getTries() != 0) {
            for (int x = 0; x < answer.length(); x++) {
                System.out.print(P1.getGuess()[x] + " ");
            }
            System.out.println();
            System.out.println("1. Guess a letter");
            System.out.println("2. Guess the answer");
            System.out.println("3. Concede");
            System.out.println();
            System.out.println("No. of tries remaining: " + "*" + P1.getTries() + "*");

            switch (askUserInteger(0)) {
                case 1: guessLetter(P1); break;
                case 2: guessAnswer(P1); break;
                case 3 : if (userWantsToConcede()) P1.setTries(0); break;
                default : System.out.println("***ERROR: Invalid input!***");
            }
        }

        if (P1.getTries() == 0 && !String.valueOf(P1.getGuess()).equals(answer)) {
            System.out.println("***GAME OVER, " + plyrName + "!***");
            System.out.println("***The answer is " + "\"" + answer + "\"***");
        }
    }

    public static void guessLetter(Player P1)
    {
        System.out.print("Input letter: ");
        String ltr = consoleReader.readLine();

        if (a1.isLetterInWord(P1, answer, ltr.toLowerCase())) {
            if (String.valueOf(P1.getGuess()).equals(answer)) {
                System.out.println("***\"" + String.valueOf(P1.getGuess())  + "\"" + " is correct!***");
                System.out.print("***You have beaten the game, " + plyrName + "!***");
                P1.setTries(0);
            }
            System.out.println();
        } else {
            P1.setTries(P1.getTries() - 1);
            if (P1.getTries() != 0) {
                System.out.println("***Sorry try again!***");
            }
        }
    }

    public static void guessAnswer(Player P1)
    {
        System.out.print("Input guess: ");
        String word = consoleReader.readLine();
        if (a1.isGuessCorrect(answer, word.toLowerCase())) {
            P1.setGuess(word.toCharArray());
            System.out.println("***\"" + word + "\"" + " is correct!***");
            System.out.println("***You have beaten the game, " + plyrName + "!***");
            P1.setTries(0);
        } else {
            System.out.println("***Sorry try again!***");
            P1.setTries(P1.getTries() - 1);
        }
    }

    public static void help ()
    {
        System.out.println("              ***Help***");
        System.out.println("You will be given a word to try and guess.");
        System.out.println("Your number of trials will depend on the length of the word.");
        System.out.println("You can guess it by letter or guess it directly.");
        System.out.println("Goodluck; Have fun!");
        System.out.println("              ***Help***");
    }

    public static void about()
    {
        System.out.println("          ***About this game***");
        System.out.println("This game was developed to check and exercise");
        System.out.println("zurcnay4's OOP knowledge using java. \n");
        System.out.println("Comments & suggestions on: ");
        System.out.println("- the application's overall design/code");
        System.out.println("- how to improve this game");
        System.out.println("are highly appreciated! \n");
        System.out.println("Fork on github: https://github.com/zurcnay4/Hangman");
        System.out.println("          ***About this game***");
    }
    public static bool userWantsToConcede()
    {
        return askUserYesNoQuestion("***Are you sure you want to concede?***");
    }
    public static bool userWantsToQuit()
    {
        return askUserYesNoQuestion("***Are you sure you want to quit?***");
    }
    public static bool askUserYesNoQuestion(String question)
    {
        System.out.println(question);
        do {
            System.out.print("Y/N: ");
            String yn = consoleReader.readLine();
            if (yn.toLowerCase().equals("y")) return true;
        }
        while (!yn.toLowerCase().equals("n"));
        return false;
    }
    public static int askUserInteger(int defValue)
    {
        try {
            return Integer.parseInt(consoleReader.readLine());
        } catch (Exception e) {
            return defValue;
        }
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ This is great! it makes it more readable indeed! \$\endgroup\$
    – Kurusu
    Sep 25, 2013 at 1:28
  • \$\begingroup\$ Question: with the functions game() about() help()... would it be better if I separate them in other classes to make it more OOP? \$\endgroup\$
    – Kurusu
    Sep 25, 2013 at 2:20
4
\$\begingroup\$

Nitpick: the variable P1 should be named p1, since the convention is to use uppercase for class names and constants.

I agree with @Josay that this function desperately needs to be broken up!

Since you indicate that you want to exercise OOP, I suggest creating a Menu class to help reduce the tedium of prompting for user choices.

public class Menu {
    public final String[] choices;

    public Menu(String... choices) {
        this.choices = choices;
    }

    int promptInt(BufferedReader in, PrintWriter out) throws IOException {
        while (true) {
            for (int i = 1; i <= this.choices.length; i++) {
                out.printf("%d. %s\n", i, this.choices[i - 1]);
            }
            out.flush();
            int choice = Integer.parseInt(in.readLine());
            if (choice > 0 && choice <= this.choices.length) {
                return choice;
            }
        }
    }

    boolean promptYN(BufferedReader in, PrintWriter out) throws IOException {
        assert 1 == this.choices.length;
        out.println(this.choices[0]);
        while (true) {
            out.print("Y/N: ");
            out.flush();
            switch (Character.toLowerCase(in.readLine().charAt(0))) {
              case 'y': return true;
              case 'n': return false;
            }
        }
    }
}

You can use it like this:

static Menu mainMenu = new Menu(
    /* 1 */ "Start game",
    /* 2 */ "Help",
    /* 3 */ "About",
    /* 4 */ "Quit"
);
static Menu quitMenu = new Menu("***Are you sure you want to quit?***");

public static void main(String[] args) throws IOException {
    BufferedReader conIn = new BufferedReader(new InputStreamReader(System.in));
    PrintWriter conOut = new PrintWriter(System.out);

    while (true) {
        switch (mainMenu.promptInt(conIn, conOut)) {
          case 1: game(conIn, conOut); break;
          case 2: help(conIn, conOut); break;
          case 3: about(conIn, conOut); break;
          case 4:
            if (quitMenu.promptYN(conIn, conOut)) {
                System.out.println("Bye!"); return;
            }
        }
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ I see. I didn't think of making a Menu class thank you for pointing that out! Did you check the project on github? what are your thoughts on the classes that I created? \$\endgroup\$
    – Kurusu
    Sep 25, 2013 at 1:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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