Programmare in java: 3. Bingo

Programmare in java: 3. Bingo

Introduzione

    Nelle case del Sud Italia, durante le feste di Natale, il suono dei numeri estratti dalla tombola scandiva le serate in famiglia. Era un gioco semplice, ma capace di riunire generazioni diverse attorno alla stessa attesa: il numero chiamato, la risata, la vittoria condivisa. La tombola nacque nel XVIII secolo a Napoli, durante il regno di Carlo di Borbone. In particolare nel 1734, infatti, il gioco del lotto era già molto diffuso ma anche discusso e contrastato: da un lato il governo borbonico voleva legalizzarlo per regolare le scommesse e incassare tasse, dall’altro il clero, invece, si opponeva, sostenendo che distraesse i fedeli dalle preghiere durante le festività natalizie.

Per placare le tensioni, il re decise di sospendere le estrazioni del lotto durante il periodo di Natale. Ma i napoletani, ingegnosi com’erano, inventarono una versione domestica del gioco: al posto delle puntate di denaro, si giocava in casa con fagioli o ceci secchi come segnalini, cartelle disegnate a mano, e un panariello — il cestino in vimini — per estrarre i numeri. Così nacque la tombola napoletana, che da allora divenne una tradizione natalizia familiare e un momento di condivisione più che di gioco d’azzardo.

Nei decenni successivi, la tombola si diffuse in tutta Italia, e nel Novecento, con la migrazione italiana verso gli Stati Uniti, ispirò la nascita del bingo moderno, regolamentato come gioco pubblico nel 1929 e poi esportato in tutto il mondo. Da quel retaggio popolare è nato il bingo, che ne conserva la struttura e lo spirito: estrarre numeri, segnare caselle, attendere la combinazione vincente. Ma dietro la semplicità del gesto si nasconde una logica di ordine e caso, una danza tra probabilità e casualità, tra algoritmo e fortuna.

Oggi, nel linguaggio della programmazione, il bingo diventa un esercizio di logica e astrazione: generare cartelle, gestire estrazioni, verificare vincite. Come nella tombola di un tempo, anche qui ogni numero è parte di un sistema, e ogni estrazione è un passo verso la soluzione.

Scrivere un programma per il bingo significa tradurre un rituale collettivo in linguaggio formale, restituendo alla macchina la capacità di giocare, contare, e in un certo senso — di “partecipare”.

Risultato (estratto dell’esecuzione)

    Il programma è stato sviluppato in Java con un approccio orientato alla chiarezza logica e alla modularità.

Ogni componente — estrazione dei numeri, generazione delle cartelle, verifica delle vincite — è stato progettato come parte autonoma di un sistema coerente, in cui la comunicazione tra le classi mantiene il flusso di gioco trasparente e controllato.

L’uso estensivo delle Java Stream API ha permesso di rappresentare in modo conciso le operazioni di filtraggio, generazione e mappatura dei dati, riducendo la complessità sintattica e migliorando la leggibilità.

Attraverso flussi e lambda expressions, il codice realizza la gestione delle estrazioni e la costruzione delle cartelle come processi funzionali, più vicini al linguaggio matematico che a quello procedurale.

L’obiettivo è stato quello di simulare la dinamica reale del bingo, ma con una struttura completamente automatizzata: il programma crea le cartelle, estrae i numeri, registra le vincite e rigenera l’intero set per una nuova partita senza intervento esterno.

Ogni esecuzione è autonoma e ripetibile, garantendo un equilibrio tra casualità controllata e riproducibilità logica.

Questo approccio mette in luce il carattere computazionale e simbolico del gioco: un intreccio tra alea e struttura, dove il caso incontra la regola e la macchina diventa parte del rito del gioco stesso.
 


Link utili

▶ Esegui il programma su Replit:

  1. Clicca sul link Apri su Replit per accedere al progetto.
  2. Se non hai un account Replit, registrati gratuitamente oppure accedi con Google/GitHub.
  3. Una volta nel progetto, premi “Run” per avviare l’esecuzione.
  4. Puoi consultare il file sorgente e, se desideri, scaricarlo o copiarlo dal pannello di codice a sinistra.


▶ Requisiti:

  1. Java JDK 8 o superiore installato (verifica con java -version).
  2. Console o IDE compatibile con UTF-8.


