forked from menault/TD3_DEV51_Qualite_Algo
274 lines
9.5 KiB
Java
274 lines
9.5 KiB
Java
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<Character> found = new HashSet<>();
|
|
private final Set<Character> 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<Character> 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<Character> 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<Character> set) {
|
|
java.util.List<Character> 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();
|
|
}
|
|
}
|