// © 2025 Alessio Severi — vedi licenza nel file Main.java package impiccato; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner; /** * Rappresenta il gioco dell'impiccato. * Gestisce lo stato della partita e coordina il flusso della partita, * delegando la lettura della parola segreta e la localizzazione dei messaggi * alle interfacce {@link IOImpiccato} e {@link ItalianLanguage}. */ public class ImpiccatoGame implements IOImpiccato, ItalianLanguage { /** * Numero massimo di errori consentiti prima che la partita venga persa. */ private static final int MAX_COUNT = 8; /** * Collezione dei caratteri inseriti correttamente dal giocatore * durante la composizione della parola segreta. */ private final List charIn = new ArrayList<>(Arrays.asList('\000')); /** * Collezione dei caratteri inseriti dal giocatore * durante la composizione della parola segreta. */ private final List charInU = new ArrayList<>(); /** * Conteggio dei tentativi effettuati dal giocatore. */ private int count = 0; static { // saluto di benvenuto nella lingua della classe System.out.println("\n\n" + Message.WELCOME.text() + "\n\n"); } @Override /** * Estrae una parola casuale dal file indicato e la trasforma in * una lista di caratteri da utilizzare come parola segreta. * * @param path percorso del file contenente l'elenco delle parole. * @param msg1 messaggio da mostrare in caso di errore di lettura. * @return lista di caratteri che rappresenta la parola segreta. */ public List estraiParola(Path path, String msg1) { String parolaScelta = (String)IOImpiccato.super.estraiParola(path, msg1); System.out.print(Message.GUESS_PROMPT.text() + "\n" ); return parolaScelta.chars().mapToObj(i -> (char)i).toList(); } /** * Gestisce l'inserimento di una lettera da parte del giocatore. * Controlla la validità dell'input, aggiorna il numero di tentativi * rimanenti e registra le lettere corrette e inserite nelle collezioni interne. * * @param sc scanner utilizzato per leggere l'input da console. * @param sacchetto lista delle lettere ancora disponibili. * @param parola lista di caratteri che rappresenta la parola segreta. * @return {@code true} se l'input è valido e la partita può proseguire, * {@code false} in caso di errore bloccante sull'input. */ public boolean estraiLettera(Scanner sc, List sacchetto, List parola) { // estrazione lettera e sistemazione sacchetto int index; String str = Message.CHOICE_PROMPT.text(); String str2 = Message.LETTER_CHOICE.text(); System.out.println("\n\n" + str); char car = Character.toLowerCase(sc.next().charAt(0)); sc.nextLine(); System.out.println("\033[1A\r"+ "\033[K"); System.out.println(str2 + "'" + Character.toUpperCase(car) + "'\n"); if((index = sacchetto.indexOf(car)) == -1) { // '\033' carattere di esc if(car == '\033'){ System.out.println("\033[2A\r"+ str2.replace(Message.LETTER.text(), Message.CHARACTER.text()) + "'ESC'"); System.out.println("\n\n" + Message.EXIT.text() + "\n\n"); System.exit(0); } else if(Character.isAlphabetic(car)) System.out.println(Message.NOTICE_LETTER.text() + ": " + charInU); else { System.out.println("\033[2A\r"+ str2.replace(Message.LETTER.text(), Message.CHARACTER.text()) + "'" + car + "'\n"); System.out.println(Message.WARNING_CHAR.text()); } return true; } charInU.add(Character.toUpperCase(car)); sacchetto.remove(index); // controllo corrispondenze tra la parola e la lettera if(parola.contains(car)){ System.out.println(Message.WIN_LETTER.text()); charIn.add(car); } else{ String a= ((++count == MAX_COUNT - 1) ? Message.REMAIN_ONE.text() : Message.REMAIN_MANY.text()); String b= ((count == MAX_COUNT - 1) ? Message.ATTEMPT_ONE.text() : Message.ATTEMPTS_MANY.text()); System.out.println(Message.LOSE_LETTER.text() + a + Message.STILL.text() + (MAX_COUNT - count) + b); IOImpiccato.printImpiccato(count); } return false; } /** * Stampa a video lo stato corrente della parola da indovinare, * mostrando le lettere già individuate e mascherando le restanti. * * Inoltre mostra un riepilogo delle lettere precedentemente scelte. * * @param parola lista di caratteri che rappresenta la parola segreta. * @return {@code true} se la parola è stata indovinata completamente, * {@code false} altrimenti. */ public boolean componiParola(List parola) { boolean flag = true; System.out.print("\n" + Message.SECRET_WORD.text()); for (int i = 0; i < parola.size(); i++){ for (int j = 0; j < charIn.size(); j++){ if(parola.get(i).equals(charIn.get(j))){ System.out.print(Character.toUpperCase(charIn.get(j))); break; } else if(j == charIn.size() - 1){ System.out.print("_"); if(flag) flag = false; } } System.out.print(" "); } System.out.print("\n\n" + Message.USER_LETTERS.text() + charInU); return flag; } /** * Valuta la condizione di vittoria o sconfitta della partita in base * allo stato corrente della parola e al numero di tentativi utilizzati. * * @param flag indica se la parola è stata indovinata. * @param parola lista di caratteri che rappresenta la parola segreta. */ public void controlWinLos(boolean flag, List parola) { if(count == MAX_COUNT || flag){ if(count == MAX_COUNT){ System.out.println("\033[A\033[F" + Message.USER_LETTERS.text() + charInU); System.out.print("\n" + Message.LOSE_GAME.text() + "\033[K"); parola.stream().map(Character::toUpperCase).forEach(System.out::print); System.out.println(); } else System.out.println("\n\n" + Message.WIN_GAME.text()); System.out.println("\n\n" + Message.EXIT.text() + "\n\n"); } } /** * Avvia una nuova partita dell'impiccato. * Inizializza il sacchetto delle lettere, estrae la parola segreta * e gestisce il ciclo principale di gioco finché non si verifica * una condizione di vittoria o di sconfitta. * * @param sc scanner utilizzato per leggere l'input da console. */ public void play(Scanner sc) { boolean flag; List sacchetto = riempiSacchetto(); List parola = estraiParola(pathFile(), Message.ERROR_FILE.text()); componiParola(parola); while(true){ if(!estraiLettera(sc, sacchetto, parola)){ flag = componiParola(parola); controlWinLos(flag, parola); if ((count == MAX_COUNT) || (flag)) break; } } } }