10 Commits

Author SHA1 Message Date
01835f841a incroyable 2025-10-08 17:07:11 +02:00
d8647f43ac reparation peut etre 2025-10-08 17:02:53 +02:00
d75f05bee0 ajout d'un bouton retour 2025-10-08 16:20:13 +02:00
64108a95e9 niveau 2025-10-08 16:15:19 +02:00
c0d2e0e5e2 Merge branch 'master' into DUCREUX 2025-10-08 15:48:04 +02:00
78333b0c32 Merge branch 'JANNAIRE' 2025-10-08 15:42:18 +02:00
5b7f341011 rm ou 2025-10-08 15:41:41 +02:00
2c611bc6fd ajout du score et du chrono plus doc 2025-10-08 15:41:08 +02:00
8b079bc103 reparation 2025-10-08 15:26:45 +02:00
485b63357e rm 2025-10-08 15:11:02 +02:00
25 changed files with 427 additions and 255 deletions

View File

@@ -1,155 +1,132 @@
package front;
package back;
import back.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Interface graphique du jeu du pendu.
* (Toutes les méthodes ≤ 50 lignes)
* Logique principale du jeu du pendu (back).
* Ajoute un score et un chronomètre.
*
* Règles de score (simples) :
* - Lettre correcte : +10 points
* - Lettre incorrecte: -5 points (le score ne descend pas sous 0)
* - Bonus victoire : nombre d'erreure restante sur 6 fois 10
* - Bonus temps : Chaque seconde restante avant 60s vaut 2 points si tu met plus de 60 secondes tu n'a pas de bonus
* - Défaite : pas de bonus
*
* Chronomètre :
* - Démarre à la création de la partie
* - S'arrête définitivement à la fin (victoire/défaite)
*/
public class GameUI {
private JFrame frame;
private JLabel imgLabel, wordLabel, triedLabel, scoreLabel, timeLabel;
private JTextField input;
private JButton tryBtn, newGameBtn;
private Game game;
private String currentWord;
private Timer timer;
public class Game {
private final String word;
private final Set<Character> correct = new HashSet<>();
private final Set<Character> all = new HashSet<>();
private final int maxErrors;
private int errors;
/** Lance la fenêtre et démarre une partie */
public void show() {
setupWindow();
setupLayout();
setupActions();
startNewGame();
frame.setVisible(true);
// --- Score & chrono ---
private int score = 0;
private long startNano; // début de partie (System.nanoTime)
private long endNano = -1L; // fin (sinon -1 = en cours)
public Game(String word, int maxErrors) {
this.word = word.toLowerCase();
this.maxErrors = maxErrors;
this.startNano = System.nanoTime(); // démarre le chrono à la création
}
/** Crée la fenêtre principale */
private void setupWindow() {
frame = new JFrame("Jeu du Pendu");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(560, 560);
frame.setLocationRelativeTo(null);
frame.setLayout(new BorderLayout(12, 12));
}
/** Tente une lettre et renvoie le résultat + ajuste le score */
public Result play(char letter) {
char c = Character.toLowerCase(letter);
if (all.contains(c)) return Result.ALREADY;
/** Construit les composants et le layout */
private void setupLayout() {
imgLabel = new JLabel("", SwingConstants.CENTER);
frame.add(imgLabel, BorderLayout.CENTER);
wordLabel = new JLabel("Mot : ");
triedLabel = new JLabel("Lettres essayées : ");
scoreLabel = new JLabel("Score : 0");
timeLabel = new JLabel("Temps : 0s");
JPanel top = new JPanel(new GridLayout(2, 1));
top.add(buildTopLine(wordLabel, scoreLabel));
top.add(buildTopLine(triedLabel, timeLabel));
frame.add(top, BorderLayout.NORTH);
JPanel bottom = new JPanel(new BorderLayout(8, 8));
JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
input = new JTextField(5);
tryBtn = new JButton("Essayer");
newGameBtn = new JButton("Nouvelle partie");
inputPanel.add(new JLabel("Lettre :"));
inputPanel.add(input);
inputPanel.add(tryBtn);
bottom.add(inputPanel, BorderLayout.WEST);
bottom.add(newGameBtn, BorderLayout.EAST);
frame.add(bottom, BorderLayout.SOUTH);
}
/** Crée une ligne du haut avec 2 labels */
private JPanel buildTopLine(JLabel left, JLabel right) {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
panel.add(left);
panel.add(Box.createHorizontalStrut(24));
panel.add(right);
return panel;
}
/** Ajoute les actions et le timer */
private void setupActions() {
tryBtn.addActionListener(this::onTry);
input.addActionListener(this::onTry);
newGameBtn.addActionListener(e -> startNewGame());
timer = new Timer(1000, e -> refreshStatsOnly());
}
/** Démarre une nouvelle partie */
private void startNewGame() {
currentWord = Words.random();
game = new Game(currentWord, 7);
input.setText("");
input.requestFocusInWindow();
if (!timer.isRunning()) timer.start();
refreshUI();
}
/** Gère le clic ou l'appui sur Entrée */
private void onTry(ActionEvent e) {
String text = input.getText();
if (!Check.isLetter(text)) {
showMsg("Tape une seule lettre (A-Z).");
input.requestFocusInWindow();
input.selectAll();
return;
}
Result res = game.play(Character.toLowerCase(text.charAt(0)));
handleResult(res);
input.setText("");
refreshUI();
checkEnd();
}
/** Réagit selon le résultat d'une tentative */
private void handleResult(Result res) {
switch (res) {
case ALREADY:
showMsg("Lettre déjà utilisée.");
break;
case HIT:
case MISS:
break; // rien, juste refresh
all.add(c);
if (word.indexOf(c) >= 0) {
correct.add(c);
addScore(10);
// Si la lettre trouvée fait gagner immédiatement, on finalise ici
if (isWin()) end(true);
return Result.HIT;
} else {
addScore(-5);
if (isLose()) end(false);
return Result.MISS;
}
}
/** Vérifie si la partie est finie */
private void checkEnd() {
if (game.isWin() || game.isLose()) {
timer.stop();
game.end(game.isWin());
String msg = (game.isWin() ? "Bravo !" : "Perdu !")
+ " Le mot était : " + currentWord
+ "\nScore final : " + game.getScore()
+ "\nTemps : " + game.getElapsedSeconds() + "s";
showMsg(msg);
/** Retourne le mot masqué avec les lettres trouvées */
public String maskedWord() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
if (!Character.isLetter(c)) sb.append(c);
else if (correct.contains(c)) sb.append(c);
else sb.append('_');
if (i < word.length() - 1) sb.append(' ');
}
return sb.toString();
}
/** Vérifie si le joueur a gagné */
public boolean isWin() {
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
if (Character.isLetter(c) && !correct.contains(c)) return false;
}
return true;
}
/** Vérifie si le joueur a perdu */
public boolean isLose() {
return errors >= maxErrors;
}
/** Nombre d'erreurs actuelles */
public int getErrors() { return errors; }
/** Liste les lettres déjà essayées */
public List<String> triedLetters() {
List<Character> sorted = new ArrayList<>(all);
sorted.sort(Character::compareTo);
List<String> out = new ArrayList<>();
for (Character ch : sorted) out.add(String.valueOf(ch));
return out;
}
// ---------- Score & Chrono ----------
/** Retourne le score courant */
public int getScore() { return score; }
/** Secondes écoulées depuis le début (si finie, temps figé) */
public long getElapsedSeconds() {
long end = (endNano > 0L) ? endNano : System.nanoTime();
long deltaNs = end - startNano;
if (deltaNs < 0) deltaNs = 0;
return deltaNs / 1_000_000_000L;
}
/** Termine la partie (victoire/défaite) et applique le bonus si gagné */
public void end(boolean win) {
if (endNano > 0L) return; // déjà terminé
endNano = System.nanoTime();
if (win) {
int remaining = Math.max(0, maxErrors - errors);
int timeBonus = (int) Math.max(0, 60 - getElapsedSeconds()) * 2;
addScore(remaining * 10 + timeBonus);
}
}
/** Met à jour tout l'affichage */
private void refreshUI() {
imgLabel.setIcon(Gallows.icon(game.getErrors()));
wordLabel.setText("Mot : " + game.maskedWord());
triedLabel.setText("Lettres essayées : " + String.join(", ", game.triedLetters()));
refreshStatsOnly();
frame.repaint();
}
/** Met à jour uniquement score + chrono */
private void refreshStatsOnly() {
scoreLabel.setText("Score : " + game.getScore());
timeLabel.setText("Temps : " + game.getElapsedSeconds() + "s");
}
/** Affiche une boîte de message */
private void showMsg(String msg) {
JOptionPane.showMessageDialog(frame, msg);
// --- utilitaires privés ---
private void addScore(int delta) {
if (delta < 0) {
// lettre ratée => +1 erreur
errors++;
}
score += delta;
if (score < 0) score = 0;
}
}

View File

@@ -2,84 +2,129 @@ package back;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.*;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
/**
* Fournit les mots pour le jeu.
* - Lit d'abord "bibliothèque/mots.txt" (UTF-8), 1 mot par ligne.
* - Ignore les lignes vides et celles qui commencent par '#'.
* - Si le fichier est introuvable ou vide, bascule sur une liste par défaut.
* Gère la bibliothèque de mots (chargement + sélection aléatoire).
* - Lit "bibliothèque/mots.txt" OU "Bibliotheque/mots.txt" (UTF-8), 1 mot par ligne.
* - Ignore lignes vides et commentaires (#...).
* - Fournit des helpers pour tirer des mots selon la difficulté.
*/
public class Words {
/** Chemin du fichier de mots (relatif à la racine du projet). */
private static final Path WORDS_PATH = Paths.get("Bibliotheque", "mots.txt");
/** Chemins possibles (accents/casse) pour maximiser la compatibilité. */
private static final Path[] CANDIDATES = new Path[] {
Paths.get("bibliothèque", "mots.txt"),
Paths.get("Bibliotheque", "mots.txt")
};
/** Liste de secours si le fichier n'est pas disponible. */
private static final List<String> DEFAULT = List.of(
"algorithm", "variable", "function", "interface", "inheritance",
"exception", "compiler", "database", "network", "architecture",
"iteration", "recursion", "encryption", "framework", "protocol"
);
/** Liste de secours si aucun fichier trouvé/valide. */
private static final List<String> DEFAULT = new ArrayList<>();
static {
Collections.addAll(DEFAULT,
"algorithm","variable","function","interface","inheritance",
"exception","compiler","database","network","architecture",
"iteration","recursion","encryption","framework","protocol",
"java","pendu","ordinateur","developpement","interface"
);
}
/** RNG partagé et cache des mots chargés. */
private static final SecureRandom RNG = new SecureRandom();
/** Cache mémoire + RNG. */
private static volatile List<String> CACHE = null;
private static final SecureRandom RNG = new SecureRandom();
/**
* Retourne un mot choisi au hasard depuis le fichier ou la liste par défaut.
* Déclenche un chargement paresseux (lazy-load) si nécessaire.
*/
/** Renvoie la liste complète (copie) — charge une seule fois si nécessaire. */
public static List<String> all() {
ensureLoaded();
return new ArrayList<>(CACHE);
}
/** Renvoie un mot aléatoire dans tout le dictionnaire. */
public static String random() {
ensureLoaded();
return CACHE.get(RNG.nextInt(CACHE.size()));
}
/**
* Recharge les mots depuis le fichier. Utile si modification de mots.txt à chaud.
*/
/** Renvoie un mot aléatoire de moins de 8 lettres (sinon bascule sur random()). */
public static String randomShortWord() {
ensureLoaded();
List<String> list = new ArrayList<>();
for (String w : CACHE) if (w.length() < 8) list.add(w);
if (list.isEmpty()) return random();
return list.get(RNG.nextInt(list.size()));
}
/** Renvoie un mot aléatoire de 8 lettres ou plus (sinon bascule sur random()). */
public static String randomLongWord() {
ensureLoaded();
List<String> list = new ArrayList<>();
for (String w : CACHE) if (w.length() >= 8) list.add(w);
if (list.isEmpty()) return random();
return list.get(RNG.nextInt(list.size()));
}
/** Renvoie une paire [court, long] pour le niveau difficile. */
public static List<String> randomPair() {
List<String> pair = new ArrayList<>(2);
pair.add(randomShortWord());
pair.add(randomLongWord());
return pair;
}
/** Force le rechargement du fichier (au cas où le contenu change en cours dexécution). */
public static synchronized void reload() {
CACHE = loadFromFileOrDefault();
}
/** Garantit que le cache est initialisé. */
// -------------------- internes --------------------
/** Charge le cache si nécessaire (thread-safe). */
private static void ensureLoaded() {
if (CACHE == null) {
synchronized (Words.class) {
if (CACHE == null) {
CACHE = loadFromFileOrDefault();
}
if (CACHE == null) CACHE = loadFromFileOrDefault();
}
}
}
/** Tente de charger depuis le fichier, sinon renvoie la liste par défaut. */
/** Tente chaque chemin candidat, sinon retourne DEFAULT mélangé. */
private static List<String> loadFromFileOrDefault() {
List<String> fromFile = readUtf8Lines(WORDS_PATH);
if (fromFile.isEmpty()) return DEFAULT;
return fromFile;
List<String> data = readFirstExistingCandidate();
if (data.isEmpty()) {
data = new ArrayList<>(DEFAULT);
}
Collections.shuffle(data, RNG); // casse tout déterminisme initial
return data;
}
/**
* Lit toutes les lignes UTF-8 depuis le chemin fourni,
* en filtrant vides et commentaires (# ...).
*/
private static List<String> readUtf8Lines(Path path) {
List<String> result = new ArrayList<>();
try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) {
lines.map(String::trim)
.filter(s -> !s.isEmpty())
.filter(s -> !s.startsWith("#"))
.forEach(result::add);
} catch (IOException e) {
// Silencieux : on basculera sur DEFAULT
/** Lit le premier fichier existant parmi les candidats. */
private static List<String> readFirstExistingCandidate() {
for (Path p : CANDIDATES) {
List<String> list = readUtf8Trimmed(p);
if (!list.isEmpty()) return list;
}
return result;
return new ArrayList<>();
}
}
/** Lit un fichier UTF-8, filtre vides/commentaires, force lowercase. */
private static List<String> readUtf8Trimmed(Path path) {
List<String> out = new ArrayList<>();
try {
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
for (String raw : lines) {
if (raw == null) continue;
String s = raw.trim().toLowerCase();
if (s.isEmpty() || s.startsWith("#")) continue;
// On accepte lettres/accentuées + tiret (simple et robuste)
if (s.matches("[a-zàâçéèêëîïôûùüÿñæœ-]+")) out.add(s);
}
} catch (IOException ignored) {
// on tombera sur DEFAULT
}
return out;
}
}

View File

@@ -1,125 +1,226 @@
package front;
import back.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
/**
* Interface graphique (Swing) du jeu du pendu.
* - Affiche une image différente à chaque erreur.
* - Champ de saisie pour entrer une lettre.
* - Texte pour le mot masqué et les lettres essayées.
* Interface graphique du pendu avec niveaux :
* - 1 : mots < 8 lettres
* - 2 : mots ≥ 8 lettres
* - 3 : deux mots (score + chrono cumulés)
* Boutons : Essayer / Nouvelle partie / Menu / Quitter.
* (Toutes les méthodes ≤ 50 lignes)
*/
public class GameUI {
private JFrame frame;
private JLabel imgLabel;
private JLabel wordLabel;
private JLabel triedLabel;
private JLabel imgLabel, wordLabel, triedLabel, scoreLabel, timeLabel;
private JTextField input;
private JButton tryBtn;
private JButton newGameBtn;
private JButton tryBtn, newBtn, menuBtn, quitBtn;
private Game game;
private String currentWord;
private List<String> words;
private int index = 0;
private final int level;
private String currentWord = "";
private Timer timer;
/** Affiche la fenêtre principale */
// Cumul de session (niveau 3)
private long sessionStartNano = -1L;
private int sessionScore = 0;
/** Reçoit la difficulté (1, 2, 3). */
public GameUI(int level) {
this.level = level;
}
/** Affiche la fenêtre et lance la session. */
public void show() {
setupUI();
startNewGame();
setupWindow();
setupLayout();
setupActions();
startNewSession();
frame.setVisible(true);
}
/** Initialise les composants Swing */
private void setupUI() {
/** Démarre une nouvelle session (nouveaux mots, reset chrono/score session). */
private void startNewSession() {
sessionStartNano = System.nanoTime();
sessionScore = 0;
index = 0;
prepareWords();
startRound();
}
/** Prépare la liste des mots selon le niveau (aléatoire géré dans Words). */
private void prepareWords() {
words = new ArrayList<>();
if (level == 1) {
words.add(Words.randomShortWord());
} else if (level == 2) {
words.add(Words.randomLongWord());
} else if (level == 3) {
words = Words.randomPair(); // [court, long] aléatoires
}
if (words.isEmpty()) words.add(Words.random()); // filet de sécurité
}
/** Fenêtre principale. */
private void setupWindow() {
frame = new JFrame("Jeu du Pendu");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(520, 520);
frame.setSize(560, 560);
frame.setLocationRelativeTo(null);
frame.setLayout(new BorderLayout(12, 12));
}
// Image du pendu
/** Layout + composants. */
private void setupLayout() {
imgLabel = new JLabel("", SwingConstants.CENTER);
frame.add(imgLabel, BorderLayout.CENTER);
// Panneau bas: saisie + actions
wordLabel = new JLabel("Mot : ");
triedLabel = new JLabel("Lettres essayées : ");
scoreLabel = new JLabel("Score : 0");
timeLabel = new JLabel("Temps : 0s");
JPanel top = new JPanel(new GridLayout(2, 1));
top.add(buildTopLine(wordLabel, scoreLabel));
top.add(buildTopLine(triedLabel, timeLabel));
frame.add(top, BorderLayout.NORTH);
JPanel bottom = new JPanel(new BorderLayout(8, 8));
JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
input = new JTextField(5);
tryBtn = new JButton("Essayer");
newBtn = new JButton("Nouvelle partie");
inputPanel.add(new JLabel("Lettre :"));
inputPanel.add(input);
inputPanel.add(tryBtn);
inputPanel.add(newBtn);
JPanel actionPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
menuBtn = new JButton("Menu");
quitBtn = new JButton("Quitter");
actionPanel.add(menuBtn);
actionPanel.add(quitBtn);
newGameBtn = new JButton("Nouvelle partie");
bottom.add(inputPanel, BorderLayout.WEST);
bottom.add(newGameBtn, BorderLayout.EAST);
bottom.add(actionPanel, BorderLayout.EAST);
frame.add(bottom, BorderLayout.SOUTH);
// Panneau haut: mot + lettres essayées
JPanel top = new JPanel();
top.setLayout(new BoxLayout(top, BoxLayout.Y_AXIS));
wordLabel = new JLabel("Mot : ");
triedLabel = new JLabel("Lettres essayées : ");
wordLabel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
triedLabel.setBorder(BorderFactory.createEmptyBorder(0, 8, 8, 8));
top.add(wordLabel);
top.add(triedLabel);
frame.add(top, BorderLayout.NORTH);
// Actions
tryBtn.addActionListener(this::onTry);
input.addActionListener(this::onTry);
newGameBtn.addActionListener(e -> startNewGame());
}
/** Démarre une nouvelle partie */
private void startNewGame() {
currentWord = Words.random();
/** Ligne dinfos (gauche/droite). */
private JPanel buildTopLine(JLabel left, JLabel right) {
JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));
p.add(left);
p.add(Box.createHorizontalStrut(24));
p.add(right);
return p;
}
/** Actions + timer. */
private void setupActions() {
tryBtn.addActionListener(this::onTry);
input.addActionListener(this::onTry);
newBtn.addActionListener(e -> startNewSession());
menuBtn.addActionListener(e -> returnToMenu());
quitBtn.addActionListener(e -> frame.dispose());
timer = new Timer(1000, e -> refreshStatsOnly());
}
/** Retour vers le menu de sélection. */
private void returnToMenu() {
timer.stop();
frame.dispose();
MenuUI menu = new MenuUI();
menu.show();
}
/** Démarre un nouveau mot (ou termine la session si plus de mots). */
private void startRound() {
if (index >= words.size()) {
int total = (level == 3) ? sessionScore : game.getScore();
long secs = (level == 3) ? getSessionSeconds() : game.getElapsedSeconds();
showMsg("Niveau terminé !\nScore total : " + total + "\nTemps : " + secs + "s");
return;
}
currentWord = words.get(index++);
game = new Game(currentWord, 7);
input.setText("");
input.requestFocusInWindow();
if (!timer.isRunning()) timer.start();
refreshUI();
}
/** Gère le clic sur "Essayer" ou Entrée dans le champ */
/** Tente une lettre (bouton/Entrée). */
private void onTry(ActionEvent e) {
String text = input.getText();
if (!Check.isLetter(text)) {
JOptionPane.showMessageDialog(frame, "Tape une seule lettre (A-Z).");
showMsg("Tape une seule lettre (A-Z).");
input.requestFocusInWindow();
input.selectAll();
return;
}
char c = Character.toLowerCase(text.charAt(0));
Result res = game.play(c);
switch (res) {
case ALREADY: JOptionPane.showMessageDialog(frame, "Lettre déjà utilisée.");
break;
case HIT:
break;
case MISS:
break;
}
Result res = game.play(Character.toLowerCase(text.charAt(0)));
if (res == Result.ALREADY) showMsg("Lettre déjà utilisée.");
input.setText("");
refreshUI();
checkEnd();
}
if (game.isWin()) {
refreshUI();
JOptionPane.showMessageDialog(frame, "Bravo ! Le mot était : " + currentWord);
} else if (game.isLose()) {
refreshUI();
JOptionPane.showMessageDialog(frame, "Perdu ! Le mot était : " + currentWord);
/** Fin du mot → affiche popup et enchaîne (lvl 3 cumule score/chrono). */
private void checkEnd() {
if (!(game.isWin() || game.isLose())) return;
game.end(game.isWin());
int displayScore = (level == 3) ? sessionScore + game.getScore() : game.getScore();
long displaySecs = (level == 3) ? getSessionSeconds() : game.getElapsedSeconds();
showMsg((game.isWin() ? "Bravo !" : "Perdu !")
+ " Le mot était : " + currentWord
+ "\nScore : " + displayScore
+ "\nTemps : " + displaySecs + "s");
if (level == 3 && index < words.size()) {
sessionScore += game.getScore();
startRound();
} else {
timer.stop();
}
}
/** Met à jour l'image et les textes selon l'état courant */
/** Refresh complet. */
private void refreshUI() {
imgLabel.setIcon(Gallows.icon(game.getErrors()));
wordLabel.setText("Mot : " + game.maskedWord());
triedLabel.setText("Lettres essayées : " + String.join(", ", game.triedLetters()));
refreshStatsOnly();
frame.repaint();
}
}
/** Refresh stats (score/chrono). */
private void refreshStatsOnly() {
int s = (level == 3) ? sessionScore + game.getScore() : game.getScore();
long t = (level == 3) ? getSessionSeconds() : game.getElapsedSeconds();
scoreLabel.setText("Score : " + s);
timeLabel.setText("Temps : " + t + "s");
}
/** Secondes écoulées depuis le début de la session (niveau 3). */
private long getSessionSeconds() {
long now = System.nanoTime();
long delta = now - sessionStartNano;
if (delta < 0) delta = 0;
return delta / 1_000_000_000L;
}
/** Popup info. */
private void showMsg(String msg) {
JOptionPane.showMessageDialog(frame, msg);
}
}

View File

@@ -0,0 +1,50 @@
package front;
import javax.swing.*;
import java.awt.*;
/*
* Menu de démarrage du jeu du pendu.
* Permet de choisir la difficulté (facile, moyen ou difficile).
*/
public class MenuUI {
private JFrame frame;
/**
* Interface graphique de la page d'accueil du jeu du pendu.
*/
public void show() {
frame = new JFrame("Jeu du Pendu - Sélection de la difficulté");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setLayout(new BorderLayout(12, 12));
JLabel title = new JLabel("Choisis une difficulté", SwingConstants.CENTER);
title.setFont(new Font("Arial", Font.BOLD, 20));
frame.add(title, BorderLayout.NORTH);
JPanel buttons = new JPanel(new GridLayout(3, 1, 10, 10));
JButton easyBtn = new JButton("Niveau Facile");
JButton mediumBtn = new JButton("Niveau Moyen");
JButton hardBtn = new JButton("Niveau Difficile");
buttons.add(easyBtn);
buttons.add(mediumBtn);
buttons.add(hardBtn);
frame.add(buttons, BorderLayout.CENTER);
easyBtn.addActionListener(e -> startGame(1));
mediumBtn.addActionListener(e -> startGame(2));
hardBtn.addActionListener(e -> startGame(3));
frame.setVisible(true);
}
/* Lance le jeu avec le niveau choisi */
private void startGame(int level) {
frame.dispose(); // ferme le menu
GameUI ui = new GameUI(level);
ui.show();
}
}

View File

@@ -1,17 +1,16 @@
package main;
import front.GameUI;
import front.MenuUI;
/**
* Point d'entrée du programme.
* Lance l'interface graphique du jeu du pendu.
*/
* Point d'entrée du programme.
* Affiche le menu de sélection avant de lancer le jeu.
*/
public class Main {
public static void main(String[] args) {
// Démarre l'UI Swing sur le thread de l'EDT
javax.swing.SwingUtilities.invokeLater(() -> {
GameUI ui = new GameUI();
ui.show();
MenuUI menu = new MenuUI();
menu.show();
});
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
out/back/Check.class Normal file

Binary file not shown.

BIN
out/back/Game.class Normal file

Binary file not shown.

BIN
out/back/Result.class Normal file

Binary file not shown.

BIN
out/back/Words.class Normal file

Binary file not shown.

Binary file not shown.

BIN
out/front/Gallows.class Normal file

Binary file not shown.

BIN
out/front/GameUI$1.class Normal file

Binary file not shown.

BIN
out/front/GameUI.class Normal file

Binary file not shown.

BIN
out/main/Main.class Normal file

Binary file not shown.