forked from menault/TD3_DEV51_Qualite_Algo
		
	Compare commits
	
		
			27 Commits
		
	
	
		
			1741908a9d
			...
			dick
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e649d30b33 | |||
| 584e8dc3c6 | |||
| 82b4e0ffd1 | |||
| 9cb9088b81 | |||
| 77b3158262 | |||
| 0f7c1f6b71 | |||
| 87909bbe35 | |||
| 9d7c681ca3 | |||
| e6e0d4cf71 | |||
| ffbe1e232e | |||
| a3627d9023 | |||
| 2a8eac0720 | |||
| 7206dca3ef | |||
| 0fa7ec527f | |||
| f7aecb038d | |||
| 62f6f94be7 | |||
| 90874a3296 | |||
| 49e32b316e | |||
| 06daa4e478 | |||
| 35c9fcd873 | |||
| ba7e16dc64 | |||
| 721543075c | |||
| d7ace2c8be | |||
| 56009640f5 | |||
| 80264f552f | |||
| 258aab00f3 | |||
| 5e8e4a1183 | 
							
								
								
									
										39
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								Makefile
									
									
									
									
									
								
							@@ -12,14 +12,47 @@ OUT = bin/
 | 
				
			|||||||
JC = javac
 | 
					JC = javac
 | 
				
			||||||
JCFLAGS = -encoding UTF-8 -implicit:none -cp $(OUT) -d $(OUT)
 | 
					JCFLAGS = -encoding UTF-8 -implicit:none -cp $(OUT) -d $(OUT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CLASSFILES = Pendu.class # \
 | 
					CLASSFILES = Pendu.class \
 | 
				
			||||||
 | 
						Partie.class \
 | 
				
			||||||
 | 
						Fenetre.class \
 | 
				
			||||||
 | 
						Dessin.class \
 | 
				
			||||||
 | 
						Mots.class \
 | 
				
			||||||
 | 
						Event.class \
 | 
				
			||||||
 | 
						LetterInputFilter.class \
 | 
				
			||||||
 | 
						MenuDifficulte.class \
 | 
				
			||||||
 | 
						Chronometre.class \
 | 
				
			||||||
 | 
						Score.class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Dépendances
 | 
					# Dépendances
 | 
				
			||||||
$(OUT)Pendu.class : $(IN)Pendu.java # $(OUT)Fichier.class $(OUT)Cible.class $(OUT)Systeme.class
 | 
					$(OUT)Pendu.class : $(IN)Pendu.java $(OUT)Partie.class $(OUT)Fenetre.class $(OUT)Event.class $(OUT)MenuDifficulte.class $(OUT)Score.class
 | 
				
			||||||
	$(JC) $(JCFLAGS) $<
 | 
						$(JC) $(JCFLAGS) $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OUT)Partie.class : $(IN)Partie.java $(OUT)Mots.class
 | 
				
			||||||
 | 
						$(JC) $(JCFLAGS) $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OUT)Fenetre.class : $(IN)Fenetre.java $(OUT)Partie.class $(OUT)Dessin.class $(OUT)Chronometre.class $(OUT)Score.class
 | 
				
			||||||
 | 
						$(JC) $(JCFLAGS) $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OUT)Dessin.class : $(IN)Dessin.java
 | 
				
			||||||
 | 
						$(JC) $(JCFLAGS) $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OUT)Mots.class : $(IN)Mots.java
 | 
				
			||||||
 | 
						$(JC) $(JCFLAGS) $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OUT)Event.class : $(IN)Event.java $(OUT)Fenetre.class $(OUT)LetterInputFilter.class
 | 
				
			||||||
 | 
						$(JC) $(JCFLAGS) $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OUT)LetterInputFilter.class : $(IN)LetterInputFilter.java $(OUT)Fenetre.class
 | 
				
			||||||
 | 
						$(JC) $(JCFLAGS) $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OUT)MenuDifficulte.class : $(IN)MenuDifficulte.java
 | 
				
			||||||
 | 
						$(JC) $(JCFLAGS) $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OUT)Chronometre.class : $(IN)Chronometre.java
 | 
				
			||||||
 | 
						$(JC) $(JCFLAGS) $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(OUT)Score.class : $(IN)Score.java
 | 
				
			||||||
 | 
						$(JC) $(JCFLAGS) $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Commandes
 | 
					# Commandes
 | 
				
			||||||
