import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; /** * Hangman game GUI. * Variables/methods and comments in English. * User-facing texts remain in French. */ public class HangmanGUI extends JFrame { 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 steps: base, post, beam, rope, head, body, arms, legs private boolean gameOver = false; // indicates if the game is finished 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(); /** Drawing panel for the hangman, progressive according to error count. */ 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; // ground level if (errors >= 1) gg.drawLine(50, baseY, w - 50, baseY); if (errors >= 2) gg.drawLine(100, baseY, 100, 60); if (errors >= 3) gg.drawLine(100, 60, 220, 60); if (errors >= 4) gg.drawLine(220, 60, 220, 90); if (errors >= 5) gg.drawOval(200, 90, 40, 40); if (errors >= 6) gg.drawLine(220, 130, 220, 200); if (errors >= 7) { gg.drawLine(220, 145, 190, 165); gg.drawLine(220, 145, 250, 165); } if (errors >= 8) { gg.drawLine(220, 200, 200, 240); gg.drawLine(220, 200, 240, 240); } } } /** Entry point: create and show the game window. */ public static void main(String[] args) { SwingUtilities.invokeLater(() -> { HangmanGUI app = new HangmanGUI(); app.setVisible(true); }); } /** Constructor: window setup, UI setup, and start the game. */ public HangmanGUI() { super("Jeu du Pendu"); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setSize(520, 520); setLocationRelativeTo(null); setupUI(); startGame(); } /** Prepare the layout and interactions. */ 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); guessBtn.addActionListener(e -> onGuess()); input.addActionListener(e -> onGuess()); addWindowListener(new WindowAdapter() { @Override public void windowOpened(WindowEvent e) { input.requestFocusInWindow(); } }); } /** Start a game. */ 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(); } /** Handle a guess: validate input, update state, check for end of game. */ private void onGuess() { if (gameOver) return; // block input after game end 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(); } /** Refresh labels/drawing and handle end-of-game. */ 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)); // pretty display of the word gameOver = true; disableInput(); } else if (errors >= MAX_ERRORS) { infoLbl.setText("Perdu ! Le mot était : " + secretWord); wordLbl.setText(spaced(secretWord)); gameOver = true; disableInput(); } // force UI refresh revalidate(); repaint(); } /** Disable controls after the game ends. */ private void disableInput() { input.setEditable(false); guessBtn.setEnabled(false); } /** Pick a random word. */ private String pickWord() { Random rnd = new Random(); return words[rnd.nextInt(words.length)].toLowerCase(Locale.ROOT); } /** Build the masked word based on found letters. */ 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(); } /** True if all letters have been found. */ 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; } /** Sort and join letters for display. */ 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(); } /** Add spaces between letters for nicer reading. */ 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(); } }