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
2 Answers 2
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;
}
}
}
-
\$\begingroup\$ This is great! it makes it more readable indeed! \$\endgroup\$Kurusu– Kurusu2013年09月25日 01:28:33 +00:00Commented 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– Kurusu2013年09月25日 02:20:25 +00:00Commented Sep 25, 2013 at 2:20
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;
}
}
}
}
-
\$\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– Kurusu2013年09月25日 01:37:33 +00:00Commented Sep 25, 2013 at 1:37
Explore related questions
See similar questions with these tags.