This is my implementation of the classic "Hangman" word-guessing game.
Class LePendu :
public class LePendu {
// Variable
public static int NB_ERREURS_MAX=10;
static ArrayList<Character> playerGuess = new ArrayList<Character>();
static ArrayList <String> wrongGuess = new ArrayList<String>();
static ArrayList <String> playerWord = new ArrayList<String>();
static String penduDessin [][] = new String[10][10];
// Le Main :
public static void main(String args[]) throws FileNotFoundException {
Scanner sc = new Scanner (new File("C:/Users/admin/pendu.txt"));
Scanner charP = new Scanner (System.in);
while(sc.hasNext()) {
playerWord.add(sc.nextLine());
}
// Intitialisation Hangman :
initialize2dArray();
// Wordchoice :
Random motAleatoire = new Random();
String word = playerWord.get(motAleatoire.nextInt(playerWord.size()));
// Loop for the game :
int chance = 0;
while(true) {
penduEntier();
drawPendu(chance);
if (chance>word.length()) {
System.out.println("Perdu!!!!");
break;
}
displayWord(word, playerGuess);
if (!getPlayerChar(charP, word, playerGuess)) {
chance ++;
};
if(displayWord(word, playerGuess)) {
System.out.println("Victoire");
break;
}
System.out.println("Tentez votre chance pour le mot");
if(charP.nextLine().equals(word)) {
System.out.println("Victoire");
break;
} else {
System.out.println("Mot incorrect, veuillez réessayer");
}
}
}
// Méthode getPlayerChar :
private static boolean getPlayerChar(Scanner charP, String word, ArrayList<Character> playerGuess) {
System.out.println("Entrez une lettre svp");
String charPlayer = charP.nextLine();
playerGuess.add(charPlayer.charAt(0));
return word.contains(charPlayer);
}
// Méthode displayWord :
private static boolean displayWord(String word, ArrayList<Character> playerGuess) {
int count = 0;
for (int i = 0;i<word.length();i++) {
if(playerGuess.contains(word.charAt(i))) {
System.out.print(word.charAt(i));
count++;
}
else {
System.out.print("-");
}
}
System.out.println("");
return (word.length() == count);
}
// Draw Hangman Methode :
public static void penduEntier(){
// Loop through the entire 2D array to display Hangman image
for (int row = 0; row < 10; row++) {
for (int column = 0; column < 10; column++) {
System.out.print(penduDessin[row][column]);
}
System.out.println();
}
}
// Tableau 2D Hangman :
public static void drawPendu(int chance) {
// The hangman will be erected from bottom to top, that is first gallos
// base will be made and then step by step hangman will be generated.
switch(chance) {
// we do not need add break in the cases because when players misses
// word after 8 chances then complete image of hangman is created.
case 8:
// Create legs of man
penduDessin[6][6] = "/";
penduDessin[7][5] = "/";
penduDessin[6][8] = "\\";
penduDessin[7][9] = "\\";
case 6:
// Create hands of man
penduDessin[4][6] = "/";
penduDessin[5][5] = "/";
penduDessin[4][8] = "\\";
penduDessin[5][9] = "\\";
case 5:
// Create tummy of man
for(int i = 3; i <= 5; i++)
penduDessin[i][7] = "|";
case 4:
// Create eyes and nose of man
penduDessin[2][6] = "*";
penduDessin[2][7] = "!";
penduDessin[2][8] = "*";
case 3:
// Create face of man
penduDessin[2][5] = "(";
penduDessin[2][9] = ")";
case 2:
// Create gallos
for(int i = 3; i <= 7; i++)
penduDessin[0][i] = "#";
penduDessin[1][7] = "#";
case 1:
// Create gallos
for(int i = 0; i <= 9; i++)
penduDessin[i][3] = "|";
case 0:
// Create base of gallos
for(int i = 0; i <= 8; i++)
penduDessin[8][i] = "_";
break;
default:
break;
}
}
// Initialize the hangman with space :
public static void initialize2dArray()
{
// Initialize the 2d array with blank spaces before printing the
// actual image of hangman.
for (int row = 0; row < 10; row++)
{
for (int column = 0; column < 10; column++)
{
penduDessin[row][column] = " ";
}
}
}
}
Thx for your help
-
\$\begingroup\$ thanks for moving it over from stackoverflow! seems to be better place here \$\endgroup\$Martin Frank– Martin Frank2021年06月25日 13:14:57 +00:00Commented Jun 25, 2021 at 13:14
-
\$\begingroup\$ An user say me to move CodeReview. ;) \$\endgroup\$Cheg 62– Cheg 622021年06月25日 14:59:12 +00:00Commented Jun 25, 2021 at 14:59
-
\$\begingroup\$ i read it - and upvoted that proposal =) \$\endgroup\$Martin Frank– Martin Frank2021年06月25日 15:03:22 +00:00Commented Jun 25, 2021 at 15:03
1 Answer 1
minor issues: language
source code is written in english. I don't speak english and many other don't do as well. that might be one reason why this review has no answers yet.
NB_ERREURS_MAX
String penduDessin
Random motAleatoire
penduEntier()
minor issue: hard-coded strings
as said that the source code is in english same applies for texts written. to handle such that you should use constants that provide an english name (but havin foreign content)
instead of
System.out.println("Victoire");
you define a constant
static final String VICTORY_MESSAGE = "Victoire";
static final String FAIL_MESSAGE = "Perdu!!!!";
...
if (chance>word.length()) {
System.out.println(FAIL_MESSAGE);
break;
}
than everybody is able to understand the foreign text.
Another important point is that would be a more "maintainable" code since you would have all String on one place and could easily translate them. (open for enhancements
thats one part of SOLID)
minor issue: c-style array initialization
in java we declare arrays directly on the array type, instead of String penduDessin [][]
we use String[][] penduDessin
issue: single responsibility
your method displayWord()
returns a boolean, because it does two things instead one. it
- displays the word
- checks if the word has been solved
seperate them!
the same applies for getPlayerChar()
, this methods
- handles user input
- validates if it matches the secret word
major issue: objects and methods
you are using java but your code is not object orientated but procedural orientated. that leads to a lot of hard-to.read code.
use objects: that's what first got into my mind, but you can decide different:
- HangmanGame (game logic)
- HangmanWord
- HangmanDisplay
- Dictionary
- Dictionary reader
- InputReader
if you would split that code in such ways your code would be far more readable (maintainable)
public static void main(String args[]){
Dictionary dic = new Dictionary(new FileDictReader().read(DICT_FILENAME));
HangmanGame game = new HangmanGame(dict, new PlayerInputReader(), new HangmanDisplay());
game.start();
}
doing so you could clearly address tasks to object, for example getting a word from a given List:
HangmanWord wordToGuess = new HangManWord(dictionary.getRandom());
so we have a single responsibility for the dictionary: provide words!
another example would be the dictionary reader:
reading the dictionary from one source (file) and it's exception handling would be done by the DictionaryReader. you could also add another reader that lets you read URLs or any other source. The benefit would be that you don't have to change the dictionary for new readers.
major: seperate data from display
you should provide a data object for the state of your game: HangmanWord
. this state would change whenever you add a letter to the HangmanWord.
HangmanWord
is a data object and could provide all relevant information needed to play the game
HangmanWord.isSolved()
HangmanWord.isFailed()
HangmanWord.getAmountFailures()
HangmanWord.addCharacter()
HangmanWord.getHiddenWord()
HangmanWord.getGuesses()
that would ease up the way your while-loop would look like
after-Thoughts
you should always try to avoid hard coupling, but hangman is a challenge. to avoid the direct dependency between HangmanWord
and HangmanPrinter
is not easily to achieve, since they are hardly connected by the amount of failures of the HangmanWord
(and therefore the shape of the hangman). you already detected that dependency by using NB_ERREURS_MAX
- i would really like to see a solution, where you (anyone) solved this dependency ^_^
-
1\$\begingroup\$ Thx a lot for your response \$\endgroup\$Cheg 62– Cheg 622021年07月01日 06:46:14 +00:00Commented Jul 1, 2021 at 6:46
-
\$\begingroup\$ you can accept the answer if you think it was helpful ;-) \$\endgroup\$Martin Frank– Martin Frank2021年07月01日 07:15:48 +00:00Commented Jul 1, 2021 at 7:15