Eu escrevi um jogo Hangman baseado em texto em Java que precisa incluir os recursos que incluí nos comentários do meu código .
Em suma, o jogo pedirá ao usuário para digitar uma palavra que ele (ou uma segunda pessoa) adivinhe. A palavra será censurada pelo programa. O programa dirá ao usuário se sua letra adivinhada está na palavra ou não, e mostrará o progresso da palavra censurada após cada adivinhação. Se o usuário já adivinhou a letra antes, o programa informará o usuário sobre isso e mostrará os palpites anteriores sem repetir nenhuma letra. O programa mostrará o número de tentativas no final.
O código que escrevi abaixo funciona e tem todos os recursos que listei. Mas não parece o ideal e provavelmente com etiqueta muito pobre, já que sou autodidata até agora. Portanto, estou procurando qualquer conselho que torne este código melhor e para garantir que eu não tenha maus hábitos ( Provavelmente já tenho haha), pois continuo a aprender Java sozinho.
//Simple Hangman game where user types a word, program stores it in all CAPS for easier user readability and censors the word (i.e *****) //User then guesses one letter at a time until the entire word is guessed. Program will inform the user if the guess is in the word, and show the progress of the word after each guess. //If the guessed letter is in the word, program will print out the # of times the letter is in the word. //Program will store and print out # of guesses (attempts) needed to guess the word at the end of the program. //If user tries to duplicate a previous guess, program will inform user of that and show previous guesses by user. Attempt count will not go up for duplicate guesses. //When the program shows previous guesses by the user (using a string), it cannot contain duplicate letters. (i.e: if user guesses "s" twice, "s" will still only show up once in the string) //StackOverFlow readers: This program works as intended, but as a self-taught beginner coder, I need assistance on optimal coding style (less lines the better) and good coding principles/etiquette //I definitely think there are much better ways to code this, but I cannot think of any more (as you probably noticed, this is v3, which has more features and yet similar amount of lines as version 1 haha) //All and any help is appreciated! Thank you :D import java.util.*; public class HangmanGameV3 { public static void main(String [] args){ //Initialize all the variables used here String storedword; char[] charstring; int length; char[] censor; int attempts=0; StringBuilder pastguesses = new StringBuilder(); //String Builder to add and print out previous guesses Scanner typedword = new Scanner(System.in); System.out.println("Enter your word to guess: "); storedword = typedword.nextLine(); storedword = storedword.toUpperCase(); //stores the word and changes it to all caps length = storedword.length(); charstring = storedword.toCharArray(); //creates char array of string //creates and prints an array of chars with the same length as string censor = storedword.toCharArray(); System.out.println("Your secret word is: "); for (int index = 0; index < length; index++){ censor[index] = "*"; } //Main loop to take guesses (is this while loop the ideal loop here? while (String.valueOf(censor).equals(storedword)== false){ //Initialize all variables in loop char charguess; String tempword; String tempstring; boolean correct = false; //required for if loops below/lets the user know if the letter is in the word or not int times = 0; //number of times a letter is in the word boolean repeated = false; //check if user guessed the same letter twice //prints the censored secret word for(int a= 0; a < length; a++){ System.out.print(censor[a]); } System.out.println(); //asks user for guess, then stores guess in Char charguess and String tempstring Scanner guess = new Scanner(System.in); System.out.println("Type your guess: "); tempword = guess.next(); charguess = tempword.charAt(0); //gets char data from scanner pastguesses.append(charguess); //adds guess to previous guess string tempstring = pastguesses.toString(); //checks if user already guessed the letter previously if (tempstring.lastIndexOf(charguess, tempstring.length() -2 ) != -1){ System.out.println("You already guessed this letter! Guess again. Your previous guesses were: "); pastguesses.deleteCharAt(tempstring.length()-1); System.out.println(tempstring.substring(0, tempstring.length()-1)); repeated = true; } //if the guess is not a duplicated guess, checks if the guessed letter is in the word if (repeated == false){ for (int index = 0; index < length; index++){ if(charstring[index] == Character.toUpperCase(charguess)) { censor[index] = Character.toUpperCase(charguess); //replaces * with guessed letter in caps correct = true; times++; } } if(correct == true){ System.out.println("The letter " + charguess + " is in the secret word! There are " + times +" " + charguess + " "s in the word. Revealing the letter(s): "); } else if (correct == false){ System.out.println("Sorry, the letter is not in the word. Your secret word: "); } System.out.println(); } attempts++; } System.out.println("You guessed the entire word "+ storedword.toUpperCase() + " correctly! It took you " + attempts + " attempts!"); //typedword.close(); //StackOverFlow readers: is this necessary? Not sure how to use .close() }
Exemplo de saída do meu código para referência, se necessário:
Resposta
Algumas mudanças simples:
Você cria dois scanners , um dentro do loop e outro com nome incorreto no início. Eu renomeio o typedword
para input
e substitua os usos de guess
por input
.
if(repeated == false)
seria melhor escrito
if(!repeated)
Da mesma forma, altero outro se declarações
Eu usaria um Set<String>
para armazenar suposições anteriores
Eu mudarei d a declaração de times
dentro do !repeated loop
para que sua declaração seja mais próxima de seu uso e limitado em escopo ao seu uso.
Outras declarações foram unidas à configuração do valor e algumas atribuições encadeadas, como o novo
String wordToGuess = input.nextLine().toUpperCase();
tempstring
foi removido, ele só é construído agora quando necessário
várias variáveis foram renomeadas para nomes mais explicativos.
Código final:
import java.util.HashSet; import java.util.Scanner; import java.util.Set; public class HangmanGameV3 { public static void main(String[] args) { int attempts = 0; Set<String> previousGuesses = new HashSet<>(); Scanner input = new Scanner(System.in); System.out.println("Enter your word to guess: "); String wordToGuess = input.nextLine().toUpperCase(); int length = wordToGuess.length(); char[] wordToGuessChars = wordToGuess.toCharArray(); //creates char array of string //creates and prints an array of chars with the same length as string char[] censor = wordToGuess.toCharArray(); System.out.println("Your secret word is: "); for (int index = 0; index < length; index++) { censor[index] = "*"; } //Main loop to take guesses (is this while loop the ideal loop here? while (!String.valueOf(censor).equals(wordToGuess)) { //Initialize all variables in loop boolean correct = false; //required for if loops below/lets the user know if the letter is in the word or not boolean repeated = false; //check if user guessed the same letter twice //prints the censored secret word for (int a = 0; a < length; a++) { System.out.print(censor[a]); } System.out.println(); //asks user for guess, then stores guess in Char charguess and String tempstring System.out.println("Type your guess: "); String currentGuess = input.next().toUpperCase().substring(0, 1); char currentGuessChar = currentGuess.charAt(0); //gets char data from scanner //checks if user already guessed the letter previously if (previousGuesses.contains(currentGuess)) { System.out.println("You already guessed this letter! Guess again. Your previous guesses were: "); System.out.println(previousGuesses.stream().reduce("", String::concat)); repeated = true; } previousGuesses.add(currentGuess); //if the guess is not a duplicated guess, checks if the guessed letter is in the word if (!repeated) { int times = 0; //number of times a letter is in the word for (int index = 0; index < length; index++) { if (wordToGuessChars[index] == currentGuessChar) { censor[index] = currentGuessChar; //replaces * with guessed letter in caps correct = true; times++; } } if (correct) { System.out.println("The letter " + currentGuessChar + " is in the secret word! There are " + times + " " + currentGuessChar + " "s in the word. Revealing the letter(s): "); } else { System.out.println("Sorry, the letter is not in the word. Your secret word: "); } System.out.println(); } attempts++; } System.out.println("You guessed the entire word " + wordToGuess.toUpperCase() + " correctly! It took you " + attempts + " attempts!"); } }
Comentários
Resposta
Obrigado por compartilhar seu código! Parece muito bom, mas (como sempre) há algumas coisas a consertar e observar:
-
Criação de várias instâncias
Scanner
: Não faça isso. Você só precisa de um. A criação de mais de um ocupa mais espaço. Em vez de criartyped word
eguess
, basta criar um chamadoinput
ou algo parecido. -
Fechando seu
Scanners
: Sempre faça então, quando você terminar de usá-los, ou então você receberá um aviso de “Vazamento de recursos”. Fechar umScanner
faz com que oScanner
não pode ser usado novamente. É como desligar as luzes ao sair da sala, não há sentido em deixá-las acesas. Será um desperdício se você fizer isso. -
Usando
==
com booleanos. Em vez de==
, use!
, assim:if(condition) { //if "condition" is true.
ou
if(!condition) { //if "condition" is false
char
em vez de uma String, mas isso muda algumas coisas menores na lógica …