Compare commits

...

3 Commits

Author SHA1 Message Date
7d2a0a12f9 Affichage intégré 2025-10-08 14:55:22 +02:00
aef5c7f70c Merge branch 'Hugo' 2025-10-08 14:12:42 +02:00
b60bda7ae0 mise en relation affichage et jeu et bouton relance 2025-10-08 13:43:58 +02:00
13 changed files with 339 additions and 163 deletions

View File

@@ -2,7 +2,7 @@
SRC_DIR = src
OUT_DIR = out
PACKAGE = fr/iut/Projet
MAIN_CLASS = fr.iut.Projet.Random_word
MAIN_CLASS = fr.iut.Projet.Display
# === Règle principale ===
all: compile run
@@ -11,7 +11,9 @@ all: compile run
compile:
@echo "Compilation du projet..."
@mkdir -p $(OUT_DIR)
@javac -d $(OUT_DIR) $(SRC_DIR)/$(PACKAGE)/Random_word.java
# Compilation de tous les fichiers Java du package
@javac -d $(OUT_DIR) $(SRC_DIR)/$(PACKAGE)/*.java
# Copier Word.txt dans le dossier de sortie
@cp $(SRC_DIR)/$(PACKAGE)/Word.txt $(OUT_DIR)/$(PACKAGE)/
@echo "Compilation terminée."

BIN
out/Affiche.class Normal file

Binary file not shown.

BIN
out/Mouse.class Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -4,28 +4,189 @@ import javax.swing.*;
import java.awt.*;
/**
* Classe Action représentant la fenêtre principale du jeu "Hanging Man".
* Affiche un message de bienvenue.
* Classe principale qui gère l'interface graphique du jeu du pendu.
* <p>
* Cette classe crée la fenêtre du jeu, affiche le mot caché, les lettres incorrectes,
* le dessin du pendu (via {@link Affiche}), et permet à l'utilisateur de saisir des lettres.
* Elle gère également la logique de mise à jour et la fin de partie.
* </p>
*
* @author
* @version 1.0
*/
public class Action {
/** Fenêtre principale du jeu. */
private JFrame gameFrame;
/** Label affichant le mot caché avec les lettres découvertes. */
private JLabel wordLabel;
/** Label affichant la liste des lettres incorrectes. */
private JLabel incorrectLettersLabel;
/** Champ de texte permettant à l'utilisateur d'entrer une lettre. */
private JTextField letterInputField;
/** Instance du jeu, contenant la logique (mot, vies, lettres, etc.). */
private Random_word game;
/** Composant graphique qui affiche le dessin du pendu. */
private Affiche affiche;
/**
* Constructeur. Crée et affiche la fenêtre du jeu avec un message.
* Constructeur de la classe {@code Action}.
* <p>
* Initialise le jeu, crée les composants graphiques, met en place la mise en page
* et affiche la fenêtre du jeu.
* </p>
*/
public Action() {
// Création de la fenêtre du jeu
JFrame gameFrame = new JFrame("Hanging Man");
gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gameFrame.setSize(1040, 1000);
gameFrame.setLayout(new BorderLayout());
// Label de bienvenue
JLabel label = new JLabel("Bienvenue dans le jeu !");
label.setFont(new Font("Arial", Font.BOLD, 28));
label.setHorizontalAlignment(SwingConstants.CENTER);
// Ajouter le label et afficher la fenêtre
gameFrame.add(label, BorderLayout.CENTER);
game = new Random_word();
initializeComponents();
layoutComponents();
letterInputField.addActionListener(e -> handleGuess());
gameFrame.setVisible(true);
}
}
// ==================== Initialisation ====================
/**
* Initialise tous les composants graphiques (labels, champs, boutons...).
*/
private void initializeComponents() {
gameFrame = new JFrame("Hanging Man");
gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gameFrame.setSize(700, 500);
affiche = new Affiche();
affiche.setPreferredSize(new Dimension(350, 400));
affiche.setBackground(Color.WHITE);
affiche.setOpaque(true);
wordLabel = new JLabel(game.getHiddenWord());
wordLabel.setFont(new Font("Arial", Font.BOLD, 32));
wordLabel.setHorizontalAlignment(SwingConstants.CENTER);
incorrectLettersLabel = new JLabel("Incorrect letters: " + game.getIncorrectLetters());
incorrectLettersLabel.setFont(new Font("Arial", Font.PLAIN, 20));
incorrectLettersLabel.setHorizontalAlignment(SwingConstants.CENTER);
letterInputField = new JTextField(3);
letterInputField.setFont(new Font("Arial", Font.PLAIN, 24));
}
// ==================== Mise en page ====================
/**
* Dispose les composants graphiques dans la fenêtre selon un {@link BorderLayout}.
*/
private void layoutComponents() {
JPanel mainPanel = new JPanel(new BorderLayout());
// --- panneau gauche : dessin du pendu ---
JPanel leftPanel = new JPanel(new BorderLayout());
leftPanel.add(affiche, BorderLayout.CENTER);
mainPanel.add(leftPanel, BorderLayout.WEST);
// --- panneau droit : interface du jeu ---
JPanel rightPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.insets = new Insets(5, 5, 5, 5);
// Mot caché
gbc.gridy = 0;
gbc.weighty = 1.0;
rightPanel.add(wordLabel, gbc);
// Lettres incorrectes
gbc.gridy = 1;
rightPanel.add(incorrectLettersLabel, gbc);
// Champ de saisie
gbc.gridy = 2;
JPanel inputRow = new JPanel();
inputRow.add(new JLabel("Enter a letter:"));
inputRow.add(letterInputField);
rightPanel.add(inputRow, gbc);
// Bouton de redémarrage
gbc.gridy = 3;
JButton restartButton = new JButton("Restart");
restartButton.addActionListener(new PlayButtonListener(gameFrame));
rightPanel.add(restartButton, gbc);
mainPanel.add(rightPanel, BorderLayout.CENTER);
gameFrame.add(mainPanel);
}
// ==================== Gestion du jeu ====================
/**
* Gère la saisie d'une lettre par le joueur.
* <p>
* Vérifie la validité de la lettre, met à jour le jeu, l'affichage
* et teste si la partie est terminée.
* </p>
*/
private void handleGuess() {
String inputText = letterInputField.getText();
letterInputField.setText("");
if (!isValidInput(inputText)) return;
char guessedLetter = inputText.charAt(0);
String message = game.guessLetter(guessedLetter);
updateUI();
if (game.isGameOver()) endGame(message);
}
/**
* Vérifie que la saisie de l'utilisateur est une seule lettre valide.
*
* @param inputText texte saisi dans le champ de saisie
* @return {@code true} si la saisie est valide, {@code false} sinon
*/
private boolean isValidInput(String inputText) {
if (inputText.length() != 1 || !Character.isLetter(inputText.charAt(0))) {
JOptionPane.showMessageDialog(gameFrame, "Please enter a single letter!");
return false;
}
return true;
}
/**
* Met à jour les éléments de l'interface graphique :
* <ul>
* <li>le mot affiché,</li>
* <li>les lettres incorrectes,</li>
* <li>et le dessin du pendu selon les vies restantes.</li>
* </ul>
*/
private void updateUI() {
wordLabel.setText(game.getHiddenWord());
incorrectLettersLabel.setText("Incorrect letters: " + game.getIncorrectLetters());
affiche.setLives(game.getLives());
}
/**
* Termine la partie en affichant un message selon le résultat (victoire ou défaite)
* et empêche de nouvelles saisies.
*
* @param message message à afficher dans une boîte de dialogue
*/
private void endGame(String message) {
if (game.isWon()) {
affiche.setYouWin(true);
} else {
affiche.setLives(0);
}
JOptionPane.showMessageDialog(gameFrame, message);
letterInputField.setEditable(false);
}
}

