Czy ten kod jest zgodny ze standardowymi konwencjami i nie jest zbędny? Jak mogę uczynić to bardziej zrozumiałym dla innych ludzi?
To ćwiczenie z książki wprowadzającej do języka Java:
Napisz gra w wisielca, która losowo generuje słowo i zachęca użytkownika do odgadnięcia jednej litery na raz. Każda litera w słowie jest wyświetlana jako gwiazdka. Gdy użytkownik zgadnie poprawnie, wyświetlana jest właściwa litera. Gdy użytkownik zakończy word, wyświetl liczbę chybień.
Mój program:
import java.util.Arrays; import java.util.Scanner; public class Hangman{ public static void main(String[] args) { String[] words = {"writer", "that", "program"}; // Pick random index of words array int randomWordNumber = (int) (Math.random() * words.length); // Create an array to store already entered letters char[] enteredLetters = new char[words[randomWordNumber].length()]; int triesCount = 0; boolean wordIsGuessed = false; do { // infinitely iterate through cycle as long as enterLetter returns true // if enterLetter returns false that means user guessed all the letters // in the word e. g. no asterisks were printed by printWord switch (enterLetter(words[randomWordNumber], enteredLetters)) { case 0: triesCount++; break; case 1: triesCount++; break; case 2: break; case 3: wordIsGuessed = true; break; } } while (! wordIsGuessed); System.out.println("\nThe word is " + words[randomWordNumber] + " You missed " + (triesCount -findEmptyPosition(enteredLetters)) + " time(s)"); } /* Hint user to enter a guess letter, returns 0 if letter entered is not in the word (counts as try), returns 1 if letter were entered 1st time (counts as try), returns 2 if already guessed letter was REentered, returns 3 if all letters were guessed */ public static int enterLetter(String word, char[] enteredLetters) { System.out.print("(Guess) Enter a letter in word "); // If-clause is true if no asterisks were printed so // word is successfully guessed if (! printWord(word, enteredLetters)) return 3; System.out.print(" > "); Scanner input = new Scanner(System.in); int emptyPosition = findEmptyPosition(enteredLetters); char userInput = input.nextLine().charAt(0); if (inEnteredLetters(userInput, enteredLetters)) { System.out.println(userInput + " is already in the word"); return 2; } else if (word.contains(String.valueOf(userInput))) { enteredLetters[emptyPosition] = userInput; return 1; } else { System.out.println(userInput + " is not in the word"); return 0; } } /* Print word with asterisks for hidden letters, returns true if asterisks were printed, otherwise return false */ public static boolean printWord(String word, char[] enteredLetters) { // Iterate through all letters in word boolean asteriskPrinted = false; for (int i = 0; i < word.length(); i++) { char letter = word.charAt(i); // Check if letter already have been entered bu user before if (inEnteredLetters(letter, enteredLetters)) System.out.print(letter); // If yes - print it else { System.out.print("*"); asteriskPrinted = true; } } return asteriskPrinted; } /* Check if letter is in enteredLetters array */ public static boolean inEnteredLetters(char letter, char[] enteredLetters) { return new String(enteredLetters).contains(String.valueOf(letter)); } /* Find first empty position in array of entered letters (one with code \u0000) */ public static int findEmptyPosition(char[] enteredLetters) { int i = 0; while (enteredLetters[i] != "\u0000") i++; return i; } }
Dziennik jego pracy:
(Guess) Enter a letter in word **** > a (Guess) Enter a letter in word **a* > t (Guess) Enter a letter in word t*at > q q is not in the word (Guess) Enter a letter in word t*at > t t is already in the word (Guess) Enter a letter in word t*at > b b is not in the word (Guess) Enter a letter in word t*at > h (Guess) Enter a letter in word that The word is that You missed 2 time(s)
Komentarze
- Czy byłoby dobrze, gdybym załączył link na darmowy hosting obrazów z obrazem schematu blokowego ilustrującym logika mojego programu, ponieważ ' nie jest oczywista, jak to działa, lub ' nie jest konieczne?
- Schematy blokowe i tym podobne zwiększyłyby th Zrozumiałość tego, co ' robisz. To ' to zawsze dobra rzecz.
- Myślę, że ' wykonałeś dobrą robotę, usuwając nadmiarowości i tworząc metody, aby było bardziej zwięzłe. Jednak jest to trochę trudne do naśladowania. Może pomogłyby bardziej opisowe nazwy metod (najlepszą dokumentacją jest kod czytelny!)
- Twój kod jest zbyt skomplikowany, musisz wyjaśnić, co się dzieje, ponieważ studentowi trudno jest przeczytać i dokładnie wiedzieć, co się dzieje dzieje się '. Dziękuję.
Odpowiedź
Magiczne liczby: Lepiej byłoby przenieść definicje na 0,1, 2,3 do pól enum
lub final
, aby można było odwołać się do nich za pomocą zrozumiałej nazwy. Na przykład final int LETTER_NOT_IN_WORD = 0
lub enum HangmanGuess { LETTER_NOT_IN_WORD }
Nadmiarowość: podstawowa logika między findEmptyLetters
i inEmptyLetters
to to samo, szukasz char
w char[]
. Mógłbyś to zmienić w ten sposób:
/* Check if letter is in enteredLetters array */ public static boolean inEnteredLetters(char letter, char[] enteredLetters) { return indexOf(letter, enteredLetters) >= 0; } /* Find first empty position in array of entered letters (one with code \u0000) */ public static int findEmptyPosition(char[] enteredLetters) { return indexOf("\u0000", enteredLetters) } /* Determine the index in {@code vals} where {@code ch} exists. Returns -1 if {@code ch} is not in {@code vals}. */ public static int indexOf(char ch, char[] vals) { return Arrays.asList(vals).indexOf(Character.valueOf(ch)); }
Jedną rzeczą, na którą należy zwrócić uwagę, jest to, że w obecnej implementacji findEmptyPosition
zwróci n
, gdzie n
to enteredLetters.length + 1
, jeśli nie ma pustych pozycji. Nie jestem pewien, czy jest to pożądana funkcja.
Odpowiedź
Pierwsza (mała) rzecz: wydaje się, że częściej użyj Random
niż Math.random()
. Przeczytaj te sprawdzone metody post.
Komentarze i przełącznik jako pierwsza w funkcji do {} while () są dla mnie osobiście bardzo zagmatwane. enterLetter()
nigdy nie zwraca true
lub false
, a nawet większość nowych programistów wie, co zrobić / podczas wykonywania iteracji, dopóki warunek nie zostanie spełniony. Bardziej pomocne byłoby opisanie, co reprezentuje 0-3 (i jeśli to czy kod produkcyjny lub bardziej złożony, Enum uczyniłoby go znacznie bardziej zrozumiałym).
Wewnątrz enterLetter()
byłoby pomocne przeniesienie int emptyPosition = findEmptyPosition(enteredLetters);
wywołanie else if
, gdzie jest używane. Nie tylko zapobiega to alokowaniu pamięci do czasu jej użycia, ale jest również bardziej czytelne (i możesz usunąć zmienną emptyPosition
, jeśli chcesz i wywołać funkcję wewnątrz referencji , ale to jest semantyczne).