diff --git a/src/HangmanGUI.java b/src/HangmanGUI.java new file mode 100644 index 0000000..cf452d2 --- /dev/null +++ b/src/HangmanGUI.java @@ -0,0 +1,306 @@ +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import java.util.Timer; +import java.util.TimerTask; + +/** + * Hangman GUI with difficulty selection, dynamic score, and timer. + * Uses WordManager for words. + * User-facing texts remain in French. + */ +public class HangmanGUI extends JFrame { + private WordManager manager; + + 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; + private boolean gameOver = false; + + // scoring and timing + private int baseScore = 200; + private int mistakePenalty = 15; + private double timePenaltyPerSecond = 1.0; + private long startTime; + + // UI components + 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 JLabel scoreLbl = new JLabel("Score: 0", SwingConstants.CENTER); + private final JLabel timerLbl = new JLabel("Temps: 0s", SwingConstants.CENTER); + private final JTextField input = new JTextField(); + private final JButton guessBtn = new JButton("Proposer"); + private final HangPanel hangPanel = new HangPanel(); + + private final String[] difficulties = {"Facile", "Moyen", "Difficile"}; + private final JComboBox difficultyCombo = new JComboBox<>(difficulties); + + private Timer timer; + + /** Drawing panel for hangman */ + 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; + + 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 */ + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> { + try { + HangmanGUI app = new HangmanGUI(); + app.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } + + /** Constructor */ + public HangmanGUI() throws Exception { + super("Jeu du Pendu"); + manager = new WordManager(); + setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + setSize(560, 620); + setLocationRelativeTo(null); + setupUI(); + startGame(); + } + + /** Setup UI */ + 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)); + scoreLbl.setFont(new Font("SansSerif", Font.BOLD, 16)); + timerLbl.setFont(new Font("SansSerif", Font.BOLD, 16)); + + JPanel top = new JPanel(new GridLayout(6, 1, 8, 8)); + top.add(wordLbl); + top.add(triedLbl); + top.add(infoLbl); + + JPanel scorePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 5)); + scorePanel.add(scoreLbl); + scorePanel.add(timerLbl); + top.add(scorePanel); + + JPanel diffPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + diffPanel.add(new JLabel("Difficulté:")); + diffPanel.add(difficultyCombo); + top.add(diffPanel); + + JButton restartBtn = new JButton("Rejouer"); + restartBtn.addActionListener(e -> startGame()); + JPanel restartPanel = new JPanel(); + restartPanel.add(restartBtn); + top.add(restartPanel); + + JPanel controls = new JPanel(new BorderLayout(8, 8)); + controls.add(input, BorderLayout.CENTER); + controls.add(guessBtn, BorderLayout.EAST); + + hangPanel.setPreferredSize(new Dimension(500, 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 new game */ + private void startGame() { + int diffIndex = difficultyCombo.getSelectedIndex(); // 0=Facile,1=Moyen,2=Difficile + int diffValue = diffIndex + 1; + secretWord = manager.getRandomWord(diffValue).toLowerCase(Locale.ROOT); + + found.clear(); + tried.clear(); + errors = 0; + gameOver = false; + startTime = System.currentTimeMillis(); + + input.setText(""); + input.setEditable(true); + guessBtn.setEnabled(true); + infoLbl.setText("Entrez une lettre (a-z)"); + updateUIState(); + + if (timer != null) timer.cancel(); + timer = new Timer(true); + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + SwingUtilities.invokeLater(() -> { + updateScoreLabel(); + updateTimerLabel(); + }); + } + }, 0, 200); + } + + /** Handle guess */ + private void onGuess() { + if (gameOver) return; + + 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 (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(); + } + + /** Update UI */ + private void updateUIState() { + wordLbl.setText(maskWord(secretWord, found)); + triedLbl.setText("Lettres essayées : " + joinChars(tried)); + hangPanel.setErrors(errors); + updateScoreLabel(); + updateTimerLabel(); + + if (isWin(secretWord, found)) { + infoLbl.setText("Bravo ! Vous avez trouvé le mot : " + secretWord); + wordLbl.setText(spaced(secretWord)); + gameOver = true; + disableInput(); + } else if (errors >= MAX_ERRORS) { + infoLbl.setText("Perdu ! Le mot était : " + secretWord); + wordLbl.setText(spaced(secretWord)); + gameOver = true; + disableInput(); + } + } + + /** Update dynamic score */ + private void updateScoreLabel() { + long elapsedMillis = System.currentTimeMillis() - startTime; + double elapsedSeconds = elapsedMillis / 1000.0; + int score = (int) (baseScore - errors * mistakePenalty - elapsedSeconds * timePenaltyPerSecond); + scoreLbl.setText("Score: " + Math.max(score, 0)); + } + + /** Update dynamic timer */ + private void updateTimerLabel() { + long elapsedMillis = System.currentTimeMillis() - startTime; + int seconds = (int) (elapsedMillis / 1000); + timerLbl.setText("Temps: " + seconds + "s"); + } + + /** Disable input after end */ + private void disableInput() { + input.setEditable(false); + guessBtn.setEnabled(false); + if (timer != null) timer.cancel(); + } + + 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(); + } + + 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; + } + + 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(); + } + + 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(); + } +}