首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java Hangman实现

Java Hangman实现
EN

Code Review用户
提问于 2018-02-18 20:10:24
回答 2查看 1.5K关注 0票数 2

我正在学习Java,并计划很快参加OCA SE8考试。我制作了一个相当原始的Hangman游戏来帮助学习。如果可能的话,我希望能得到一些反馈。如果没有达到所需的标准(命名约定、某些方法的速度等),我很想知道。

我不满意的两件事是:

  1. 我不知道如何掩蔽用户的输入,此时玩家2可以看到要猜测的单词。
  2. 这个游戏是一行行完成的。我不知道如何使它更“静态”,即星号在一个地方,它不会移动,有一行词已经猜到了(我希望这是有意义的)。我试图避免使用GUI。
代码语言:javascript
复制
package hangman2;
import java.util.Arrays;
import java.util.Scanner;

public class Hangman2 {

static int guessesRemaining;
static String stringWord;
static char[] charWord;

public static void playHangman() {

    System.out.print("Welcome to Hangman! ");
    System.out.println("Player 1: Enter a word");
    Scanner scan = new Scanner(System.in);
    stringWord = scan.nextLine();

    //Loop to get user to enter in letters only
    while (stringWord.matches(".*[^a-z].*")) {
        System.out.println("Please enter letters only, try again:");
        stringWord = scan.nextLine();
    }

    System.out.println("The length of the word is " + stringWord.length()); //Print out length of word.
    stringWord = stringWord.toLowerCase();

    int lettersRemaining = stringWord.length(); //Letters to be gussed is equal to the word length.

    //Create a new char array equal to the word length, add * to each index.
    charWord = new char[stringWord.length()];
    for (int i = 0; i < stringWord.length(); i++) {
        charWord[i] = ('\u002A');
    }
    int livesRemaining = 7; // 7 lives remaining!
    MainLoop:
    /*
    Main loop, gets user input using Scanner, ensures it is only a letter (not a number or special character)
    Converts string to char, uses the guess method which compares the secret word to the character entered and
    returns true if it found it, false if it didn't. 
    If found, letters remaining - 1, if the char array contains any asterisks, envoke the gameWon() method.
    If not found, lives remaining - 1, if no more lives, envoke the gameLost() method.
    */
    while (livesRemaining > 0) {
        System.out.println("Player 2: Guess a Letter:!");
        char guessLetter;
        String b = scan.next();
        while (b.matches(".*[^a-z].*")) {
            System.out.println("Please enter letters only, try again:");
            b = scan.next();
        }
        guessLetter = b.toLowerCase().charAt(0);
        String a = new Hangman2().print(guessLetter);
        if (guess(guessLetter, stringWord)) {
            lettersRemaining--;
            if (!a.contains("*")) {
                gameWon();
                break;
            }
            System.out.println("Well done, you guessed correctly! You have " + lettersRemaining + " letters remaining");
        } else {
            livesRemaining--;
            if (livesRemaining == 0) {
                gameLost();
            }
            System.out.println("Too bad, you guessed incorrectly, you have " + livesRemaining + " lives remaining");
        }
    }
}

public String print(char c) {
    //Prints asterisks and replaces characters that have been guessed.
    String misses;
    char[] guess = stringWord.toCharArray();
    for (int i = 0; i < charWord.length; i++) {
        if (guess[i] == c) {
            charWord[i] = c;
        }
    }
    misses = Arrays.toString(charWord);
    System.out.print(misses + "  ");
    return misses;
}

public static boolean guess(char c, String s) {
    //Evaluates the chracter entered and compares it to the word, returns a boolean (correct or incorrect).
    boolean result = false;
    char[] a = s.toCharArray();
    for (int i = 0; i < s.length(); i++) {
        if (a[i] == c) {
            result = true;
        }
    }
    return result;
}

public static void gameWon() {
    char yesno;
    boolean enter;
    System.out.print("Congratulations, you won!");
    Scanner input = new Scanner(System.in);
    System.out.println(" Would you like to play again? Y / N");
    do {
        yesno = input.next().toUpperCase().charAt(0);
        switch (yesno) {
            case 'Y':
                playHangman();
            case 'N':
                System.exit(0);
            default:
                System.out.println("Please enter Y / N");
                enter = false;
                break;
        }
    } while (!enter);
}

public static void gameLost() {
    char yesno;
    boolean enter;
    System.out.print("Too bad, you lost...");
    Scanner input = new Scanner(System.in);
    System.out.println(" Would you like to play again? Y / N");
    do {
        yesno = input.next().toUpperCase().charAt(0);
        switch (yesno) {
            case 'Y':
                playHangman();
            case 'N':
                System.exit(0);
            default:
                System.out.println("Please enter Y / N");
                enter = false;
                break;
        }
    } while (!enter);
}

public static void main(String[] args) {
    playHangman();
}

}
EN

回答 2

Code Review用户

发布于 2018-02-19 01:41:47

类不是

对象

静态int guessesRemaining;静态字符串stringWord;静态char[] charWord;

你要把整个类变成一个假的对象。

