Files
TD3_DEV51_DUCREUX_JANNAIRE/Jeu_pendu/Back/Words.java

131 lines
4.7 KiB
Java
Raw Normal View History

2025-10-08 12:14:42 +02:00
package back;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
2025-10-08 17:02:53 +02:00
import java.nio.file.*;
2025-10-08 12:14:42 +02:00
import java.security.SecureRandom;
import java.util.ArrayList;
2025-10-08 17:02:53 +02:00
import java.util.Collections;
2025-10-08 12:14:42 +02:00
import java.util.List;
/**
2025-10-08 17:02:53 +02:00
* 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é.
2025-10-08 12:14:42 +02:00
*/
public class Words {
2025-10-08 17:02:53 +02:00
/** 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")
};
2025-10-08 12:14:42 +02:00
2025-10-08 17:02:53 +02:00
/** 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"
);
}
2025-10-08 12:14:42 +02:00
2025-10-08 17:02:53 +02:00
/** Cache mémoire + RNG. */
2025-10-08 12:14:42 +02:00
private static volatile List<String> CACHE = null;
2025-10-08 17:02:53 +02:00
private static final SecureRandom RNG = new SecureRandom();
2025-10-08 12:14:42 +02:00
2025-10-08 17:02:53 +02:00
/** 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. */
2025-10-08 12:14:42 +02:00
public static String random() {
ensureLoaded();
return CACHE.get(RNG.nextInt(CACHE.size()));
}
2025-10-08 17:02:53 +02:00
/** 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). */
2025-10-08 12:14:42 +02:00
public static synchronized void reload() {
CACHE = loadFromFileOrDefault();
}
2025-10-08 17:02:53 +02:00
// -------------------- internes --------------------
/** Charge le cache si nécessaire (thread-safe). */
2025-10-08 12:14:42 +02:00
private static void ensureLoaded() {
if (CACHE == null) {
synchronized (Words.class) {
2025-10-08 17:02:53 +02:00
if (CACHE == null) CACHE = loadFromFileOrDefault();
2025-10-08 12:14:42 +02:00
}
}
}
2025-10-08 17:02:53 +02:00
/** Tente chaque chemin candidat, sinon retourne DEFAULT mélangé. */
2025-10-08 12:14:42 +02:00
private static List<String> loadFromFileOrDefault() {
2025-10-08 17:02:53 +02:00
List<String> data = readFirstExistingCandidate();
if (data.isEmpty()) {
data = new ArrayList<>(DEFAULT);
2025-10-08 12:14:42 +02:00
}
2025-10-08 17:02:53 +02:00
Collections.shuffle(data, RNG); // casse tout déterminisme initial
return data;
2025-10-08 12:14:42 +02:00
}
2025-10-08 16:15:19 +02:00
2025-10-08 17:02:53 +02:00
/** 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 new ArrayList<>();
2025-10-08 16:15:19 +02:00
}
2025-10-08 17:02:53 +02:00
/** 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;
2025-10-08 16:15:19 +02:00
}
2025-10-08 17:02:53 +02:00
}