Compare commits

9 Commits

15 changed files with 2170 additions and 17 deletions

29
Makefile Normal file
View File

@@ -0,0 +1,29 @@
# === Configuration ===
SRC_DIR = src
OUT_DIR = out
PACKAGE = fr/iut/Projet
MAIN_CLASS = fr.iut.Projet.Display
# === Règle principale ===
all: compile run
# === Compilation ===
compile:
@echo "Compilation du projet..."
@mkdir -p $(OUT_DIR)
# 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."
# === Exécution ===
run:
@echo "Exécution du programme..."
@java -cp $(OUT_DIR) $(MAIN_CLASS)
# === Nettoyage ===
clean:
@echo "Suppression des fichiers compilés..."
@rm -rf $(OUT_DIR)
@echo "Nettoyage terminé."

Binary file not shown.

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.

835
out/fr/iut/Projet/Word.txt Normal file

File diff suppressed because it is too large Load Diff

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

@@ -0,0 +1,177 @@
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 {
/** Nombre de vies restantes (entre 0 et 8). */
private int lives = 8;
/** Indique si le joueur a gagné. */
private boolean youWin = false;
/**
* 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);
if (isOpaque()) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
Graphics2D g2 = (Graphics2D) g.create();
g2.setStroke(new BasicStroke(3));
g2.setColor(Color.BLACK);
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) {
g2.drawLine(50, 350, 200, 350);
g2.drawLine(100, 350, 100, 50);
g2.drawLine(100, 50, 250, 50);
g2.drawLine(250, 50, 250, 100);
g2.drawLine(100, 100, 180, 50);
}
// 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;
/** Dessine la tête du pendu. */
private void drawHead(Graphics2D g2) { g2.drawOval(headX, headY, headDiam, headDiam); }
/** 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);
}
/** 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);
g2.drawLine(bodyX, bodyYStart, bodyX, bodyYEnd);
g2.drawLine(bodyX, bodyYStart + 20, bodyX - armLength, bodyYStart + 20);
g2.drawLine(bodyX, bodyYStart + 20, bodyX + armLength, bodyYStart + 20);
g2.drawLine(bodyX, bodyYEnd, bodyX - 5, bodyYEnd + legLength);
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;
g2.setColor(Color.BLACK);
g2.fillOval(skullX, skullY, skullDiam, skullDiam);
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);
g2.fillOval(skullX + skullDiam / 2 - skullDiam / 12, skullY + skullDiam / 2 - skullDiam / 12, skullDiam / 6, skullDiam / 6);
g2.setStroke(new BasicStroke(2));
g2.drawLine(skullX + skullDiam / 5, skullY + 2 * skullDiam / 3,
skullX + 4 * skullDiam / 5, skullY + 2 * skullDiam / 3);
g2.setColor(Color.RED);
g2.setFont(new Font("Arial", Font.BOLD, 36));
String message = "GAME OVER";
FontMetrics fm = g2.getFontMetrics();
int textWidth = fm.stringWidth(message);
int xText = (getWidth() - textWidth) / 2;
int yText = skullY - 20;
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));
String message = "YOU WIN";
FontMetrics fm = g2.getFontMetrics();
int textWidth = fm.stringWidth(message);
int xText = (getWidth() - textWidth) / 2;
int yText = 50;
g2.drawString(message, xText, yText);
}
}

View File

@@ -0,0 +1,116 @@
package fr.iut.Projet;
import java.io.*;
import java.util.*;
public class Random_word {
private String secretWord;
private char[] hiddenWord;
private Set<Character> lettersGuessed;
private Set<Character> incorrectLetters;
private int lives;
/**
* 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 !");
}
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.
*/
private String getRandomWord() {
InputStream is = Random_word.class.getResourceAsStream("Word.txt");
if (is == null) return null;
String randomWord = null;
Random random = new Random();
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String line;
int count = 0;
while ((line = br.readLine()) != null) {
line = line.trim();
if (!line.isEmpty()) {
count++;
if (random.nextInt(count) == 0) {
randomWord = line;
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return randomWord != null ? randomWord.toLowerCase() : null;
}
/**
* Tente une lettre, met à jour l'état du jeu et retourne un message.
*/
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.";
}
}
public String getHiddenWord() {
StringBuilder sb = new StringBuilder();
for (char c : hiddenWord) sb.append(c).append(' ');
return sb.toString().trim();
}
public String getIncorrectLetters() {
return incorrectLetters.toString();
}
public int getLives() {
return lives;
}
public boolean isGameOver() {
return lives <= 0 || isWon();
}
public boolean isWon() {
for (char c : hiddenWord) {
if (c == '_') {
return false;
}
}
return true;
}
public String getSecretWord() {
return secretWord;
}
}

835
src/fr/iut/Projet/Word.txt Normal file

File diff suppressed because it is too large Load Diff