Escribí un juego basado en texto Hangman en Java que debe incluir las características que incluí en los comentarios de mi código .
En resumen, el juego le pedirá al usuario que escriba una palabra que él (o una segunda persona) adivinará. La palabra será censurada por el programa. El programa le dirá al usuario si su letra adivinada está en la palabra o no, y mostrará el progreso de la palabra censurada después de cada adivinación. Si el usuario ya adivinó la letra antes, el programa se lo dirá al usuario y mostrará sus conjeturas anteriores sin repetir ninguna letra. El programa mostrará el número de intentos al final.
El código que escribí a continuación funciona y tiene todas las características que enumeré. Pero parece que no es óptimo y probablemente con muy mala etiqueta, ya que soy autodidacta hasta ahora. Por lo tanto, estoy buscando algún consejo que mejore este código y que me asegure de no tener malos hábitos ( Probablemente ya tengo jaja) ya que continúo aprendiendo Java por mí mismo.
//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() }
Salida de muestra de mi código como referencia si es necesario:
Respuesta
Algunos cambios simples:
Creas dos escáneres , uno dentro del ciclo y otro mal nombrado al principio. Cambio el nombre del typedword
a input
y reemplace los usos de guess
con input
.
if(repeated == false)
estaría mejor escrito
if(!repeated)
De manera similar, modifico otros si declaraciones
Yo usaría un Set<String>
para almacenar conjeturas pasadas
Me he movido d la declaración de times
dentro de la !repeated loop
para que su declaración esté más cerca de su uso y su alcance se limite a su uso.
Se han unido otras declaraciones a la configuración del valor, y se han encadenado algunas asignaciones como la nueva
String wordToGuess = input.nextLine().toUpperCase();
tempstring
se ha eliminado, solo se construye ahora cuando es necesario
Se ha cambiado el nombre de una serie de variables para obtener nombres más 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!"); } }
Comentarios
Respuesta
¡Gracias por compartir tu código! Se ve bastante bien, pero (como siempre) hay algunas cosas que corregir y tener en cuenta:
-
Creación de varias
Scanner
instancias: No lo haga. Solo necesita uno. Crear más de uno solo ocupa más espacio. En lugar de creartyped word
yguess
, simplemente cree uno llamadoinput
o algo así. -
Cerrando su
Scanners
: Siempre haga así que cuando termines de usarlos, o de lo contrario, recibirás una advertencia de «Fuga de recursos». Si cierras unScanner
, elScanner
no se puede volver a utilizar. Es como apagar las luces cuando sales de la habitación, no tiene sentido dejarlas encendidas. Si lo haces, es un desperdicio. -
Usando
==
con booleanos. En lugar de==
, use!
, así:if(condition) { //if "condition" is true.
o
if(!condition) { //if "condition" is false
char
en lugar de una Cadena, pero eso cambia algunas cosas menores en la lógica …