代码语言:javascript
复制
    private String stringWord;
    private char[] charWord;

这就是真实对象字段的外观。

除非您有特定的原因(例如,您希望某个字段出于某种特定原因在外部可见),否则您应该将对象字段声明为private可见性。避免默认(包私有),除非您有一些理由使用它。而不是一个“我可能想.在未来”的理由。这是在代码中实际实现的原因。在这种情况下,整个程序是一个类。任何可见性都可以,但在大多数情况下,private是首选。

同样,我并不是说除了对对象字段(存储在对象中的数据)使用private以外,没有理由使用可见性。我是说你在这里没有这样的理由。我还说,可能总是让字段private和修复罕见的异常比在一开始就尝试寻找其他任何东西的原因要容易一些。如果这一政策开始令人恼火,那就重新考虑一下。但在早期阶段,它很少会超出设置者和获取者的范围。

您不想使用类作为假对象的原因是,它阻止您创建类的多个实例。你不能这样一次玩两个汉曼游戏。

你需要一个构造函数。

代码语言:javascript
复制
    Hangman2(String word) {
        stringWord = word;
        charWord = new char[word.length()];
        Arrays.fill(charWord, '*');
    }

这也消除了用星号手动填充字符数组的需要。相反,我们使用内置的Arrays.fill

虽然有些方法不需要是static,但main需要。所以重写它就像

代码语言:javascript
复制
    public static void main(String[] args) {
        do {
            Hangman2 game = new Hangman2(inputWordToGuess());
            game.play();
        } while (isReplayDesired());
    }

注意,getWordToGuessisReplayDesired都是static方法。与此同时,play不是。

何时使用static

当使用static确实有意义时,您在任何地方都使用相同的东西。例如,有一个static Scanner是有意义的。

代码语言:javascript
复制
    public static Scanner input = new Scanner(System.in);

这也可以是public,所以其他类不必自己制作扫描器。

在您的原始版本中,您将在任何碰巧需要获取用户输入的方法中构建一个扫描器对象。这样,您就可以为整个程序构建一个持久的程序。

不使用冗余代码

您的gameWongameLost方法几乎是相同的。所以我用

代码语言:javascript
复制
    public static boolean isReplayDesired() {
        while (true) {
            System.out.println(" Would you like to play again? Y / N");
            switch (input.next().toUpperCase().charAt(0)) {
                case 'Y':
                    return true;
                case 'N':
                    return false;
                default:
                    System.out.println("Please enter Y / N");
            }
        }
    }

这就去掉了enter布尔值。所以代码更少了。

您可以使用中间的yesno变量,但这是不必要的。

通过返回布尔值,我们可以简化这里和调用方中的代码。

可以使用原始代码使用递归调用来溢出堆栈(尽管有些困难)。现在不是了,没有递归调用。

break语句是switch语句中的最后一个子句时,我从不将它放入默认子句中。这没必要。我总是在我可以的时候把它放在最后,这几乎一直都是。我确实把它放在最后一个非缺省子句中,尽管它仍然是不必要的。

试图保持方法的单用途

您的原始playHangman方法尝试做几件事。我听说了这个词。现在我们有两种更简单的方法。这使得事情变得更加灵活。与从用户输入中获取单词不同,我完全可以切换到从文件中读取单词,而无需更改play方法。我只是停止使用inputWordToGuess

如果我更改名称,我可以将inputWordToGuess重用到其他地方。

票数 2
EN

Code Review用户

发布于 2018-02-19 03:30:05

代码语言:javascript
复制
public class Hangman2 {

HangMan2是个坏名字。不要将数字作为类名添加。如果不打算覆盖类,则向类添加final修饰符。

代码语言:javascript
复制
static int guessesRemaining;
static String stringWord;
static char[] charWord;

您可以用纯面向对象的方式编写代码,因此您不需要statics。此外,您还可以添加一个private修饰符。

代码语言:javascript
复制
public static void playHangman() {

不需要static

代码语言:javascript
复制
//Loop to get user to enter in letters only
while (stringWord.matches(".*[^a-z].*")) {
    System.out.println("Please enter letters only, try again:");
    stringWord = scan.nextLine();
}

这可能是另一种方法。Regex可以声明为字符串常量。你可能不想要无限的尝试。

代码语言:javascript
复制
stringWord = stringWord.toLowerCase();

为什么不叫它word呢?

代码语言:javascript
复制
while (livesRemaining > 0) {

显然需要有自己的方法。

代码语言:javascript
复制
while (b.matches(".*[^a-z].*")) {

回到我的常量点。如果stringnull,你是否确保它不会导致NPE?

代码语言:javascript
复制
String a = new Hangman2().print(guessLetter);

print方法应该是void,否则更改名称。a是个坏名字。

代码语言:javascript
复制
if (!a.contains("*")) {

难道不能用letterRemaining == 0来代替吗?

代码语言:javascript
复制
System.out.print(misses + "  ");

假设你可以一次打印一个字符串?

代码语言:javascript
复制
char[] a = s.toCharArray();

你可以选择String.charAt(i)

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/187820

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档