Pendu : $(OUT)Pendu.class
 | 
					Pendu : $(OUT)Pendu.class
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										83
									
								
								src/Chronometre.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/Chronometre.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.awt.*;
 | 
				
			||||||
 | 
					import java.awt.event.ActionEvent;
 | 
				
			||||||
 | 
					import java.awt.event.ActionListener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Composant chronomètre (mm:ss) pour le jeu du pendu.
 | 
				
			||||||
 | 
					 * - Démarre/stoppe/réinitialise le temps
 | 
				
			||||||
 | 
					 * - S'affiche comme une barre en haut de la fenêtre
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @version 1.0
 | 
				
			||||||
 | 
					 * @author Adrien
 | 
				
			||||||
 | 
					 * Date : 08-10-2025
 | 
				
			||||||
 | 
					 * Licence :
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class Chronometre extends JPanel implements ActionListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final JLabel timeLabel = new JLabel("00:00", SwingConstants.CENTER);
 | 
				
			||||||
 | 
					    private final Timer timer; // tick chaque seconde
 | 
				
			||||||
 | 
					    private boolean running = false;
 | 
				
			||||||
 | 
					    private long startMillis = 0L;
 | 
				
			||||||
 | 
					    private long accumulatedMillis = 0L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Chronometre() {
 | 
				
			||||||
 | 
					        setLayout(new BorderLayout());
 | 
				
			||||||
 | 
					        setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
 | 
				
			||||||
 | 
					        timeLabel.setFont(new Font("Segoe UI", Font.BOLD, 20));
 | 
				
			||||||
 | 
					        add(timeLabel, BorderLayout.CENTER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Timer Swing (1s)
 | 
				
			||||||
 | 
					        timer = new Timer(1000, this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Démarre le chronomètre (ou reprend si en pause). */
 | 
				
			||||||
 | 
					    public void start() {
 | 
				
			||||||
 | 
					        if (!running) {
 | 
				
			||||||
 | 
					            running = true;
 | 
				
			||||||
 | 
					            startMillis = System.currentTimeMillis();
 | 
				
			||||||
 | 
					            timer.start();
 | 
				
			||||||
 | 
					            repaint();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Met en pause le chronomètre. */
 | 
				
			||||||
 | 
					    public void stop() {
 | 
				
			||||||
 | 
					        if (running) {
 | 
				
			||||||
 | 
					            running = false;
 | 
				
			||||||
 | 
					            accumulatedMillis += System.currentTimeMillis() - startMillis;
 | 
				
			||||||
 | 
					            timer.stop();
 | 
				
			||||||
 | 
					            repaint();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Remet le chronomètre à 00:00 (sans le relancer). */
 | 
				
			||||||
 | 
					    public void reset() {
 | 
				
			||||||
 | 
					        running = false;
 | 
				
			||||||
 | 
					        startMillis = 0L;
 | 
				
			||||||
 | 
					        accumulatedMillis = 0L;
 | 
				
			||||||
 | 
					        timer.stop();
 | 
				
			||||||
 | 
					        updateLabel(0L);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Temps écoulé total (en millisecondes). */
 | 
				
			||||||
 | 
					    public long getElapsedMillis() {
 | 
				
			||||||
 | 
					        long now = System.currentTimeMillis();
 | 
				
			||||||
 | 
					        long runningMillis = running ? (now - startMillis) : 0L;
 | 
				
			||||||
 | 
					        return accumulatedMillis + runningMillis;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Tick du timer : met à jour l'affichage. */
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void actionPerformed(ActionEvent actionEvent) {
 | 
				
			||||||
 | 
					        updateLabel(getElapsedMillis());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // --- interne ---
 | 
				
			||||||
 | 
					    private void updateLabel(long elapsedMillis) {
 | 
				
			||||||
 | 
					        long totalSeconds = elapsedMillis / 1000;
 | 
				
			||||||
 | 
					        long minutes = totalSeconds / 60;
 | 
				
			||||||
 | 
					        long seconds = totalSeconds % 60;
 | 
				
			||||||
 | 
					        timeLabel.setText(String.format("%02d:%02d", minutes, seconds));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										103
									
								
								src/Dessin.java
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								src/Dessin.java
									
									
									
									
									
								
							@@ -1,23 +1,102 @@
 | 
				
			|||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.awt.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
* La classe <code>Dessin</code>
 | 
					* La classe <code>Dessin</code> gère uniquement le dessin du pendu,
 | 
				
			||||||
 | 
					* avec révélation progressive en fonction du nombre d'erreurs (stage).
 | 
				
			||||||
*
 | 
					*
 | 
				
			||||||
* @version
 | 
					* @version 1.1
 | 
				
			||||||
* @author
 | 
					* author Adrien
 | 
				
			||||||
* Date :
 | 
					* Date : 08-10-2025
 | 
				
			||||||
* Licence :
 | 
					 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
public class Dessin {
 | 
					public class Dessin extends JPanel {
 | 
				
			||||||
   //Attributs
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   //Constructeur
 | 
					    /** Nombre d'étapes max pour le personnage (hors potence). */
 | 
				
			||||||
 | 
					    public static final int MAX_STAGE = 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Étape actuelle (erreurs) : 0..6 */
 | 
				
			||||||
 | 
					    private int stage = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // --- Constructeur ---
 | 
				
			||||||
    public Dessin() {
 | 
					    public Dessin() {
 | 
				
			||||||
 | 
					        setPreferredSize(new Dimension(600, 350));
 | 
				
			||||||
 | 
					        setBackground(new Color(245, 245, 245));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Définit l'étape (nb d'erreurs) et redessine. */
 | 
				
			||||||
 | 
					    public void setStage(int newStage) {
 | 
				
			||||||
 | 
					        int clamped = Math.max(0, Math.min(newStage, MAX_STAGE));
 | 
				
			||||||
 | 
					        if (clamped != this.stage) {
 | 
				
			||||||
 | 
					            this.stage = clamped;
 | 
				
			||||||
 | 
					            repaint();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
   //Méthodes
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   //Affichage
 | 
					    public int getStage() { return stage; }
 | 
				
			||||||
   public String toString() {
 | 
					
 | 
				
			||||||
      return "" ;
 | 
					    // --- Dessin principal ---
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected void paintComponent(Graphics graphics) {
 | 
				
			||||||
 | 
					        super.paintComponent(graphics);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Graphics2D g2 = (Graphics2D) graphics.create();
 | 
				
			||||||
 | 
					        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 | 
				
			||||||
 | 
					        g2.setStroke(new BasicStroke(3f));
 | 
				
			||||||
 | 
					        g2.setColor(Color.DARK_GRAY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Repères et proportions
 | 
				
			||||||
 | 
					        int width = getWidth();
 | 
				
			||||||
 | 
					        int height = getHeight();
 | 
				
			||||||
 | 
					        int margin = Math.min(width, height) / 12;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Potence (toujours affichée)
 | 
				
			||||||
 | 
					        int baseY = height - margin;
 | 
				
			||||||
 | 
					        g2.drawLine(margin, baseY, width / 2, baseY);                 // socle
 | 
				
			||||||
 | 
					        int postX = margin + (width / 12);
 | 
				
			||||||
 | 
					        g2.drawLine(postX, baseY, postX, margin);                      // montant
 | 
				
			||||||
 | 
					        int beamLength = width / 3;
 | 
				
			||||||
 | 
					        g2.drawLine(postX, margin, postX + beamLength, margin);        // traverse
 | 
				
			||||||
 | 
					        g2.drawLine(postX, margin + height / 10, postX + width / 12, margin); // renfort
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Corde (toujours)
 | 
				
			||||||
 | 
					        int ropeX = postX + beamLength;
 | 
				
			||||||
 | 
					        int ropeTopY = margin;
 | 
				
			||||||
 | 
					        int ropeBottomY = margin + height / 12;
 | 
				
			||||||
 | 
					        g2.drawLine(ropeX, ropeTopY, ropeX, ropeBottomY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Géométrie du personnage
 | 
				
			||||||
 | 
					        int headR = Math.min(width, height) / 16;
 | 
				
			||||||
 | 
					        int headCX = ropeX;
 | 
				
			||||||
 | 
					        int headCY = ropeBottomY + headR;
 | 
				
			||||||
 | 
					        int bodyTopY = headCY + headR;
 | 
				
			||||||
 | 
					        int bodyBottomY = bodyTopY + height / 6;
 | 
				
			||||||
 | 
					        int armSpan = width / 10;
 | 
				
			||||||
 | 
					        int shouldersY = bodyTopY + height / 24;
 | 
				
			||||||
 | 
					        int legSpan = width / 12;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Étapes du personnage
 | 
				
			||||||
 | 
					        if (stage >= 1) { // tête
 | 
				
			||||||
 | 
					            g2.drawOval(headCX - headR, headCY - headR, headR * 2, headR * 2);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if (stage >= 2) { // corps
 | 
				
			||||||
 | 
					            g2.drawLine(headCX, bodyTopY, headCX, bodyBottomY);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (stage >= 3) { // bras gauche
 | 
				
			||||||
 | 
					            g2.drawLine(headCX, shouldersY, headCX - armSpan, shouldersY + height / 20);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (stage >= 4) { // bras droit
 | 
				
			||||||
 | 
					            g2.drawLine(headCX, shouldersY, headCX + armSpan, shouldersY + height / 20);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (stage >= 5) { // jambe gauche
 | 
				
			||||||
 | 
					            g2.drawLine(headCX, bodyBottomY, headCX - legSpan, bodyBottomY + height / 8);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (stage >= 6) { // jambe droite
 | 
				
			||||||
 | 
					            g2.drawLine(headCX, bodyBottomY, headCX + legSpan, bodyBottomY + height / 8);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g2.dispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public String toString() { return ""; }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										62
									
								
								src/Event.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/Event.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.awt.event.*;
 | 
				
			||||||
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * La classe <code>Event</code> regroupe et branche tous les listeners liés à Fenetre.
 | 
				
			||||||
 | 
					 * - Validation de la saisie (1 lettre A-Z, majuscule)
 | 
				
			||||||
 | 
					 * - Action sur Entrée ou clic bouton
 | 
				
			||||||
 | 
					 * - Notification du handler externe (fourni au constructeur)
 | 
				
			||||||
 | 
					 * Aucune logique de jeu ici.
 | 
				
			||||||
 | 
					 * @version 1.3
 | 
				
			||||||
 | 
					 * author Adrien
 | 
				
			||||||
 | 
					 * Date : 08-10-2025
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class Event implements ActionListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final Fenetre window;
 | 
				
			||||||
 | 
					    private final Consumer<Character> onLetterSubmitted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Constructeur : conserve les références et branche les événements. */
 | 
				
			||||||
 | 
					    public Event(Fenetre window, Consumer<Character> onLetterSubmitted) {
 | 
				
			||||||
 | 
					        this.window = window;
 | 
				
			||||||
 | 
					        this.onLetterSubmitted = onLetterSubmitted;
 | 
				
			||||||
 | 
					        wireEvents();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Branche les listeners sur les composants de Fenetre. */
 | 
				
			||||||
 | 
					    private void wireEvents() {
 | 
				
			||||||
 | 
					        JTextField letterInput = window.getLetterInput();
 | 
				
			||||||
 | 
					        JButton sendButton = window.getSendButton();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Même listener (this) pour Entrée et clic bouton
 | 
				
			||||||
 | 
					        sendButton.addActionListener(this);
 | 
				
			||||||
 | 
					        letterInput.addActionListener(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // UX : limiter à une seule lettre et forcer la majuscule (classe dédiée)
 | 
				
			||||||
 | 
					        letterInput.addKeyListener(new LetterInputFilter(letterInput));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Réagit à Entrée ou au clic bouton : récupère, valide et transmet la lettre. */
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void actionPerformed(ActionEvent actionEvent) {
 | 
				
			||||||
 | 
					        JTextField letterInput = window.getLetterInput();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String inputText = letterInput.getText().trim().toUpperCase();
 | 
				
			||||||
 | 
					        letterInput.setText(""); // reset du champ après tentative
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validation : exactement une lettre A–Z
 | 
				
			||||||
 | 
					        if (inputText.length() != 1 || !inputText.matches("[A-Z]")) {
 | 
				
			||||||
 | 
					            JOptionPane.showMessageDialog(window.getWindow(), "Veuillez entrer une seule lettre (A-Z).");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Notification du handler externe, sinon placeholder
 | 
				
			||||||
 | 
					        if (onLetterSubmitted != null) {
 | 
				
			||||||
 | 
					            onLetterSubmitted.accept(inputText.charAt(0));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            JOptionPane.showMessageDialog(window.getWindow(),
 | 
				
			||||||
 | 
					                    "Lettre soumise (placeholder) : " + inputText);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										101
									
								
								src/Fenetre.java
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								src/Fenetre.java
									
									
									
									
									
								
							@@ -1,23 +1,102 @@
 | 
				
			|||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.awt.*;
 | 
				
			||||||
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
* La classe <code>Fenetre</code>
 | 
					* La classe <code>Fenetre</code> gère uniquement l'interface graphique :
 | 
				
			||||||
 | 
					* - zone de dessin (assurée par la classe Dessin)
 | 
				
			||||||
 | 
					* - affichage du mot masqué
 | 
				
			||||||
 | 
					* - saisie d'une lettre (les événements sont gérés dans Event)
 | 
				
			||||||
*
 | 
					*
 | 
				
			||||||
* @version
 | 
					* Aucune logique de jeu ici.
 | 
				
			||||||
* @author
 | 
					* @version 1.5
 | 
				
			||||||
* Date :
 | 
					* @author Adrien
 | 
				
			||||||
 | 
					* Date : 08-10-2025
 | 
				
			||||||
* Licence :
 | 
					* Licence :
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class Fenetre {
 | 
					public class Fenetre {
 | 
				
			||||||
   //Attributs
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   //Constructeur
 | 
					    // --- Composants de l'interface ---
 | 
				
			||||||
 | 
					    private JFrame window;
 | 
				
			||||||
 | 
					    private JLabel wordLabel;
 | 
				
			||||||
 | 
					    private JTextField letterInput;
 | 
				
			||||||
 | 
					    private JButton sendButton;
 | 
				
			||||||
 | 
					    private JPanel drawZone;
 | 
				
			||||||
 | 
					    private Chronometre chronometre;
 | 
				
			||||||
 | 
					    private JLabel scoreLabel; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // --- Constructeur ---
 | 
				
			||||||
    public Fenetre() {
 | 
					    public Fenetre() {
 | 
				
			||||||
 | 
					        setupWindow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   }
 | 
					        JPanel root = new JPanel();
 | 
				
			||||||
   //Méthodes
 | 
					        root.setLayout(new BoxLayout(root, BoxLayout.Y_AXIS));
 | 
				
			||||||
 | 
					        window.setContentPane(root);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   //Affichage
 | 
					        // Barre supérieure : chrono + score
 | 
				
			||||||
   public String toString() {
 | 
					        JPanel topBar = new JPanel(new BorderLayout());
 | 
				
			||||||
      return "" ;
 | 
					        chronometre = new Chronometre();
 | 
				
			||||||
 | 
					        topBar.add(chronometre, BorderLayout.CENTER);
 | 
				
			||||||
 | 
					        scoreLabel = new JLabel("Score : " + Score.BASE, SwingConstants.RIGHT);
 | 
				
			||||||
 | 
					        scoreLabel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 12));
 | 
				
			||||||
 | 
					        scoreLabel.setFont(new Font("Segoe UI", Font.BOLD, 16));
 | 
				
			||||||
 | 
					        topBar.add(scoreLabel, BorderLayout.EAST);
 | 
				
			||||||
 | 
					        root.add(topBar);
 | 
				
			||||||
 | 
					        chronometre.start(); // démarrage automatique
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        drawZone = new Dessin();
 | 
				
			||||||
 | 
					        root.add(drawZone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wordLabel = createWordLabel();
 | 
				
			||||||
 | 
					        root.add(wordLabel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        JPanel inputPanel = createInputPanel();
 | 
				
			||||||
 | 
					        root.add(inputPanel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        window.setVisible(true);
 | 
				
			||||||
 | 
					        letterInput.requestFocusInWindow();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // --- Initialisation fenêtre ---
 | 
				
			||||||
 | 
					    private void setupWindow() {
 | 
				
			||||||
 | 
					        window = new JFrame("Jeu du Pendu");
 | 
				
			||||||
 | 
					        window.setSize(600, 600);
 | 
				
			||||||
 | 
					        window.setLocationRelativeTo(null);
 | 
				
			||||||
 | 
					        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // --- Sous-composants UI ---
 | 
				
			||||||
 | 
					    private JLabel createWordLabel() {
 | 
				
			||||||
 | 
					        JLabel label = new JLabel("_ _ _ _ _", SwingConstants.CENTER);
 | 
				
			||||||
 | 
					        label.setFont(new Font("Segoe UI", Font.BOLD, 32));
 | 
				
			||||||
 | 
					        label.setBorder(BorderFactory.createEmptyBorder(20, 10, 20, 10));
 | 
				
			||||||
 | 
					        label.setAlignmentX(Component.CENTER_ALIGNMENT);
 | 
				
			||||||
 | 
					        return label;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private JPanel createInputPanel() {
 | 
				
			||||||
 | 
					        JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
 | 
				
			||||||
 | 
					        JLabel prompt = new JLabel("Entrez une lettre :");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        letterInput = new JTextField(2);
 | 
				
			||||||
 | 
					        letterInput.setHorizontalAlignment(JTextField.CENTER);
 | 
				
			||||||
 | 
					        letterInput.setFont(new Font("Segoe UI", Font.BOLD, 24));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sendButton = new JButton("Envoyer");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        inputPanel.add(prompt);
 | 
				
			||||||
 | 
					        inputPanel.add(letterInput);
 | 
				
			||||||
 | 
					        inputPanel.add(sendButton);
 | 
				
			||||||
 | 
					        return inputPanel;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // --- Getters pour Event ---
 | 
				
			||||||
 | 
					    public JFrame getWindow() { return window; }
 | 
				
			||||||
 | 
					    public JTextField getLetterInput() { return letterInput; }
 | 
				
			||||||
 | 
					    public JButton getSendButton() { return sendButton; }
 | 
				
			||||||
 | 
					    public JLabel getWordLabel() { return wordLabel; }
 | 
				
			||||||
 | 
					    public JPanel getDrawZone() { return drawZone; }
 | 
				
			||||||
 | 
					    public Chronometre getChronometre() { return chronometre; }
 | 
				
			||||||
 | 
					    public JLabel getScoreLabel() { return scoreLabel; }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								src/LetterInputFilter.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/LetterInputFilter.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.awt.event.KeyAdapter;
 | 
				
			||||||
 | 
					import java.awt.event.KeyEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * La classe <code>LetterInputFilter</code> limite la saisie d'un champ texte
 | 
				
			||||||
 | 
					 * à une seule lettre de l'alphabet (A–Z), en forçant automatiquement
 | 
				
			||||||
 | 
					 * la majuscule. Toute autre frappe est ignorée.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @version 1.0
 | 
				
			||||||
 | 
					 * @author Adrien
 | 
				
			||||||
 | 
					 * Date : 08-10-2025
 | 
				
			||||||
 | 
					 * Licence :
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class LetterInputFilter extends KeyAdapter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Référence vers le champ de saisie à filtrer. */
 | 
				
			||||||
 | 
					    private final JTextField letterInput;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //Constructeur.
 | 
				
			||||||
 | 
					    public LetterInputFilter(JTextField letterInput) {
 | 
				
			||||||
 | 
					        if (letterInput == null) {
 | 
				
			||||||
 | 
					            throw new NullPointerException("letterInput ne doit pas être null");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.letterInput = letterInput;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Intercepte les frappes clavier et applique les règles suivantes :
 | 
				
			||||||
 | 
					     * - n'accepte que les lettres (A–Z) 
 | 
				
			||||||
 | 
					     * - limite la saisie à un seul caractère 
 | 
				
			||||||
 | 
					     * - force la majuscule sur le caractère saisi.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void keyTyped(KeyEvent keyEvent) {
 | 
				
			||||||
 | 
					        char typedChar = keyEvent.getKeyChar();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Refuse tout caractère non alphabétique ou une saisie > 1 caractère.
 | 
				
			||||||
 | 
					        if (!Character.isLetter(typedChar) || letterInput.getText().length() >= 1) {
 | 
				
			||||||
 | 
					            keyEvent.consume(); // ignore la frappe
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Force la majuscule.
 | 
				
			||||||
 | 
					        keyEvent.setKeyChar(Character.toUpperCase(typedChar));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										75
									
								
								src/MenuDifficulte.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/MenuDifficulte.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.awt.*;
 | 
				
			||||||
 | 
					import java.awt.event.ActionEvent;
 | 
				
			||||||
 | 
					import java.awt.event.ActionListener;
 | 
				
			||||||
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Fenêtre de sélection de la difficulté (Facile / Moyen / Difficile).
 | 
				
			||||||
 | 
					 * Notifie le choix via un Consumer<String> fourni au constructeur.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @version 1.0
 | 
				
			||||||
 | 
					 * @author Adrien
 | 
				
			||||||
 | 
					 * Date : 08-10-2025
 | 
				
			||||||
 | 
					 * Licence :
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class MenuDifficulte implements ActionListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final JFrame frame;
 | 
				
			||||||
 | 
					    private final Consumer<String> onDifficultyChosen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Construit la fenêtre et prépare les boutons. */
 | 
				
			||||||
 | 
					    public MenuDifficulte(Consumer<String> onDifficultyChosen) {
 | 
				
			||||||
 | 
					        this.onDifficultyChosen = onDifficultyChosen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        frame = new JFrame("Jeu du Pendu — Choix de difficulté");
 | 
				
			||||||
 | 
					        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 | 
				
			||||||
 | 
					        frame.setSize(400, 250);
 | 
				
			||||||
 | 
					        frame.setLocationRelativeTo(null);
 | 
				
			||||||
 | 
					        frame.setLayout(new BorderLayout(0, 10));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        JLabel title = new JLabel("Choisissez une difficulté", SwingConstants.CENTER);
 | 
				
			||||||
 | 
					        title.setFont(new Font("Segoe UI", Font.BOLD, 18));
 | 
				
			||||||
 | 
					        title.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 10));
 | 
				
			||||||
 | 
					        frame.add(title, BorderLayout.NORTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        JPanel buttonsPanel = new JPanel(new GridLayout(1, 3, 10, 10));
 | 
				
			||||||
 | 
					        buttonsPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        JButton easyBtn = new JButton("Facile");
 | 
				
			||||||
 | 
					        JButton mediumBtn = new JButton("Moyen");
 | 
				
			||||||
 | 
					        JButton hardBtn = new JButton("Difficile");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        easyBtn.setActionCommand("Facile");
 | 
				
			||||||
 | 
					        mediumBtn.setActionCommand("Moyen");
 | 
				
			||||||
 | 
					        hardBtn.setActionCommand("Difficile");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        easyBtn.addActionListener(this);
 | 
				
			||||||
 | 
					        mediumBtn.addActionListener(this);
 | 
				
			||||||
 | 
					        hardBtn.addActionListener(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buttonsPanel.add(easyBtn);
 | 
				
			||||||
 | 
					        buttonsPanel.add(mediumBtn);
 | 
				
			||||||
 | 
					        buttonsPanel.add(hardBtn);
 | 
				
			||||||
 | 
					        frame.add(buttonsPanel, BorderLayout.CENTER);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Affiche la fenêtre. */
 | 
				
			||||||
 | 
					    public void show() { frame.setVisible(true); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Ferme la fenêtre. */
 | 
				
			||||||
 | 
					    public void close() { frame.dispose(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Accès optionnel au JFrame. */
 | 
				
			||||||
 | 
					    public JFrame getFrame() { return frame; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Réception des clics sur les boutons. */
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void actionPerformed(ActionEvent actionEvent) {
 | 
				
			||||||
 | 
					        String difficulty = actionEvent.getActionCommand(); // "Facile" | "Moyen" | "Difficile"
 | 
				
			||||||
 | 
					        frame.dispose();
 | 
				
			||||||
 | 
					        if (onDifficultyChosen != null) {
 | 
				
			||||||
 | 
					            onDifficultyChosen.accept(difficulty);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										58
									
								
								src/Mots.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/Mots.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* La classe <code>Mots</code>
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* @version 1.0
 | 
				
			||||||
 | 
					* @author Aurélien
 | 
				
			||||||
 | 
					* Date : 08-10-25
 | 
				
			||||||
 | 
					* Licence :
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					public final class Mots {
 | 
				
			||||||
 | 
					   //Attributs
 | 
				
			||||||
 | 
					   public static final short dictionarysize = 32 ;
 | 
				
			||||||
 | 
					   public static final String[] dictionary = {
 | 
				
			||||||
 | 
					      "Magnifique",
 | 
				
			||||||
 | 
					      "Etoile",
 | 
				
			||||||
 | 
					      "Voyage",
 | 
				
			||||||
 | 
					      "Biscuit",
 | 
				
			||||||
 | 
					      "Refrigerateur",
 | 
				
			||||||
 | 
					      "Courage",
 | 
				
			||||||
 | 
					      "Avion",
 | 
				
			||||||
 | 
					      "Explorateur",
 | 
				
			||||||
 | 
					      "Montagne",
 | 
				
			||||||
 | 
					      "Philosophie",
 | 
				
			||||||
 | 
					      "Lumiere",
 | 
				
			||||||
 | 
					      "Ethernet",
 | 
				
			||||||
 | 
					      "Architecture",
 | 
				
			||||||
 | 
					      "Ocean",
 | 
				
			||||||
 | 
					      "Liberte",
 | 
				
			||||||
 | 
					      "Aventure",
 | 
				
			||||||
 | 
					      "Cerise",
 | 
				
			||||||
 | 
					      "Harmonieux",
 | 
				
			||||||
 | 
					      "Informatique",
 | 
				
			||||||
 | 
					      "Pluie",
 | 
				
			||||||
 | 
					      "Equilibriste",
 | 
				
			||||||
 | 
					      "Papillon",
 | 
				
			||||||
 | 
					      "Saisons",
 | 
				
			||||||
 | 
					      "Liberte",
 | 
				
			||||||
 | 
					      "Alphabet",
 | 
				
			||||||
 | 
					      "Musique",
 | 
				
			||||||
 | 
					      "Translucent",
 | 
				
			||||||
 | 
					      "Passion",
 | 
				
			||||||
 | 
					      "Etreindre",
 | 
				
			||||||
 | 
					      "Poetique",
 | 
				
			||||||
 | 
					      "Serenite",
 | 
				
			||||||
 | 
					      "Révolution"
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   //Constructeur
 | 
				
			||||||
 | 
					   private Mots() {  //N'a pas pour but d'être instanciée
 | 
				
			||||||
 | 
					      throw new UnsupportedOperationException("The \"Fichier\" class cannot be instanced !");
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   //Méthodes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   //Affichage
 | 
				
			||||||
 | 
					   public String toString() {
 | 
				
			||||||
 | 
					      return "" ;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										121
									
								
								src/Partie.java
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								src/Partie.java
									
									
									
									
									
								
							@@ -1,23 +1,136 @@
 | 
				
			|||||||
 | 
					import java.util.Random;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
* La classe <code>Partie</code>
 | 
					* La classe <code>Partie</code>
 | 
				
			||||||
*
 | 
					*
 | 
				
			||||||
* @version
 | 
					* @version 0.2
 | 
				
			||||||
* @author
 | 
					* @author Aurélien
 | 
				
			||||||
* Date :
 | 
					* Date : 08-10-25
 | 
				
			||||||
* Licence :
 | 
					* Licence :
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
public class Partie {
 | 
					public class Partie {
 | 
				
			||||||
 | 
					   //Contantes
 | 
				
			||||||
 | 
					   private static final byte REMAININGTRY = 6 ;
 | 
				
			||||||
 | 
					   private static final byte CARACTERCODESHIFT = 65 ;  //Décalage ASCI > 'A'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   //Attributs
 | 
					   //Attributs
 | 
				
			||||||
 | 
					   private char[] secretword ;
 | 
				
			||||||
 | 
					   private byte wordsize ;
 | 
				
			||||||
 | 
					   private boolean[] foundletters ;
 | 
				
			||||||
 | 
					   private boolean[] entriesletters = new boolean[26] ;  //Pseudo Alphabée
 | 
				
			||||||
 | 
					   private byte remainingtry = REMAININGTRY ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   //Constructeur
 | 
					   //Constructeur
 | 
				
			||||||
   public Partie() {
 | 
					   public Partie() {
 | 
				
			||||||
 | 
					      this.secretword = generateSecretWord() ;
 | 
				
			||||||
 | 
					      this.wordsize = (byte) secretword.length ;
 | 
				
			||||||
 | 
					      this.foundletters = new boolean[wordsize] ;
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
   //Méthodes
 | 
					   //Méthodes
 | 
				
			||||||
 | 
					   public char[] getSecretWord() {
 | 
				
			||||||
 | 
					      return this.secretword ;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   public boolean[] getFoundLetters() {
 | 
				
			||||||
 | 
					      return this.foundletters ;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   public byte getRemainingTry() {
 | 
				
			||||||
 | 
					      return this.remainingtry ;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   /**
 | 
				
			||||||
 | 
					    * Vérifie l'état de la partie en cours.
 | 
				
			||||||
 | 
					    * 
 | 
				
			||||||
 | 
					    * @return true si le jeu est fini.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					   public boolean gameIsEnding() {
 | 
				
			||||||
 | 
					      if(this.remainingtry <= 0){
 | 
				
			||||||
 | 
					         return true ;
 | 
				
			||||||
 | 
					      }else if(wordIsFound()){
 | 
				
			||||||
 | 
					         return true ;
 | 
				
			||||||
 | 
					      }else{
 | 
				
			||||||
 | 
					         return false ;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   /**
 | 
				
			||||||
 | 
					    * Vérifie si la lettre reçu n'a pas déjà été joué puis, met à jour le tableau "entriesletters" et
 | 
				
			||||||
 | 
					    * "foundletters" le cas échéant.
 | 
				
			||||||
 | 
					    * 
 | 
				
			||||||
 | 
					    * @return true si la lettre était déjà présente.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					   public boolean isAlreadyEntries(char letter) {
 | 
				
			||||||
 | 
					      short caractercode = (short) letter ;  //Récupération du code du caractère
 | 
				
			||||||
 | 
					      if(this.entriesletters[caractercode-CARACTERCODESHIFT]){
 | 
				
			||||||
 | 
					         this.remainingtry-- ;  //Décrément des essais
 | 
				
			||||||
 | 
					         return true ;
 | 
				
			||||||
 | 
					      }else{
 | 
				
			||||||
 | 
					         boolean isfind = false ;
 | 
				
			||||||
 | 
					         for(byte i = 0 ; i < this.wordsize ; i++){  //Parcours du "secretword"
 | 
				
			||||||
 | 
					            if(this.secretword[i] == letter){
 | 
				
			||||||
 | 
					               this.foundletters[i] = true ;
 | 
				
			||||||
 | 
					               isfind = true ;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         if(isfind == false){
 | 
				
			||||||
 | 
					            this.remainingtry-- ;  //Décrément des essais
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         this.entriesletters[caractercode-CARACTERCODESHIFT] = true ;  //Ajout au tableau des lettres jouées
 | 
				
			||||||
 | 
					         return false ;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   /**
 | 
				
			||||||
 | 
					    * Génère un mot à partir d'un grand dictionnaire (enfin en principe).
 | 
				
			||||||
 | 
					    * 
 | 
				
			||||||
 | 
					    * @return le mot généré.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					   private char[] generateSecretWord() {
 | 
				
			||||||
 | 
					      Random random = new Random();
 | 
				
			||||||
 | 
					      byte grain = (byte) random.nextInt(Mots.dictionarysize);
 | 
				
			||||||
 | 
					      char[] word = Mots.dictionary[grain].toUpperCase().toCharArray();
 | 
				
			||||||
 | 
					      return word ;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   private boolean wordIsFound() {
 | 
				
			||||||
 | 
					      for(byte i = 0 ; i < this.wordsize ; i++){  //Parcours du "secretword"
 | 
				
			||||||
 | 
					         if(!this.foundletters[i]){  //Si une lettre n'est pas trouvé
 | 
				
			||||||
 | 
					            return false ;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return true ;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   //Affichage
 | 
					   //Affichage
 | 
				
			||||||
   public String toString() {
 | 
					   public String toString() {
 | 
				
			||||||
      return "" ;
 | 
					      return "" ;
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   //Tests
 | 
				
			||||||
 | 
					   public static void main(String[] args){
 | 
				
			||||||
 | 
					      char[] test = {'E','O','M','I','E','D','A','Z','N','L','C','R','P','H','T','S'};
 | 
				
			||||||
 | 
					      byte size = (byte) test.length ;
 | 
				
			||||||
 | 
					      boolean status ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Partie game = new Partie();
 | 
				
			||||||
 | 
					      System.out.println("Trick > " + String.valueOf(game.secretword) + "\n");
 | 
				
			||||||
 | 
					      for(byte i = 0 ; i < size && !game.gameIsEnding() ; i++){
 | 
				
			||||||
 | 
					         System.out.println("Essais restants : " + game.getRemainingTry());
 | 
				
			||||||
 | 
					         status = game.isAlreadyEntries(test[i]);
 | 
				
			||||||
 | 
					         for(byte l = 0 ; l < game.wordsize ; l++){  //Parcours du "secretword"
 | 
				
			||||||
 | 
					            if(game.foundletters[l] == true){
 | 
				
			||||||
 | 
					               System.out.print(game.getSecretWord()[l] + " ");
 | 
				
			||||||
 | 
					            }else{
 | 
				
			||||||
 | 
					               System.out.print("_ ");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         System.out.println("");  //Lisibilité
 | 
				
			||||||
 | 
					         //System.out.println("Lettres : " + game.entriesletters);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      System.out.println("Essais restants : " + game.getRemainingTry());
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										131
									
								
								src/Pendu.java
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								src/Pendu.java
									
									
									
									
									
								
							@@ -1,14 +1,135 @@
 | 
				
			|||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
* La classe <code>Pendu</code>
 | 
					 * Point d'entrée : affiche le menu de difficulté puis lance la fenêtre du jeu.
 | 
				
			||||||
 | 
					 * Lie Fenetre (vue) et Partie (logique) via un handler.
 | 
				
			||||||
 | 
					 * Met à jour le dessin du pendu à chaque erreur.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
* @version
 | 
					 * @version 1.4
 | 
				
			||||||
* @author
 | 
					 * author Adrien
 | 
				
			||||||
* Date :
 | 
					 * Date : 08-10-2025
 | 
				
			||||||
 * Licence :
 | 
					 * Licence :
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class Pendu {
 | 
					public class Pendu {
 | 
				
			||||||
   public static void main(String[] args){
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void main(String[] args) {
 | 
				
			||||||
 | 
					        SwingUtilities.invokeLater(() -> {
 | 
				
			||||||
 | 
					            MenuDifficulte menu = new MenuDifficulte(difficulty -> openGameWindow(difficulty));
 | 
				
			||||||
 | 
					            menu.show();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Ouvre la fenêtre du jeu, crée la Partie et branche les événements. */
 | 
				
			||||||
 | 
					    private static void openGameWindow(String difficulty) {
 | 
				
			||||||
 | 
					        Fenetre fenetre = new Fenetre();
 | 
				
			||||||
 | 
					        fenetre.getWindow().setTitle("Jeu du Pendu — " + difficulty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Partie partie = new Partie();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Affichage initial du mot masqué (construit ici)
 | 
				
			||||||
 | 
					        fenetre.getWordLabel().setText(buildMaskedWord(partie));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Stage initial (0 erreur)
 | 
				
			||||||
 | 
					        if (fenetre.getDrawZone() instanceof Dessin) {
 | 
				
			||||||
 | 
					            ((Dessin) fenetre.getDrawZone()).setStage(0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // On mémorise les essais initiaux pour calculer les erreurs = initialTries - remainingTry
 | 
				
			||||||
 | 
					        final int initialTries = partie.getRemainingTry();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Handler : applique Partie puis met à jour l'UI (mot + dessin + score)
 | 
				
			||||||
 | 
					        Consumer<Character> handler = new GameLetterHandler(fenetre, partie, initialTries);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Branchement des événements clavier/bouton
 | 
				
			||||||
 | 
					        new Event(fenetre, handler);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Construit la chaîne "_ _ A _ _" à partir de l'état de Partie (sans modifier Partie). */
 | 
				
			||||||
 | 
					    private static String buildMaskedWord(Partie partie) {
 | 
				
			||||||
 | 
					        char[] word = partie.getSecretWord();
 | 
				
			||||||
 | 
					        boolean[] found = partie.getFoundLetters();
 | 
				
			||||||
 | 
					        StringBuilder sb = new StringBuilder();
 | 
				
			||||||
 | 
					        for (int i = 0; i < word.length; i++) {
 | 
				
			||||||
 | 
					            sb.append(found[i] ? word[i] : '_');
 | 
				
			||||||
 | 
					            if (i < word.length - 1) sb.append(' ');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return sb.toString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handler de lettres :
 | 
				
			||||||
 | 
					     * - applique Partie.isAlreadyEntries
 | 
				
			||||||
 | 
					     * - met à jour le mot affiché
 | 
				
			||||||
 | 
					     * - calcule errors = initialTries - remainingTry, puis stage = min(errors, Dessin.MAX_STAGE)
 | 
				
			||||||
 | 
					     * - met à jour le score
 | 
				
			||||||
 | 
					     * - gère la fin de partie
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static class GameLetterHandler implements Consumer<Character> {
 | 
				
			||||||
 | 
					        private final Fenetre fenetre;
 | 
				
			||||||
 | 
					        private final Partie partie;
 | 
				
			||||||
 | 
					        private final int initialTries;   // essais au démarrage (peut être 11 avec ta Partie)
 | 
				
			||||||
 | 
					        private final Dessin dessinPanel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        GameLetterHandler(Fenetre fenetre, Partie partie, int initialTries) {
 | 
				
			||||||
 | 
					            this.fenetre = fenetre;
 | 
				
			||||||
 | 
					            this.partie = partie;
 | 
				
			||||||
 | 
					            this.initialTries = initialTries;
 | 
				
			||||||
 | 
					            this.dessinPanel = (fenetre.getDrawZone() instanceof Dessin)
 | 
				
			||||||
 | 
					                    ? (Dessin) fenetre.getDrawZone() : null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public void accept(Character ch) {
 | 
				
			||||||
 | 
					            boolean alreadyPlayed = partie.isAlreadyEntries(ch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Mise à jour du mot
 | 
				
			||||||
 | 
					            fenetre.getWordLabel().setText(buildMaskedWord(partie));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Erreurs -> stage pour le dessin (borné à MAX_STAGE)
 | 
				
			||||||
 | 
					            int errors = Math.max(0, initialTries - partie.getRemainingTry());
 | 
				
			||||||
 | 
					            if (dessinPanel != null) {
 | 
				
			||||||
 | 
					                int stage = Math.min(errors, Dessin.MAX_STAGE);
 | 
				
			||||||
 | 
					                dessinPanel.setStage(stage);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Mise à jour du score courant (si tu utilises Score + Chronometre)
 | 
				
			||||||
 | 
					            long elapsed = (fenetre.getChronometre() != null)
 | 
				
			||||||
 | 
					                    ? fenetre.getChronometre().getElapsedMillis() : 0L;
 | 
				
			||||||
 | 
					            if (fenetre.getScoreLabel() != null) {
 | 
				
			||||||
 | 
					                int score = Score.compute(errors, elapsed);
 | 
				
			||||||
 | 
					                fenetre.getScoreLabel().setText("Score : " + score);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (alreadyPlayed) {
 | 
				
			||||||
 | 
					                JOptionPane.showMessageDialog(fenetre.getWindow(),
 | 
				
			||||||
 | 
					                        "Lettre déjà jouée : " + ch + "\nEssais restants : " + partie.getRemainingTry());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Fin de partie
 | 
				
			||||||
 | 
					            if (partie.gameIsEnding()) {
 | 
				
			||||||
 | 
					                // Stoppe le chronomètre pour figer le temps
 | 
				
			||||||
 | 
					                if (fenetre.getChronometre() != null) {
 | 
				
			||||||
 | 
					                    fenetre.getChronometre().stop();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // Score final (si Score/Chronometre présents)
 | 
				
			||||||
 | 
					                long finalElapsed = (fenetre.getChronometre() != null)
 | 
				
			||||||
 | 
					                        ? fenetre.getChronometre().getElapsedMillis() : elapsed;
 | 
				
			||||||
 | 
					                int finalErrors = Math.max(0, initialTries - partie.getRemainingTry());
 | 
				
			||||||
 | 
					                int finalScore = Score.compute(finalErrors, finalElapsed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                boolean win = !fenetre.getWordLabel().getText().contains("_");
 | 
				
			||||||
 | 
					                String msg = (win
 | 
				
			||||||
 | 
					                        ? "Bravo ! Mot trouvé : "
 | 
				
			||||||
 | 
					                        : "Perdu ! Le mot était : ")
 | 
				
			||||||
 | 
					                        + String.valueOf(partie.getSecretWord())
 | 
				
			||||||
 | 
					                        + (fenetre.getScoreLabel() != null ? "\nScore : " + finalScore : "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                JOptionPane.showMessageDialog(fenetre.getWindow(), msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                fenetre.getLetterInput().setEnabled(false);
 | 
				
			||||||
 | 
					                fenetre.getSendButton().setEnabled(false);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										36
									
								
								src/Score.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/Score.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Calcule le score du pendu à partir du nombre d'erreurs et du temps écoulé.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Formule (simple et configurable) :
 | 
				
			||||||
 | 
					 * score = max(0, BASE - erreurs * ERROR_PENALTY - secondes * TIME_PENALTY_PER_SEC)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @version 1.0
 | 
				
			||||||
 | 
					 * @author Adrien
 | 
				
			||||||
 | 
					 * Date : 08-10-2025
 | 
				
			||||||
 | 
					 * Licence :
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public final class Score {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Score de départ. */
 | 
				
			||||||
 | 
					    public static final int BASE = 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Malus par erreur. (6 erreurs max par défaut) */
 | 
				
			||||||
 | 
					    public static final int ERROR_PENALTY = 120;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Malus par seconde écoulée. */
 | 
				
			||||||
 | 
					    public static final double TIME_PENALTY_PER_SEC = 1.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private Score() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * - nombre d'erreurs (>=0)
 | 
				
			||||||
 | 
					     * - temps écoulé en millisecondes
 | 
				
			||||||
 | 
					     * - score >= 0
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static int compute(int errors, long elapsedMillis) {
 | 
				
			||||||
 | 
					        if (errors < 0) errors = 0;
 | 
				
			||||||
 | 
					        double timePenalty = (elapsedMillis / 1000.0) * TIME_PENALTY_PER_SEC;
 | 
				
			||||||
 | 
					        int value = (int)Math.round(BASE - errors * ERROR_PENALTY - timePenalty);
 | 
				
			||||||
 | 
					        return Math.max(0, value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user