import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; /** * Interface graphique du jeu du Pendu. * Noms de variables/fonctions en anglais (exigence), * affichages et commentaires en français. */ public class HangmanGUI extends JFrame { // --- Données du jeu --- private final String[] words = { "ordinateur","voiture","maison","soleil","lumiere", "fromage","chocolat","montagne","riviere","plage", "oiseau","papillon","musique","chateau","livre", "telephone","aventure","mystere","foret","fleur", "chapeau","nuage","horloge","chaise","fenetre", "paysage","bouteille","parapluie","clavier","souris", "brouillard","village","histoire","cerise","pomme", "banane","poisson","arbre","cascade","cheval" }; private String secretWord; private final Set found = new HashSet<>(); private final Set tried = new HashSet<>(); private int errors = 0; private static final int MAX_ERRORS = 8; // 8 étapes : base, poteau, poutre, corde, tête, corps, bras, jambes private boolean gameOver = false; // indique si la partie est terminée // --- Éléments UI --- private final JLabel wordLbl = new JLabel("", SwingConstants.CENTER); private final JLabel triedLbl = new JLabel("", SwingConstants.CENTER); private final JLabel infoLbl = new JLabel("Entrez une lettre (a-z)", SwingConstants.CENTER); private final JTextField input = new JTextField(); private final JButton guessBtn = new JButton("Proposer"); private final HangPanel hangPanel = new HangPanel(); /** Panneau de dessin du pendu, progressif selon le nombre d'erreurs. */ private static class HangPanel extends JPanel { private int errors = 0; public void setErrors(int e) { this.errors = Math.max(0, Math.min(e, MAX_ERRORS)); repaint(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D gg = (Graphics2D) g; gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int w = getWidth(), h = getHeight(); int baseY = h - 40; // niveau du sol // 1) base if (errors >= 1) gg.drawLine(50, baseY, w - 50, baseY); // 2) poteau vertical if (errors >= 2) gg.drawLine(100, baseY, 100, 60); // 3) poutre horizontale if (errors >= 3) gg.drawLine(100, 60, 220, 60); // 4) corde if (errors >= 4) gg.drawLine(220, 60, 220, 90); // 5) tête if (errors >= 5) gg.drawOval(200, 90, 40, 40); // 6) corps if (errors >= 6) gg.drawLine(220, 130, 220, 200); // 7) bras if (errors >= 7) { gg.drawLine(220, 145, 190, 165); // bras gauche gg.drawLine(220, 145, 250, 165); // bras droit } // 8) jambes if (errors >= 8) { gg.drawLine(220, 200, 200, 240); // jambe gauche gg.drawLine(220, 200, 240, 240); // jambe droite } } } /** Point d'entrée : crée et affiche la fenêtre du jeu. */ public static void main(String[] args) { SwingUtilities.invokeLater(() -> { HangmanGUI app = new HangmanGUI(); app.setVisible(true); }); } /** Constructeur : configure la fenêtre, l'UI et lance la partie. */ public HangmanGUI() { super("Jeu du Pendu"); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setSize(520, 520); setLocationRelativeTo(null); setupUI(); startGame(); } /** Prépare la mise en page et les actions de l'interface. */ private void setupUI() { wordLbl.setFont(new Font(Font.MONOSPACED, Font.BOLD, 28)); triedLbl.setFont(new Font("SansSerif", Font.PLAIN, 14)); infoLbl.setFont(new Font("SansSerif", Font.PLAIN, 14)); JPanel top = new JPanel(new GridLayout(3, 1, 8, 8)); top.add(wordLbl); top.add(triedLbl); top.add(infoLbl); JPanel controls = new JPanel(new BorderLayout(8, 8)); controls.add(input, BorderLayout.CENTER); controls.add(guessBtn, BorderLayout.EAST); hangPanel.setPreferredSize(new Dimension(480, 300)); JPanel center = new JPanel(new BorderLayout()); center.add(hangPanel, BorderLayout.CENTER); JPanel main = new JPanel(new BorderLayout(10, 10)); main.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); main.add(top, BorderLayout.NORTH); main.add(center, BorderLayout.CENTER); main.add(controls, BorderLayout.SOUTH); setContentPane(main); // Actions guessBtn.addActionListener(e -> onGuess()); input.addActionListener(e -> onGuess()); // touche Entrée addWindowListener(new WindowAdapter() { @Override public void windowOpened(WindowEvent e) { input.requestFocusInWindow(); } }); } /** Démarre une partie (unique). */ private void startGame() { secretWord = pickWord(); found.clear(); tried.clear(); errors = 0; gameOver = false; input.setText(""); input.setEditable(true); guessBtn.setEnabled(true); infoLbl.setText("Entrez une lettre (a-z)"); updateUIState(); } /** Traite une proposition : valide, met à jour et vérifie fin de partie. */ private void onGuess() { if (gameOver) return; // bloque toute saisie après fin String s = input.getText().trim().toLowerCase(Locale.ROOT); if (s.length() != 1 || s.charAt(0) < 'a' || s.charAt(0) > 'z') { infoLbl.setText("Veuillez entrer une seule lettre (a-z)."); input.selectAll(); input.requestFocusInWindow(); return; } char c = s.charAt(0); if (tried.contains(c)) { infoLbl.setText("Lettre déjà essayée : " + c); input.selectAll(); input.requestFocusInWindow(); return; } tried.add(c); boolean hit = false; for (int i = 0; i < secretWord.length(); i++) { if (Character.toLowerCase(secretWord.charAt(i)) == c) { found.add(c); hit = true; } } if (!hit) { errors++; infoLbl.setText("Mauvaise lettre : " + c); } else { infoLbl.setText("Bonne lettre : " + c); } updateUIState(); input.selectAll(); input.requestFocusInWindow(); } /** Met à jour les libellés, le dessin, et gère la fin de partie. */ private void updateUIState() { wordLbl.setText(maskWord(secretWord, found)); triedLbl.setText("Lettres essayées : " + joinChars(tried)); hangPanel.setErrors(errors); if (isWin(secretWord, found)) { infoLbl.setText("Bravo ! Vous avez trouvé le mot : " + secretWord); wordLbl.setText(spaced(secretWord)); // affichage propre du mot gameOver = true; disableInput(); } else if (errors >= MAX_ERRORS) { infoLbl.setText("Perdu ! Le mot était : " + secretWord); wordLbl.setText(spaced(secretWord)); gameOver = true; disableInput(); } // force le rafraîchissement de l'interface revalidate(); repaint(); } /** Désactive les contrôles après la fin du jeu. */ private void disableInput() { input.setEditable(false); guessBtn.setEnabled(false); } /** Sélectionne un mot aléatoire. */ private String pickWord() { Random rnd = new Random(); return words[rnd.nextInt(words.length)].toLowerCase(Locale.ROOT); } /** Construit le mot masqué selon les lettres trouvées. */ private String maskWord(String secret, Set foundSet) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < secret.length(); i++) { char ch = secret.charAt(i); char lc = Character.toLowerCase(ch); if (Character.isLetter(lc) && !foundSet.contains(lc)) sb.append('_'); else sb.append(ch); if (i < secret.length() - 1) sb.append(' '); } return sb.toString(); } /** Vrai si toutes les lettres du mot ont été trouvées. */ private boolean isWin(String secret, Set foundSet) { for (int i = 0; i < secret.length(); i++) { char lc = Character.toLowerCase(secret.charAt(i)); if (Character.isLetter(lc) && !foundSet.contains(lc)) return false; } return true; } /** Trie et joint les lettres pour affichage. */ private String joinChars(Set set) { java.util.List list = new ArrayList<>(set); Collections.sort(list); StringBuilder sb = new StringBuilder(); for (int i = 0; i < list.size(); i++) { sb.append(list.get(i)); if (i < list.size() - 1) sb.append(' '); } return sb.toString(); } /** Ajoute des espaces entre les lettres pour une lecture plus claire. */ private String spaced(String s) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < s.length(); i++) { sb.append(s.charAt(i)); if (i < s.length() - 1) sb.append(' '); } return sb.toString(); } }