package back; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * 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 : + (restant * 10) + bonus temps * * bonus temps = max(0, 60 - secondes) * 2 (jusqu'à 120 pts si < 60s) * - 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 Game { private final String word; private final Set correct = new HashSet<>(); private final Set all = new HashSet<>(); private final int maxErrors; private int errors; // --- 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 } /** 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; 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; } } /** 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 triedLetters() { List sorted = new ArrayList<>(all); sorted.sort(Character::compareTo); List 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); } } // --- utilitaires privés --- private void addScore(int delta) { if (delta < 0) { // lettre ratée => +1 erreur errors++; } score += delta; if (score < 0) score = 0; } }