forked from menault/TD3_DEV51_Qualite_Algo
Compare commits
2 Commits
JANNAIRE
...
4b7d0c7753
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b7d0c7753 | |||
| cc14043782 |
@@ -2,129 +2,94 @@ package back;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.*;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gère la bibliothèque de mots (chargement + sélection aléatoire).
|
* Fournit les mots pour le jeu.
|
||||||
* - Lit "bibliothèque/mots.txt" OU "Bibliotheque/mots.txt" (UTF-8), 1 mot par ligne.
|
* - Lit d'abord "bibliothèque/mots.txt" (UTF-8), 1 mot par ligne.
|
||||||
* - Ignore lignes vides et commentaires (#...).
|
* - Ignore les lignes vides et celles qui commencent par '#'.
|
||||||
* - Fournit des helpers pour tirer des mots selon la difficulté.
|
* - Si le fichier est introuvable ou vide, bascule sur une liste par défaut.
|
||||||
*/
|
*/
|
||||||
public class Words {
|
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é. */
|
/** Liste de secours si le fichier n'est pas disponible. */
|
||||||
private static final Path[] CANDIDATES = new Path[] {
|
private static final List<String> DEFAULT = List.of(
|
||||||
Paths.get("bibliothèque", "mots.txt"),
|
"algorithm", "variable", "function", "interface", "inheritance",
|
||||||
Paths.get("Bibliotheque", "mots.txt")
|
"exception", "compiler", "database", "network", "architecture",
|
||||||
};
|
"iteration", "recursion", "encryption", "framework", "protocol"
|
||||||
|
);
|
||||||
|
|
||||||
/** Liste de secours si aucun fichier trouvé/valide. */
|
/** RNG partagé et cache des mots chargés. */
|
||||||
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"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Cache mémoire + RNG. */
|
|
||||||
private static volatile List<String> CACHE = null;
|
|
||||||
private static final SecureRandom RNG = new SecureRandom();
|
private static final SecureRandom RNG = new SecureRandom();
|
||||||
|
private static volatile List<String> CACHE = null;
|
||||||
|
|
||||||
/** Renvoie la liste complète (copie) — charge une seule fois si nécessaire. */
|
/**
|
||||||
public static List<String> all() {
|
* Retourne un mot choisi au hasard depuis le fichier ou la liste par défaut.
|
||||||
ensureLoaded();
|
* Déclenche un chargement paresseux (lazy-load) si nécessaire.
|
||||||
return new ArrayList<>(CACHE);
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
/** Renvoie un mot aléatoire dans tout le dictionnaire. */
|
|
||||||
public static String random() {
|
public static String random() {
|
||||||
ensureLoaded();
|
ensureLoaded();
|
||||||
return CACHE.get(RNG.nextInt(CACHE.size()));
|
return CACHE.get(RNG.nextInt(CACHE.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Renvoie un mot aléatoire de moins de 8 lettres (sinon bascule sur random()). */
|
/**
|
||||||
public static String randomShortWord() {
|
* Recharge les mots depuis le fichier. Utile si modification de mots.txt à chaud.
|
||||||
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 d’exécution). */
|
|
||||||
public static synchronized void reload() {
|
public static synchronized void reload() {
|
||||||
CACHE = loadFromFileOrDefault();
|
CACHE = loadFromFileOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------- internes --------------------
|
/** Garantit que le cache est initialisé. */
|
||||||
|
|
||||||
/** Charge le cache si nécessaire (thread-safe). */
|
|
||||||
private static void ensureLoaded() {
|
private static void ensureLoaded() {
|
||||||
if (CACHE == null) {
|
if (CACHE == null) {
|
||||||
synchronized (Words.class) {
|
synchronized (Words.class) {
|
||||||
if (CACHE == null) CACHE = loadFromFileOrDefault();
|
if (CACHE == null) {
|
||||||
|
CACHE = loadFromFileOrDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tente chaque chemin candidat, sinon retourne DEFAULT mélangé. */
|
/** Tente de charger depuis le fichier, sinon renvoie la liste par défaut. */
|
||||||
private static List<String> loadFromFileOrDefault() {
|
private static List<String> loadFromFileOrDefault() {
|
||||||
List<String> data = readFirstExistingCandidate();
|
List<String> fromFile = readUtf8Lines(WORDS_PATH);
|
||||||
if (data.isEmpty()) {
|
if (fromFile.isEmpty()) return DEFAULT;
|
||||||
data = new ArrayList<>(DEFAULT);
|
return fromFile;
|
||||||
}
|
|
||||||
Collections.shuffle(data, RNG); // casse tout déterminisme initial
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Lit le premier fichier existant parmi les candidats. */
|
/**
|
||||||
private static List<String> readFirstExistingCandidate() {
|
* Lit toutes les lignes UTF-8 depuis le chemin fourni,
|
||||||
for (Path p : CANDIDATES) {
|
* en filtrant vides et commentaires (# ...).
|
||||||
List<String> list = readUtf8Trimmed(p);
|
*/
|
||||||
if (!list.isEmpty()) return list;
|
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
|
||||||
}
|
}
|
||||||
return new ArrayList<>();
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Lit un fichier UTF-8, filtre vides/commentaires, force lowercase. */
|
/** Retourne la liste complète des mots disponibles */
|
||||||
private static List<String> readUtf8Trimmed(Path path) {
|
public static List<String> all() {
|
||||||
List<String> out = new ArrayList<>();
|
ensureLoaded();
|
||||||
try {
|
return new ArrayList<>(CACHE);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/** Petit utilitaire pour afficher un mot masqué dans les messages */
|
||||||
|
public static String hiddenWord(Game g) {
|
||||||
|
return g.maskedWord().replace(' ', '_');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,67 +9,65 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface graphique du pendu avec niveaux :
|
* Interface graphique du jeu du pendu avec gestion des difficultés.
|
||||||
* - 1 : mots < 8 lettres
|
* - Niveau Facile : mots < 8 lettres
|
||||||
* - 2 : mots ≥ 8 lettres
|
* - Niveau Moyen : mots ≥ 8 lettres
|
||||||
* - 3 : deux mots (score + chrono cumulés)
|
* - Niveau Difficile : deux mots à la suite (score & chrono cumulés)
|
||||||
* Boutons : Essayer / Nouvelle partie / Menu / Quitter.
|
* Toutes les méthodes ≤ 50 lignes.
|
||||||
* (Toutes les méthodes ≤ 50 lignes)
|
|
||||||
*/
|
*/
|
||||||
public class GameUI {
|
public class GameUI {
|
||||||
private JFrame frame;
|
private JFrame frame;
|
||||||
private JLabel imgLabel, wordLabel, triedLabel, scoreLabel, timeLabel;
|
private JLabel imgLabel, wordLabel, triedLabel, scoreLabel, timeLabel;
|
||||||
private JTextField input;
|
private JTextField input;
|
||||||
private JButton tryBtn, newBtn, menuBtn, quitBtn;
|
private JButton tryBtn, quitBtn, menuBtn, newGameBtn;
|
||||||
|
|
||||||
private Game game;
|
private Game game;
|
||||||
private List<String> words;
|
private List<String> words;
|
||||||
private int index = 0;
|
private int index = 0;
|
||||||
private final int level;
|
private int level;
|
||||||
private String currentWord = "";
|
private String currentWord = "";
|
||||||
private Timer timer;
|
private Timer timer;
|
||||||
|
|
||||||
// Cumul de session (niveau 3)
|
// Cumul pour le niveau 3
|
||||||
private long sessionStartNano = -1L;
|
private long sessionStartNano = -1L; // début du niveau
|
||||||
private int sessionScore = 0;
|
private int sessionScore = 0; // score cumulé des mots terminés
|
||||||
|
|
||||||
/** Reçoit la difficulté (1, 2, 3). */
|
public GameUI(int level) { this.level = level; }
|
||||||
public GameUI(int level) {
|
|
||||||
this.level = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Affiche la fenêtre et lance la session. */
|
/** Affiche la fenêtre et lance la partie (ou séquence) */
|
||||||
public void show() {
|
public void show() {
|
||||||
setupWindow();
|
setupWindow();
|
||||||
setupLayout();
|
setupLayout();
|
||||||
setupActions();
|
setupActions();
|
||||||
startNewSession();
|
prepareWords();
|
||||||
|
sessionStartNano = System.nanoTime(); // CHRONO DE SESSION (lvl 3)
|
||||||
|
startRound();
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Démarre une nouvelle session (nouveaux mots, reset chrono/score session). */
|
/** Prépare la liste des mots selon la difficulté choisie */
|
||||||
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() {
|
private void prepareWords() {
|
||||||
words = new ArrayList<>();
|
words = new ArrayList<String>();
|
||||||
|
List<String> all = Words.all();
|
||||||
|
|
||||||
if (level == 1) {
|
if (level == 1) {
|
||||||
words.add(Words.randomShortWord());
|
for (String w : all) if (w.length() < 8) words.add(w);
|
||||||
} else if (level == 2) {
|
} else if (level == 2) {
|
||||||
words.add(Words.randomLongWord());
|
for (String w : all) if (w.length() >= 8) words.add(w);
|
||||||
} else if (level == 3) {
|
} else if (level == 3) {
|
||||||
words = Words.randomPair(); // [court, long] aléatoires
|
String shortW = null, longW = null;
|
||||||
|
for (String w : all) {
|
||||||
|
if (shortW == null && w.length() < 8) shortW = w;
|
||||||
|
if (longW == null && w.length() >= 8) longW = w;
|
||||||
|
if (shortW != null && longW != null) break;
|
||||||
|
}
|
||||||
|
if (shortW != null) words.add(shortW);
|
||||||
|
if (longW != null) words.add(longW);
|
||||||
}
|
}
|
||||||
if (words.isEmpty()) words.add(Words.random()); // filet de sécurité
|
if (words.isEmpty()) words.add(Words.random());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fenêtre principale. */
|
/** Crée la fenêtre principale */
|
||||||
private void setupWindow() {
|
private void setupWindow() {
|
||||||
frame = new JFrame("Jeu du Pendu");
|
frame = new JFrame("Jeu du Pendu");
|
||||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
@@ -78,7 +76,7 @@ public class GameUI {
|
|||||||
frame.setLayout(new BorderLayout(12, 12));
|
frame.setLayout(new BorderLayout(12, 12));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Layout + composants. */
|
/** Construit la mise en page et les composants */
|
||||||
private void setupLayout() {
|
private void setupLayout() {
|
||||||
imgLabel = new JLabel("", SwingConstants.CENTER);
|
imgLabel = new JLabel("", SwingConstants.CENTER);
|
||||||
frame.add(imgLabel, BorderLayout.CENTER);
|
frame.add(imgLabel, BorderLayout.CENTER);
|
||||||
@@ -97,11 +95,10 @@ public class GameUI {
|
|||||||
JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||||
input = new JTextField(5);
|
input = new JTextField(5);
|
||||||
tryBtn = new JButton("Essayer");
|
tryBtn = new JButton("Essayer");
|
||||||
newBtn = new JButton("Nouvelle partie");
|
newGameBtn = new JButton("Nouvelle partie");
|
||||||
inputPanel.add(new JLabel("Lettre :"));
|
inputPanel.add(new JLabel("Lettre :"));
|
||||||
inputPanel.add(input);
|
inputPanel.add(input);
|
||||||
inputPanel.add(tryBtn);
|
inputPanel.add(tryBtn);
|
||||||
inputPanel.add(newBtn);
|
|
||||||
|
|
||||||
JPanel actionPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
JPanel actionPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
||||||
menuBtn = new JButton("Menu");
|
menuBtn = new JButton("Menu");
|
||||||
@@ -111,10 +108,11 @@ public class GameUI {
|
|||||||
|
|
||||||
bottom.add(inputPanel, BorderLayout.WEST);
|
bottom.add(inputPanel, BorderLayout.WEST);
|
||||||
bottom.add(actionPanel, BorderLayout.EAST);
|
bottom.add(actionPanel, BorderLayout.EAST);
|
||||||
|
top.add(newGameBtn, BorderLayout.EAST);
|
||||||
frame.add(bottom, BorderLayout.SOUTH);
|
frame.add(bottom, BorderLayout.SOUTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ligne d’infos (gauche/droite). */
|
/** Construit une ligne (label gauche + espace + label droit) */
|
||||||
private JPanel buildTopLine(JLabel left, JLabel right) {
|
private JPanel buildTopLine(JLabel left, JLabel right) {
|
||||||
JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||||
p.add(left);
|
p.add(left);
|
||||||
@@ -123,17 +121,16 @@ public class GameUI {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Actions + timer. */
|
/** Branche les actions + timer */
|
||||||
private void setupActions() {
|
private void setupActions() {
|
||||||
tryBtn.addActionListener(this::onTry);
|
tryBtn.addActionListener(this::onTry);
|
||||||
input.addActionListener(this::onTry);
|
input.addActionListener(this::onTry);
|
||||||
newBtn.addActionListener(e -> startNewSession());
|
|
||||||
menuBtn.addActionListener(e -> returnToMenu());
|
|
||||||
quitBtn.addActionListener(e -> frame.dispose());
|
quitBtn.addActionListener(e -> frame.dispose());
|
||||||
|
menuBtn.addActionListener(e -> returnToMenu());
|
||||||
timer = new Timer(1000, e -> refreshStatsOnly());
|
timer = new Timer(1000, e -> refreshStatsOnly());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Retour vers le menu de sélection. */
|
/** Retour au menu principal */
|
||||||
private void returnToMenu() {
|
private void returnToMenu() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
frame.dispose();
|
frame.dispose();
|
||||||
@@ -141,12 +138,14 @@ public class GameUI {
|
|||||||
menu.show();
|
menu.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Démarre un nouveau mot (ou termine la session si plus de mots). */
|
/** Démarre un nouveau mot (ou termine la séquence au niveau 3) */
|
||||||
private void startRound() {
|
private void startRound() {
|
||||||
if (index >= words.size()) {
|
if (index >= words.size()) {
|
||||||
int total = (level == 3) ? sessionScore : game.getScore();
|
// Fin du niveau (affiche score cumulé si lvl 3)
|
||||||
|
int finalScore = (level == 3) ? sessionScore : game.getScore();
|
||||||
long secs = (level == 3) ? getSessionSeconds() : game.getElapsedSeconds();
|
long secs = (level == 3) ? getSessionSeconds() : game.getElapsedSeconds();
|
||||||
showMsg("Niveau terminé !\nScore total : " + total + "\nTemps : " + secs + "s");
|
showMsg("Niveau terminé !\nScore total : " + finalScore + "\nTemps : " + secs + "s");
|
||||||
|
frame.dispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentWord = words.get(index++);
|
currentWord = words.get(index++);
|
||||||
@@ -157,7 +156,7 @@ public class GameUI {
|
|||||||
refreshUI();
|
refreshUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tente une lettre (bouton/Entrée). */
|
/** Tente une lettre (clic bouton ou Entrée) */
|
||||||
private void onTry(ActionEvent e) {
|
private void onTry(ActionEvent e) {
|
||||||
String text = input.getText();
|
String text = input.getText();
|
||||||
if (!Check.isLetter(text)) {
|
if (!Check.isLetter(text)) {
|
||||||
@@ -173,28 +172,29 @@ public class GameUI {
|
|||||||
checkEnd();
|
checkEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fin du mot → affiche popup et enchaîne (lvl 3 cumule score/chrono). */
|
/** Vérifie fin de mot et enchaîne si besoin (niveau 3 → cumule score & chrono) */
|
||||||
private void checkEnd() {
|
private void checkEnd() {
|
||||||
if (!(game.isWin() || game.isLose())) return;
|
if (!(game.isWin() || game.isLose())) return;
|
||||||
|
|
||||||
game.end(game.isWin());
|
game.end(game.isWin()); // applique bonus de fin pour ce mot
|
||||||
int displayScore = (level == 3) ? sessionScore + game.getScore() : game.getScore();
|
int displayScore = (level == 3) ? sessionScore + game.getScore() : game.getScore();
|
||||||
long displaySecs = (level == 3) ? getSessionSeconds() : game.getElapsedSeconds();
|
long displaySecs = (level == 3) ? getSessionSeconds() : game.getElapsedSeconds();
|
||||||
|
|
||||||
showMsg((game.isWin() ? "Bravo !" : "Perdu !")
|
String verdict = game.isWin() ? "Bravo !" : "Perdu !";
|
||||||
+ " Le mot était : " + currentWord
|
showMsg(verdict + " Le mot était : " + currentWord
|
||||||
+ "\nScore : " + displayScore
|
+ "\nScore : " + displayScore
|
||||||
+ "\nTemps : " + displaySecs + "s");
|
+ "\nTemps : " + displaySecs + "s");
|
||||||
|
|
||||||
if (level == 3 && index < words.size()) {
|
if (level == 3 && index < words.size()) {
|
||||||
|
// CUMULE le score du mot terminé, poursuit SANS réinitialiser le chrono
|
||||||
sessionScore += game.getScore();
|
sessionScore += game.getScore();
|
||||||
startRound();
|
startRound();
|
||||||
} else {
|
} else {
|
||||||
timer.stop();
|
timer.stop(); // fins niveaux 1/2, ou mot 2 du niveau 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Refresh complet. */
|
/** Rafraîchit image + textes + stats */
|
||||||
private void refreshUI() {
|
private void refreshUI() {
|
||||||
imgLabel.setIcon(Gallows.icon(game.getErrors()));
|
imgLabel.setIcon(Gallows.icon(game.getErrors()));
|
||||||
wordLabel.setText("Mot : " + game.maskedWord());
|
wordLabel.setText("Mot : " + game.maskedWord());
|
||||||
@@ -203,7 +203,7 @@ public class GameUI {
|
|||||||
frame.repaint();
|
frame.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Refresh stats (score/chrono). */
|
/** Rafraîchit uniquement score + chrono (cumul si niveau 3) */
|
||||||
private void refreshStatsOnly() {
|
private void refreshStatsOnly() {
|
||||||
int s = (level == 3) ? sessionScore + game.getScore() : game.getScore();
|
int s = (level == 3) ? sessionScore + game.getScore() : game.getScore();
|
||||||
long t = (level == 3) ? getSessionSeconds() : game.getElapsedSeconds();
|
long t = (level == 3) ? getSessionSeconds() : game.getElapsedSeconds();
|
||||||
@@ -211,7 +211,7 @@ public class GameUI {
|
|||||||
timeLabel.setText("Temps : " + t + "s");
|
timeLabel.setText("Temps : " + t + "s");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Secondes écoulées depuis le début de la session (niveau 3). */
|
/** Durée écoulée depuis le début du niveau (niveau 3) */
|
||||||
private long getSessionSeconds() {
|
private long getSessionSeconds() {
|
||||||
long now = System.nanoTime();
|
long now = System.nanoTime();
|
||||||
long delta = now - sessionStartNano;
|
long delta = now - sessionStartNano;
|
||||||
@@ -219,8 +219,6 @@ public class GameUI {
|
|||||||
return delta / 1_000_000_000L;
|
return delta / 1_000_000_000L;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Popup info. */
|
/** Affiche un message */
|
||||||
private void showMsg(String msg) {
|
private void showMsg(String msg) { JOptionPane.showMessageDialog(frame, msg); }
|
||||||
JOptionPane.showMessageDialog(frame, msg);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,7 @@ package front;
|
|||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Menu de démarrage du jeu du pendu.
|
* Menu de démarrage du jeu du pendu.
|
||||||
* Permet de choisir la difficulté (facile, moyen ou difficile).
|
* Permet de choisir la difficulté (facile, moyen ou difficile).
|
||||||
*/
|
*/
|
||||||
@@ -41,7 +41,7 @@ public class MenuUI {
|
|||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lance le jeu avec le niveau choisi */
|
/** Lance le jeu avec le niveau choisi */
|
||||||
private void startGame(int level) {
|
private void startGame(int level) {
|
||||||
frame.dispose(); // ferme le menu
|
frame.dispose(); // ferme le menu
|
||||||
GameUI ui = new GameUI(level);
|
GameUI ui = new GameUI(level);
|
||||||
|
|||||||
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.
14
README.md
14
README.md
@@ -5,11 +5,15 @@
|
|||||||
|
|
||||||
## Fonctionnalités
|
## Fonctionnalités
|
||||||
|
|
||||||
Affichage d’une **image différente du pendu** à chaque erreur
|
- Affichage d’une **image différente du pendu** à chaque erreur
|
||||||
Lecture de mots depuis un **fichier externe** (`bibliothèque/mots.txt`)
|
- Lecture de mots depuis un **fichier externe** (`bibliothèque/mots.txt`)
|
||||||
Validation des entrées (une seule LETTRE à la fois)
|
- Validation des entrées (une seule LETTRE à la fois)
|
||||||
Bouton **“Nouvelle partie”** pour rejouer sans relancer le programme
|
- Bouton **“Nouvelle partie”** pour rejouer sans relancer le programme
|
||||||
Messages de victoire / défaite
|
- Bouton **“Quitter”** pour quitter le programme
|
||||||
|
- Bouton **“Menu”** pour retourner à la page menu et pouvoir rechoisir le niveau de difficulté
|
||||||
|
- Messages de victoire / défaite
|
||||||
|
- Score + Chronomètre en direct
|
||||||
|
- Sélection du niveau dans le menu avant de jouer (Facile, Moyen, Difficile)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
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.
Reference in New Issue
Block a user