▶ Scarica la versione portatile del codice:

  1. Effettua queste tre semplici operazioni:
    • Clicca sul link Scarica File per scaricare il file Main.txt, che contiene il codice sorgente completo in formato .txt.
    • Clicca sul link Scarica File per scaricare il file Bingo.txt, che contiene il codice sorgente completo in formato .txt.
    • Clicca sul link Scarica File per scaricare il file CartellaUtente.txt, che contiene il codice sorgente completo in formato .txt.
  2. Rinomina i file cambiando l’estensione da .txt a .java.
  3. A. Se usi un IDE Java (VS Code, IntelliJ, NetBeans, Eclipse), crea un nuovo progetto java vuoto e aggiungi il package bingo; poi importa i tre file e avvia la classe Main.java come Java Application.
  1. B. Se invece vuoi eseguirlo senza IDE, crea una cartella chiamata bingo e inserisci al suo interno i tre file .java.
  2. B. Apri il terminale nella cartella che contiene bingo/ e usa uno dei comandi seguenti:

macOS / Linux :

mkdir -p out && javac -encoding UTF-8 -d out $(find . -name "*.java") && java -Dfile.encoding=UTF-8 -cp out bingo.Main


Windows (PowerShell):

mkdir out; javac -encoding UTF-8 -d out (Get-ChildItem -Recurse -Filter *.java).FullName; java -Dfile.encoding=UTF-8 -cp out bingo.Main


Windows (Prompt dei comandi):
esegui i comandi uno alla volta (senza ; tra di essi). Esempio:

mkdir out
javac -encoding UTF-8 -d out *.java
java -Dfile.encoding=UTF-8 -cp out bingo.Main


▶ Utilizzo:

Dopo l’avvio, la console ti guida passo-passo:

  1. inserisci il numero dei giocatori,
  2. il programma genera e stampa ogni cartella in un file .txt (e le salva in src/bingo/cartelle_utenti/ – su Replit in src/bingo/cartelle_utenti/),
  3. premi INVIO per ogni estrazione: viene mostrato il numero estratto e il gioco si mette in pausa per permettere ai partecipanti di segnare tale numero sulla propria cartella,
  4. a ogni vincita viene stampato un resoconto (numeri estratti fino a quel momento e la cartella del vincitore).

Per una nuova partita ti basta rilanciare il programma: le cartelle utente vengono cancellate e rigenerate automaticamente all’inizio.

replit.com
A

Bingo

@alessioseveri27


Codice

    L’architettura del programma è organizzata in più classi distinte, ognuna con un ruolo specifico nella logica del gioco:

Bingo gestisce l’estrazione dei numeri e il controllo delle vincite, e CartellaUtente rappresenta la struttura dati delle singole cartelle e del sacchetto. Nella classe Main, il metodo statico main() coordina l’intero flusso di esecuzione, mantenendo il codice principale essenziale e leggibile, mentre gli altri metodi si occupano della scrittura delle cartelle in file .txt, garantendo portabilità e facilità di distribuzione.

Il cuore del progetto è tuttavia la classe Bingo, dove la logica di estrazione e verifica è implementata in modo indipendente, così da poter essere riutilizzata o estesa facilmente.

Il gioco è pensato per un utilizzo multiplayer, con la generazione automatica di cartelle salvate in formato .txt, rendendolo portabile e facilmente condivisibile tra diversi utenti.

La separazione delle responsabilità e la modularità del codice rispecchiano un principio di chiarezza logica: ogni classe opera come parte di un sistema coerente, dove il flusso del gioco si mantiene trasparente, leggibile e adattabile.