View File

@@ -1,20 +1,58 @@
package fr.iut.Projet;
import javax.swing.*;
import java.awt.*;
/**
* Classe graphique responsable du dessin du pendu dans le jeu.
* <p>
* Cette classe hérite de {@link JComponent} et redéfinit la méthode
* {@link #paintComponent(Graphics)} pour afficher le pendu selon le nombre
* de vies restantes. Elle affiche également un message de victoire ou de défaite.
* </p>
*
* @author
* @version 1.0
*/
class Affiche extends JComponent {
private int step = 0;
/** Nombre de vies restantes (entre 0 et 8). */
private int lives = 8;
/** Indique si le joueur a gagné. */
private boolean youWin = false;
public void setStep(int step) {
this.step = step;
/**
* Définit le nombre de vies restantes et redessine le composant.
*
* @param lives nombre de vies restantes
*/
public void setLives(int lives) {
this.lives = lives;
repaint();
}
/**
* Définit si le joueur a gagné et redessine le composant.
*
* @param value {@code true} si le joueur a gagné, sinon {@code false}
*/
public void setYouWin(boolean value) {
this.youWin = value;
repaint();
}
/**
* Redessine le pendu en fonction du nombre de vies restantes.
* <ul>
* <li>Affiche la potence dès la première erreur</li>
* <li>Ajoute progressivement les membres du pendu</li>
* <li>Affiche une tête de mort si toutes les vies sont perdues</li>
* <li>Affiche un message "YOU WIN" si la partie est gagnée</li>
* </ul>
*
* @param g contexte graphique utilisé pour dessiner
*/
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
@@ -28,43 +66,67 @@ class Affiche extends JComponent {
g2.setStroke(new BasicStroke(3));
g2.setColor(Color.BLACK);
drawGallows(g2);
drawHangman(g2);
if (step >= 7) drawSkull(g2);
if (lives <= 7) drawGallows(g2);
if (lives <= 6) drawHead(g2);
if (lives <= 5) drawBody(g2);
if (lives <= 4) drawLeftArm(g2);
if (lives <= 3) drawRightArm(g2);
if (lives <= 2) drawLeftLeg(g2);
if (lives <= 1) drawRightLeg(g2);
if (lives == 1) drawAura(g2);
if (lives == 0) drawSkull(g2);
if (youWin) drawYouWinMessage(g2);
g2.dispose();
}
// ==================== Méthodes de dessin ====================
/** Dessine la potence. */
private void drawGallows(Graphics2D g2) {
// Base and vertical post
g2.drawLine(50, 350, 200, 350);
g2.drawLine(100, 350, 100, 50);
// Horizontal beam and rope
g2.drawLine(100, 50, 250, 50);
g2.drawLine(250, 50, 250, 100);
// Diagonal support
g2.drawLine(100, 100, 180, 50);
}
private void drawHangman(Graphics2D g2) {
int headX = 225, headY = 100, headDiam = 50;
int bodyX = headX + headDiam / 2, bodyYStart = headY + headDiam, bodyYEnd = bodyYStart + 100;
int armLength = 60;
int legLength = 70;
// Coordonnées et tailles du pendu
private final int headX = 225, headY = 100, headDiam = 50;
private final int bodyX = headX + headDiam / 2;
private final int bodyYStart = headY + headDiam;
private final int bodyYEnd = bodyYStart + 100;
private final int armLength = 60;
private final int legLength = 70;
if (step >= 1) g2.drawOval(headX, headY, headDiam, headDiam); // head
if (step >= 2) g2.drawLine(bodyX, bodyYStart, bodyX, bodyYEnd); // body
if (step >= 3) g2.drawLine(bodyX, bodyYStart + 20, bodyX - armLength, bodyYStart + 20); // left arm
if (step >= 4) g2.drawLine(bodyX, bodyYStart + 20, bodyX + armLength, bodyYStart + 20); // right arm
if (step >= 5) g2.drawLine(bodyX, bodyYEnd, bodyX - 5, bodyYEnd + legLength); // left leg
if (step >= 6) g2.drawLine(bodyX, bodyYEnd, bodyX + 5, bodyYEnd + legLength); // right leg
/** Dessine la tête du pendu. */
private void drawHead(Graphics2D g2) { g2.drawOval(headX, headY, headDiam, headDiam); }
if (step == 6) drawAura(g2, headX, headY, headDiam, bodyX, bodyYStart, bodyYEnd, armLength, legLength);
/** Dessine le corps du pendu. */
private void drawBody(Graphics2D g2) { g2.drawLine(bodyX, bodyYStart, bodyX, bodyYEnd); }
/** Dessine le bras gauche. */
private void drawLeftArm(Graphics2D g2) {
g2.drawLine(bodyX, bodyYStart + 20, bodyX - armLength, bodyYStart + 20);
}
private void drawAura(Graphics2D g2, int headX, int headY, int headDiam, int bodyX, int bodyYStart, int bodyYEnd, int armLength, int legLength) {
/** Dessine le bras droit. */
private void drawRightArm(Graphics2D g2) {
g2.drawLine(bodyX, bodyYStart + 20, bodyX + armLength, bodyYStart + 20);
}
/** Dessine la jambe gauche. */
private void drawLeftLeg(Graphics2D g2) {
g2.drawLine(bodyX, bodyYEnd, bodyX - 5, bodyYEnd + legLength);
}
/** Dessine la jambe droite. */
private void drawRightLeg(Graphics2D g2) {
g2.drawLine(bodyX, bodyYEnd, bodyX + 5, bodyYEnd + legLength);
}
/** Dessine une aura bleue lorsque le joueur est sur sa dernière vie. */
private void drawAura(Graphics2D g2) {
g2.setColor(new Color(0, 0, 255, 100));
g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.drawOval(headX, headY, headDiam, headDiam);
@@ -75,27 +137,22 @@ class Affiche extends JComponent {
g2.drawLine(bodyX, bodyYEnd, bodyX + 5, bodyYEnd + legLength);
}
/** Dessine la tête de mort et le message "GAME OVER". */
private void drawSkull(Graphics2D g2) {
int skullX = 225, skullY = 100, skullDiam = 50;
// Skull
g2.setColor(Color.BLACK);
g2.fillOval(skullX, skullY, skullDiam, skullDiam);
// Eyes
g2.setColor(Color.WHITE);
g2.fillOval(skullX + skullDiam / 5, skullY + skullDiam / 6, skullDiam / 5, skullDiam / 5);
g2.fillOval(skullX + 3 * skullDiam / 5, skullY + skullDiam / 6, skullDiam / 5, skullDiam / 5);
// Nose
g2.fillOval(skullX + skullDiam / 2 - skullDiam / 12, skullY + skullDiam / 2 - skullDiam / 12, skullDiam / 6, skullDiam / 6);
// Mouth
g2.setStroke(new BasicStroke(2));
g2.drawLine(skullX + skullDiam / 5, skullY + 2 * skullDiam / 3,
skullX + 4 * skullDiam / 5, skullY + 2 * skullDiam / 3);
// GAME OVER message
g2.setColor(Color.RED);
g2.setFont(new Font("Arial", Font.BOLD, 36));
String message = "GAME OVER";
@@ -106,6 +163,7 @@ class Affiche extends JComponent {
g2.drawString(message, xText, yText);
}
/** Dessine le message "YOU WIN" en vert en cas de victoire. */
private void drawYouWinMessage(Graphics2D g2) {
g2.setColor(Color.GREEN);
g2.setFont(new Font("Arial", Font.BOLD, 36));
@@ -116,4 +174,4 @@ class Affiche extends JComponent {
int yText = 50;
g2.drawString(message, xText, yText);
}
}
}

View File

@@ -1,25 +0,0 @@
import java.awt.event.*;
import javax.swing.SwingUtilities;
class Mouse extends MouseAdapter {
private Affiche aff;
private int step = 0; // correspond à Affiche.step
public Mouse(Affiche aff) {
this.aff = aff;
}
@Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
// clic droit -> gagne
aff.setYouWin(true);
} else {
// clic gauche -> incrémente étape
if (step < 7) {
step++;
aff.setStep(step); // <-- utiliser setStep
}
}
}
}

View File

@@ -5,132 +5,112 @@ import java.util.*;
public class Random_word {
public static void main(String[] args) {
// Récupère un mot aléatoire depuis le fichier Word.txt
String randomword = getRandomWord();
private String secretWord;
private char[] hiddenWord;
private Set<Character> lettersGuessed;
private Set<Character> incorrectLetters;
private int lives;
if (randomword == null) {
System.err.println("Impossible de choisir un mot aléatoire !");
return;
/**
* Constructeur : sélectionne un mot aléatoire et initialise le jeu.
*/
public Random_word() {
this.secretWord = getRandomWord();
if (this.secretWord == null) {
throw new RuntimeException("Impossible de choisir un mot aléatoire !");
}
// Démarre le jeu avec le mot choisi
play(randomword);
this.lives = 8;
this.hiddenWord = new char[secretWord.length()];
Arrays.fill(this.hiddenWord, '_');
this.lettersGuessed = new HashSet<>();
this.incorrectLetters = new HashSet<>();
}
/**
* Lit les mots dans "Word.txt" et retourne un mot aléatoire.
* @return un mot aléatoire en minuscules, ou null si le fichier est introuvable ou vide
*/
public static String getRandomWord() {
// Charge le fichier Word.txt depuis le package
private String getRandomWord() {
InputStream is = Random_word.class.getResourceAsStream("Word.txt");
if (is == null) {
System.err.println("Le fichier 'Word.txt' est introuvable dans le package !");
return null;
}
if (is == null) return null;
String randomWord = null;
Random random = new Random();
try (BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(is))) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String line;
int count = 0;
// Parcourt chaque ligne du fichier
while ((line = bufferedreader.readLine()) != null) {
while ((line = br.readLine()) != null) {
line = line.trim();
if (!line.isEmpty()) {
count++;
// Sélection aléatoire d'un mot (méthode reservoir sampling)
if (random.nextInt(count) == 0) {
randomWord = line;
}
}
}
} catch (IOException e) {
System.err.println("Erreur lors de la lecture du fichier : " + e.getMessage());
e.printStackTrace();
}
return randomWord != null ? randomWord.toLowerCase() : null;
}
/**
* Affiche l'état actuel du mot et les lettres incorrectes.
* @param hiddenWord le mot masqué avec les lettres découvertes
* @param incorrectLetters les lettres déjà essayées mais incorrectes
* Tente une lettre, met à jour l'état du jeu et retourne un message.
*/
private static void showwordstatus(char[] hiddenWord, Set<Character> incorrectLetters) {
System.out.print("\nMot actuel : ");
for (char Character : hiddenWord) {
System.out.print(Character + " ");
public String guessLetter(char letter) {
letter = Character.toLowerCase(letter);
if (lettersGuessed.contains(letter) || incorrectLetters.contains(letter)) {
return "Vous avez déjà essayé cette lettre !";
}
if (secretWord.indexOf(letter) >= 0) {
lettersGuessed.add(letter);
for (int i = 0; i < secretWord.length(); i++) {
if (secretWord.charAt(i) == letter) {
hiddenWord[i] = letter;
}
}
if (isWon()) {
return "Félicitations ! Vous avez trouvé le mot : " + secretWord;
}
return "Bien joué !";
} else {
incorrectLetters.add(letter);
lives--;
if (lives <= 0) {
return "Vous avez perdu ! Le mot était : " + secretWord;
}
return "Mauvaise lettre ! Il vous reste " + lives + " vies.";
}
System.out.println();
System.out.println("Lettres incorrectes : " + incorrectLetters);
}
/**
* Logique principale du jeu : gère les essais, met à jour l'état du mot,
* suit le nombre de vies restantes, et détermine la victoire ou la défaite.
* @param secretWord le mot que le joueur doit deviner
*/
public static void play(String secretWord) {
Scanner scanner = new Scanner(System.in);
Set<Character> lettersGuessed = new HashSet<>();
Set<Character> incorrectLetters = new HashSet<>();
int lives = 8; // nombre d'essais
public String getHiddenWord() {
StringBuilder sb = new StringBuilder();
for (char c : hiddenWord) sb.append(c).append(' ');
return sb.toString().trim();
}
char[] hiddenWord = new char[secretWord.length()];
Arrays.fill(hiddenWord, '_');
public String getIncorrectLetters() {
return incorrectLetters.toString();
}
System.out.println("Bienvenue dans le jeu du mot mystère !");
System.out.println("Le mot contient " + secretWord.length() + " lettres.");
public int getLives() {
return lives;
}
while (lives > 0) {
// Affiche le mot actuel et les lettres incorrectes
showwordstatus(hiddenWord, incorrectLetters);
public boolean isGameOver() {
return lives <= 0 || isWon();
}
System.out.print("Entrez une lettre : ");
String input = scanner.nextLine().toLowerCase();
// Vérifie que l'entrée est valide
if (input.length() != 1 || !Character.isLetter(input.charAt(0))) {
System.out.println("Entrez une seule lettre !");
continue;
}
char letter = input.charAt(0);
// Vérifie si la lettre a déjà été essayée
if (lettersGuessed.contains(letter) || incorrectLetters.contains(letter)) {
System.out.println("Vous avez déjà essayé cette lettre !");
continue;
}
// Vérifie si la lettre fait partie du mot secret
if (secretWord.indexOf(letter) >= 0) {
lettersGuessed.add(letter);
for (int i = 0; i < secretWord.length(); i++) {
if (secretWord.charAt(i) == letter) {
hiddenWord[i] = letter;
}
}
System.out.println("Bien joué !");
} else {
// Lettre incorrecte : décrémente le nombre de vies
incorrectLetters.add(letter);
lives--;
System.out.println("Mauvaise lettre ! Il vous reste " + lives + " vies.");
}
// Vérifie si le mot complet a été trouvé
if (String.valueOf(hiddenWord).equals(secretWord)) {
System.out.println("\nFélicitations ! Vous avez trouvé le mot : " + secretWord);
return;
public boolean isWon() {
for (char c : hiddenWord) {
if (c == '_') {
return false;
}
}
return true;
}
// Le joueur a perdu
System.out.println("\nVous avez perdu ! Le mot était : " + secretWord);
public String getSecretWord() {
return secretWord;
}
}