Bingo package bingo
Main.java
Bingo.java
CartellaUtente.java
1/*
2 Gioco del Bingo
3
4 Package: bingo
5
6 Descrizione:
7 Simulatore completo del gioco del Bingo.
8 Il programma gestisce automaticamente la creazione delle cartelle
9 dei giocatori, l’estrazione dei numeri in tempo reale (“live”) e
10 il salvataggio delle cartelle su file di testo.
11
12 Include funzionalità per la generazione, scelta del numero di player,
13 stampa e archiviazione delle cartelle, con possibilità di pausa tra
14 le estrazioni per rendere l’esperienza di gioco più realistica.
15
16 Ad ogni vincita viene mostrato un resoconto dettagliato
17 dei numeri estratti fino a quel momento.
18
19
20 Autore: Alessio Severi
21 Licenza: MIT License
22
23 MIT License
24
25 Copyright (c) 2025 Alessio Severi
26
27 Permission is hereby granted, free of charge, to any person obtaining a copy
28 of this software and associated documentation files (the "Software"), to deal
29 in the Software without restriction, including without limitation the rights
30 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31 copies of the Software, and to permit persons to whom the Software is
32 furnished to do so, subject to the following conditions:
33
34 The above copyright notice and this permission notice shall be included in all
35 copies or substantial portions of the Software.
36
37 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
43 SOFTWARE.
44
45*/
46
47
48package bingo;
49
50import java.io.File;
51import java.io.IOException;
52import java.nio.charset.StandardCharsets;
53import java.nio.file.Files;
54import java.nio.file.Path;
55import java.util.InputMismatchException;
56import java.util.Map;
57import java.util.Scanner;
58
59
60
61public class Main {
62
63
64
65 public static void main(String[] args) {
66
67
68 Bingo go= new Bingo();
69
70 System.out.println("\n\nGioco del Bingo\n\n");
71
72
73
74 try(Scanner sc= new Scanner(System.in)){
75
76 System.out.print("Inserisci il numero dei partecipanti: ");
77
78 try {
79
80
81 final int N_PLAYERS= sc.nextInt();
82
83 // consumo newline dopo nextInt()
84 sc.nextLine();
85
86
87 if (N_PLAYERS < 3) throw new IllegalArgumentException("Il numero dei partecipanti deve essere almeno 3. ");
88
89 System.out.println();
90
91
92 for (int i = 0; i < N_PLAYERS; i++) go.creaCartella();
93
94
95
96 printSaveCartelle(go, createFolder(new File("bingo/cartelle_utenti")));
97
98
99 System.out.println("\nPremi INVIO per iniziare le estrazioni…");
100 sc.nextLine();
101
102
103 // Ciclo di estrazione con pausa
104 while (go.estraiNumero()) {
105 System.out.println("\nPremi INVIO per estrarre il prossimo numero…");
106 sc.nextLine();
107 }
108
109
110
111 // opzionale: stampa contenuto del sacchetto
112 go.stampaCartella(go.getID_SACCHETTO(), "\n\nIl contenuto del sacchetto iniziale è:\n");
113
114
115
116
117 } catch (InputMismatchException e) {
118
119 System.out.println("\n\nNumero dei partecipanti errato, tentativo di giocare al Bingo fallito.\n");
120
121 }
122 catch (IllegalArgumentException e) {
123
124 System.out.println("\n\n" + e.getMessage() + "Tentativo di giocare al Bingo fallito.\n");
125
126 }
127
128 }
129
130
131 System.out.println();
132
133 }
134
135
136
137 private static Path createFolder(File file) {
138
139
140 if (file.exists()) {
141
142 File[] files = file.listFiles();
143 if (files != null) {
144 for (File f : files) {
145 f.delete(); // cancella contenuti
146 }
147 }
148 file.delete();
149 }
150
151
152 try {
153 Path dir = Path.of("bingo/cartelle_utenti");
154 Files.createDirectories(dir);
155
156 return dir;
157
158 } catch (IOException e) {
159 System.out.println(e.getMessage());
160 }
161 return null;
162
163
164
165 }
166
167
168
169 private static void printSaveCartelle(Bingo go, Path dir){
170
171 // Stampa e salvataggio delle cartelle dei giocatori
172 for (Map.Entry<Integer, CartellaUtente> entry : go.getUtenti().entrySet()) {
173
174 int id = entry.getKey();
175 if (id == go.getID_SACCHETTO()) continue; // salta il sacchetto
176
177
178 go.stampaCartella(id, "\n\nCartella del giocatore " + id + ":\n");
179
180
181 CartellaUtente c = entry.getValue();
182 StringBuilder sb = new StringBuilder();
183
184
185 for (Integer[] riga : c.cartella()) {
186
187 for (Integer elem : riga)
188
189 sb.append(String.format("%6d", elem));
190
191 sb.append("\n");
192 }
193
194
195 try {
196
197 // Costruisce il percorso completo del file dentro quella cartella
198 Path file = dir.resolve("cartella_giocatore_" + id + ".txt");
199
200 // Scrittura del contenuto
201 Files.writeString(file, sb.toString(), StandardCharsets.UTF_8);
202
203 System.out.println("Salvataggio cartella in: " + file.toAbsolutePath());
204
205
206 } catch (IOException e) {
207 System.out.println("Errore salvataggio cartella giocatore " + id + ": " + e.getMessage());
208 }
209 }
210
211
212 }
213
214
215}
216
1
2// © 2025 Alessio Severi — vedi licenza nel file Main.java
3
4package bingo;
5
6
7import java.util.Arrays;
8import java.util.Collections;
9import java.util.LinkedHashMap;
10import java.util.List;
11import java.util.Map;
12import java.util.stream.Collectors;
13import java.util.stream.IntStream;
14
15
16public class Bingo {
17
18
19 final int ID_SACCHETTO = 0; // indice 0
20 final int tot_numeri= 0; // indice 0
21
22 private int id_utente= ID_SACCHETTO;
23
24 // utenti: utente sacchetto e concorrenti
25 private final Map<Integer, CartellaUtente> utenti = new LinkedHashMap<>();
26
27
28 // premi
29 private static final Map<Integer, String> premi = Map.of(
30 2, "Ambo",
31 3, "Terno",
32 4, "Quaterna",
33 5, "Cinquina",
34 6, "Bingo"
35
36 );
37
38 int current_premio= 2;
39
40 private int RIGHE, COLONNE;
41
42
43 {
44 RIGHE= 18;
45 COLONNE= 5;
46
47 creaCartella();
48
49
50 RIGHE= 3;
51 COLONNE= 5;
52
53 }
54
55
56
57
58 public void creaCartella(){
59
60
61 // stream.toList() restituisce un’istanza di java.util.ImmutableCollections,
62 // che non supporta operazioni come shuffle() o swap(): Collections.swap(lista, i, j);
63
64 // opzione 1: List<Integer> numeri = new ArrayList<>(IntStream.range(1, 91).boxed().toList());
65 // opzione 2: List<Integer> numeri = IntStream.range(1, 91).boxed().collect(Collectors.toList());
66 // opzione 3: List<Integer> numeri = IntStream.range(1, 91).boxed().collect(Collectors.toCollection(ArrayList::new));
67 List<Integer> numeri = IntStream.range(1, 91).boxed().collect(Collectors.toList());
68
69 Collections.shuffle(numeri);
70
71 Integer[][] value = IntStream.range(0, RIGHE)
72 .mapToObj(i -> numeri.subList(i * COLONNE, (i + 1) * COLONNE).toArray(Integer[]::new))
73 .toArray(Integer[][]::new);
74
75
76
77
78 // dati utente del sacchetto (o sacchetto virtuale) e utenti: in un campo la cartella o sacchetto
79 // e in un altro il conteggio iniziale a 0
80 // dei numeri coperti per ogni riga (corrispondente ad ogni elento dell'array), per gli utenti,
81 // e per il sacchetto i numeri totali usciti (il conteggio) all'indice 0 dell'array
82 CartellaUtente cartella_utente = new CartellaUtente(value, 0);
83
84 // catalogati nella mappa
85 utenti.put(id_utente++, cartella_utente);
86
87 }
88
89 public Map<Integer, CartellaUtente> getUtenti() {
90 return utenti;
91 }
92
93 public boolean estraiNumero(){
94
95
96 // numeri del sacchetto terminati senza nessun Bingo
97 if (utenti.get(ID_SACCHETTO).getNumeri_count()[tot_numeri] == 90) {
98
99 System.out.println("\n\nSono stati estratti tutti i numeri, ma nessun concorrente ha fatto Bingo!");
100
101 return false;
102 }
103
104
105 // inizio estrazione numero e aggiornamento sacchetto
106 // sacchetto: numero corrente che è estratto dal sacchetto (dalla matrice): riga 97
107 // contatore del numero delle estrazioni dei numeri dal sacchetto: riga 100
108 int i= utenti.get(ID_SACCHETTO).getNumeri_count()[tot_numeri] / COLONNE;
109 int j= utenti.get(ID_SACCHETTO).getNumeri_count()[tot_numeri] % COLONNE;
110
111 Integer numb_est= utenti.get(ID_SACCHETTO).cartella()[i][j];
112
113 System.out.println("\n\n Il numero estratto è: " + numb_est);
114
115
116 utenti.get(ID_SACCHETTO).setNumeri_count(tot_numeri, utenti.get(ID_SACCHETTO).getNumeri_count()[tot_numeri] + 1);
117
118
119 // controllo e aggiornamento cartella per ogni utente e assegnazione premi
120 // con aggiornamenti annessi
121 int index;
122 for (int k = 1; k < utenti.size(); k++) {
123
124 // controllo cartella
125 // NB: le variabili catturate da una lambda devono essere final o effectively final
126 // userIndex è final, mentre numb_est è effectively final
127 final int userIndex = k;
128
129 index = IntStream.range(0, RIGHE * COLONNE)
130 .filter(pos -> {
131
132 int r = pos / COLONNE;
133 int c = pos % COLONNE;
134 return utenti.get(userIndex).cartella()[r][c].equals(numb_est);
135
136 })
137 .findAny()
138 .orElse(-1); // se -1, il numero non è stato trovato
139
140
141 // aggiornamento cartella
142 if(index != –1){
143
144 index= index / COLONNE; // riga i-esima
145
146 utenti.get(k).setNumeri_count(index, (utenti.get(k).getNumeri_count()[index]) + 1);
147
148
149
150 // controllo assegnazione premi
151 if(current_premio == Arrays.stream(utenti.get(k).getNumeri_count()).reduce(0, Integer::max)){
152
153 System.out.println("\n\nIl concorrente " + k + " ha fatto " + premi.get(current_premio) + " alla riga " + (index + 1));
154 stampaCartella(k, "\nLa cartella del concorrente è:\n");
155 stampaNumEstratti();
156
157 current_premio++;
158
159 }
160 else if(Arrays.stream(utenti.get(k).getNumeri_count()).allMatch( l -> l == 5)){
161
162 System.out.println("\n\nIl concorrente " + k + " ha fatto " + premi.get(current_premio) + " e ha vinto!");
163 stampaCartella(k, "\nLa cartella del concorrente è:\n");
164 stampaNumEstratti();
165
166 return false;
167 }
168
169
170 }
171
172 }
173
174
175 return true;
176 }
177
178
179
180 public int getID_SACCHETTO() {
181 return ID_SACCHETTO;
182 }
183
184
185 public void stampaCartella(int k, String message){
186
187 System.out.println(message);
188
189 for(Integer[] riga : utenti.get(k).cartella()){
190
191 for(Integer ele : riga)
192
193 System.out.print(String.format("%6d", ele));
194
195 System.out.println();
196
197
198 }
199
200 System.out.println();
201
202 }
203
204
205
206 public void stampaNumEstratti(){
207
208
209 System.out.println("\nElenco dei " + utenti.get(ID_SACCHETTO).getNumeri_count()[tot_numeri] + " numeri estratti dal sacchetto:\n");
210
211 Arrays.stream(utenti.get(ID_SACCHETTO).cartella()).flatMap(Arrays::stream).limit(utenti.get(ID_SACCHETTO).getNumeri_count()[tot_numeri])
212 .forEach(n -> System.out.print(n + " "));
213
214
215 System.out.println("\n");
216
217 }
218
219
220}
221
222
223
224
225
226
227
228
1
2// © 2025 Alessio Severi — vedi licenza nel file Main.java
3
4package bingo;
5
6import java.util.Arrays;
7
8public class CartellaUtente {
9
10
11 private final int RIGHE= 3;
12
13
14 private final Integer[][] cartella;
15 private final int[] numeri_count= new int[RIGHE];
16
17
18 public CartellaUtente(Integer[][] cartella, int numeri_count) {
19
20 this.cartella = cartella;
21
22 Arrays.fill(this.numeri_count, numeri_count);
23 /*
24 for(int i=0; i < this.numeri_count.length; i++)
25 this.numeri_count[i] = numeri_count;
26 */
27
28 }
29
30 public Integer[][] cartella() {
31 return cartella;
32 }
33
34 public int[] getNumeri_count() {
35 return numeri_count;
36 }
37
38 public void setNumeri_count(int index, Integer n) {
39 this.numeri_count[index] = n;
40 }
41}