{*********************************************************************************************
PROGRAM NAME : funghi_nascosti
PROGRAMMERS : Massimo Zappino
DESCRIPTION : Programma in grado di riprodurre il gioco funghi nascosti il cui scopo è quello di
riuscire ad individuare tutti i funghi senza calpestarli. E' anche possibile salvare
una partita per riprenderla in futuro ed è possibile salvare una partita giocata da rivedere
DATE : Iniziato il 16/06/2003;
Terminato il 25/06/2003.
COMPILE : Irie Pascal for Windows
SYSTEM : Windows XP
BUGS : il programma va in crash se i file aperti in lettura non esistono
*********************************************************************************************}
program funghi_nascosti (f,input,output);
const
max_colonne=20; {valore massimo delle colonne della matrice}
max_righe=20; {valore massimo delle righe della matrice}
num_righe=9; {valore di default per l'altezza della matrice}
num_colonne=9; {valore di default per la larghezza della matrice}
type
matrice_campo=array[1..max_righe,1..max_colonne] of char; {definisce il tipo della matrice di gioco}
lista=^nodo;
nodo=record {dichiarazione della lista}
val_x:char;
val_y:char;
next:lista;
end;
var
numero_menu: char; {variabile usata per memorizzare la scelta del menu}
matrice: matrice_campo; {matrice contenente i valori del gioco}
matricegioco: matrice_campo; {matrice contenente i valori del gioco}
p,head:lista; {puntatori della lista contenente le coordinate}
righe,colonne,funghi:integer; {valori globali delle righe, colonne e funghi}
f: text; {variabile utilizzata per il salvataggio su file delle partite}
{**************************************************************************************************************************}
{PROCEDURE PULISCI_SCHERMO
SCOPO:cancella tutti i dati presenti a video
EFFETTI COLLATERALI:nessuno}
procedure pulisci_schermo;
begin
clrscr;
end;
{**************************************************************************************************************************}
{PROCEDURE STAMPA_VALORI_GIOCO
SCOPO: stampa a video l'intestazione della partita in corso
EFFETTI COLLATERALI:
CALLED BY: nuova_partita, avvia_gioco
PARAMETERS: }
procedure stampa_valori_gioco;
begin {stampa_valori_gioco}
writeln;
writeln("Righe: ",righe:1," Colonne: ",colonne:1," Funghi: ",funghi:1);
writeln;
end; {stampa_valori_gioco}
{********************************************************************************************}
{PROCEDURE DISEGNA_MATRICE
SCOPO: stampare a video la matrice passata alla procedura
EFFETTI COLLATERALI:
CALLED BY: avvia_gioco,nuova_partita
PARAMETERS: matrice_passata = matrice da stampare a video }
procedure disegna_matrice(matrice_passata:matrice_campo);
var
i,j : integer;
c: char;
begin {disegna_matrice}
c:=pred("a");
write(" ");
for i:=1 to colonne do begin {scrive la prima riga di lettere}
write(succ(c));
c:=succ(c);
end;
writeln;
c:=pred("a");
for j:=1 to righe do begin
write(succ(c)); {scrive la prima colonna di lettere}
c:=succ(c);
for i:=1 to colonne do begin
write(matrice_passata[i,j]);
end;
writeln;
end;
end; {disegna_matrice}
{********************************************************************************************}
{PROCEDURE INIZIALIZZA_MATRICE_GIOCO
SCOPO: inserisce un asterisco * per ogni cella della matrice gioco
EFFETTI COLLATERALI:
CALLED BY: nuova_partita,carica_partita
PARAMETERS: }
procedure inizializza_matrice_gioco;
var
i,j:integer;
begin {inizializza_matrice_gioco}
for i:=1 to max_righe do begin
for j:=1 to max_colonne do
matricegioco[i,j]:="*";
end;
end; {inizializza_matrice_gioco}
{********************************************************************************************}
{PROCEDURE AVVIA_GIOCO
SCOPO: avviare la partita prendendo come input le coordinate e stampando a video la matrice
EFFETTI COLLATERALI:
CALLED BY: nuova_partita,carica_partita
PARAMETERS: ripristino_partita,rivedi = booleani che indicano il tipo di partita }
procedure avvia_gioco(ripristino_partita,rivedi:boolean);
var
x,y:char; {valori letterali corrispondenti alle coordinate}
i,j,mosse:integer;
vinto,perso,soluzione,termina:boolean;
c:char; {selettore menu}
{************************************************}
{PROCEDURE SALVA_PARTITA
SCOPO: salvare su file la partita in corso (rivedi o ripristina)
EFFETTI COLLATERALI:
CALLED BY: avvia_gioco
PARAMETERS: tipo = identifica se è "rivedi" o "ripristina"}
procedure salva_partita(tipo:string);
var
nomefile: string; {variabile che conterrà il nome del file da salvare}
i,j:integer ;
begin {salva_partita}
clrscr;
writeln("Salvataggio partita");
writeln;
writeln;
p:=head;
repeat
write("Scrivi il nome del file da salvare: ");
readln(nomefile);
until nomefile<>"";
rewrite(f,nomefile);
writeln(f,tipo);
writeln(f,"#");
for i:=1 to righe do begin
for j:=1 to colonne do
write(f, matrice[j,i]);
writeln(f);
end;
writeln(f,"#");
while p^.next<>nil do begin
writeln(f,p^.val_x,p^.val_y);
p:=p^.next;
end;
writeln;
writeln("Il file '",nomefile,"' e' stato salvato correttamente.");
writeln("Premere INVIO per continuare...");
rewrite(f,"temp_file"); {viene fatto puntare f ad un file temporaneo per far si che il file da salvare venga chiuso
e sia quindi possibile scrivere i dati al suo interno}
readln;
end {salva_partita};
{************************************************}
{FUNCTION CONTA_FOGLIE_RIMASTE
SCOPO: restituire il numero di foglie rimaste nella matrice gioco
EFFETTI COLLATERALI:
CALLED BY: avvia_gioco
PARAMETERS: matrice_passata = matrice gioco}
function conta_foglie_rimaste(matrice_passata:matrice_campo):integer;
var
i,j,contatore:integer;
begin {conta_foglie_rimaste}
contatore:=0;
for i:=1 to righe do
for j:=1 to colonne do
if matrice_passata[i,j]="*" then
contatore:=contatore+1;
conta_foglie_rimaste:=contatore;
end; {conta_foglie_rimaste}
{************************************************}
{FUNCTION CONTROLLA_INPUT_COORDINATE
SCOPO: restituire true se le coordinate inserite sono corrette
EFFETTI COLLATERALI:
CALLED BY: avvia_gioco
PARAMETERS: i = carattere inserito, parametro = intero che identifica la grandezza massima di righa o colonna }
function controlla_input_coordinate(i:char;parametro:integer):boolean;
begin {controlla_input_coordinate}
if (i>="a") and (i<=(chr(ord(parametro)+96))) or (i="0") then
begin
controlla_input_coordinate:=true
end
else
controlla_input_coordinate:=false;
end; {controlla_input_coordinate}
{************************************************}
{PROCEDURE APRI_MENU_RAPIDO
SCOPO: visualizza sullo schermo il menu rapido durante la partita
EFFETTI COLLATERALI:
CALLED BY: avvia_gioco
PARAMETERS: }
procedure apri_menu_rapido;
var
c:char;
begin {apri_menu_rapido}
repeat
pulisci_schermo;
writeln;
writeln("*** Menu Rapido ***");
writeln;
writeln(" 1 Salva Partita");
writeln(" 2 Mostra soluzione");
writeln(" 3 Termina partita");
writeln(" 0 Ritorna alla Partita");
writeln;
write("Opera una scelta: ");
readln(c);
until (c="1") or (c="2") or (c="3") or (c="0");
if c="3" then termina:=true;
if c="2" then begin
soluzione:=true;
termina:=false;
end;
if c="1" then begin
p^.next:=nil;
salva_partita("riprendi")
end;
end; {apri_menu_rapido}
{************************************************}
{PROCEDURE SCOPRI_CASELLE
SCOPO: scopre le celle vuote adiacenti tra loro e quelle confinanti conteneti un numero
tramite la ricorsione della procedura
EFFETTI COLLATERALI:
CALLED BY: avvia_gioco;
PARAMETERS: i,j= coordinate che indicano la cella in questione}
procedure scopri_caselle(i,j:integer);
var
x,x1,x2,y,y1,y2: integer;
begin {scopri_caselle}
matricegioco[i,j]:=" ";
if i<>1 then x1:=i-1 else x1:=i;
if i<>colonne then x2:=i+1 else x2:=i;
if j<>1 then y1:=j-1 else y1:=j;
if j<>righe then y2:=j+1 else y2:=j;
for x:=x1 to x2 do begin
for y:=y1 to y2 do
if matricegioco[x,y]<>" " then
begin
if matrice[x,y]<>" " then
matricegioco[x,y]:=matrice[x,y]
else
scopri_caselle(x,y)
end;
end;
end; {scopri_caselle}
{************************************************}
{PROCEDURE ESEGUI_MOSSE_SALVATE
SCOPO: esegue in automatico le mosse di una partita salvata lette dalla lista
EFFETTI COLLATERALI:
CALLED BY: avvia_gioco
PARAMETERS: ripristino_partita = parametro che indica se la partita era salvata}
procedure esegui_mosse_salvate(var ripristino_partita:boolean);
var
j,i:integer;
x,y:char;
begin {esegui_mosse_salvate}
p:=head;
while p^.next<>nil do begin
x:=p^.val_x;
y:=p^.val_y;
i:=ord(x)-96; {trasforma la lettera inserita nel numero della riga corrispondente}
j:=ord(y)-96; {trasforma la lettera inserita nel numero della colonna corrispondente}
if matricegioco[i,j]<>"*" then begin
writeln("La cella che hai selezionata e' già scoperta.");
readln;
end
else
begin
if matrice[i,j]=" " then
begin
scopri_caselle(i,j);
mosse:=mosse+1
end
else
begin
matricegioco[i,j]:=matrice[i,j];
mosse:=mosse+1;
end;
end;
p:=p^.next;
end;
ripristino_partita:=false;
{ora il puntatore della lista punta all'ultima posizione cioè alla coda della lista}
end; {esegui_mosse_salvate}
{************************************************}
{PROCEDURE CANCELLA_LISTA
SCOPO: esegue in automatico le mosse di una partita salvata lette dalla lista
EFFETTI COLLATERALI:
CALLED BY: avvia_gioco
PARAMETERS: }
procedure cancella_lista;
var
q:lista;
begin {cancella_lista}
p:=head;
while p<>nil do begin
q:=p^.next;
dispose(p);
p:=q;
end;
end; {cancella_lista}
{************************************************}
begin {avvia_gioco}
mosse:=0;
vinto:=false;
perso:=false;
termina:=false;
soluzione:=false;
p:=head;
if ripristino_partita=true then {vengono eseguite le mosse precedentemente salvate nella lista}
esegui_mosse_salvate(ripristino_partita);
while (perso=false) and (vinto=false) and (termina=false) and (soluzione=false) do begin;
pulisci_schermo;
writeln("AVVIO PARTITA");
stampa_valori_gioco;
disegna_matrice(matricegioco);
writeln;
writeln("Numero mosse: ",mosse:1);
writeln;
if rivedi=false then begin {se la partita si sta giocando richiedi le coordinate da tastiera}
writeln("Inserisci le coordinate (Scrivi 0 per il Menu rapido): ");
repeat
write("Riga: ");
readln(y);
until controlla_input_coordinate(y,righe)=true;
repeat
write("Colonna: ");
readln(x);
until controlla_input_coordinate(x,colonne)=true;
end;
if rivedi=true then begin {se la partita è da rivedere legge le coordinate dalla lista}
x:=p^.val_x;
y:=p^.val_y;
p:=p^.next;
writeln("Riga: ",x:1);
writeln("Colonna: ",y:1);
readln; {attende l'input utente}
end;
if (x="0") or (y="0") then {apre il menu rapido se una coordinata è uguale a 0}
apri_menu_rapido
else
begin {Else}
i:=ord(x)-96; {trasforma la lettera inserita nel numero della riga corrispondente}
j:=ord(y)-96; {trasforma la lettera inserita nel numero della colonna corrispondente}
if matrice[i,j]="@" then
perso:=true
else
begin
if matricegioco[i,j]<>"*" then begin {fa ripetere l'inserimento se la cella è già scoperta}
writeln("La cella che hai selezionata e' già scoperta.");
readln;
end
else
begin
if matrice[i,j]=" " then {se la matrice dati è vuota allora chiama la procedura scopri_caselle}
begin
scopri_caselle(i,j);
mosse:=mosse+1
end
else
begin
matricegioco[i,j]:=matrice[i,j]; {se la matrice dati contiene un valore non vuoto e senza @ allora mostra la cella}
mosse:=mosse+1;
end;
end;
end;
if rivedi=false then begin
p^.val_x:=x; {salva nella prima variabile del record il valore di x}
p^.val_y:=y; {salva nella seconda variabile del record il valore di y}
new(p^.next); {crea una nuova variabile dinamica che conterrà le prossime coordinate}
p:=p^.next; {sposta il puntatore p alla nuova cella di memoria creata}
end;
if conta_foglie_rimaste(matricegioco)=funghi then {verifica che il numero di foglie rimaste e i funghi da scoprire siano uguali}
vinto:=true; {se è vero allora la partita è vinta}
end; {Else}
end {While};
p^.next:=nil; {termina la lista}
pulisci_schermo; {se la partita è terminata viene eseguita questa parte codice}
if termina=false then begin
writeln("AVVIO PARTITA");
stampa_valori_gioco;
disegna_matrice(matrice); {viene richiamata la matrice di codice contenente i valori di gioco}
writeln;
writeln("Numero mosse: ",mosse:1);
writeln;
if soluzione=false then
begin
if vinto=true then
writeln("HAI VINTO!")
else
writeln("HAI PERSO!");
repeat
write("Desideri salvare questa partita per visionarla in futuro? (S/N): ");
readln(c);
until (c="s") or (c="S") or (c="n") or (c="N");
case c of
"s","S": salva_partita("rivedi");
otherwise
end
end
else
begin
writeln("Hai deciso di mostrare la soluzione di questa partita.");
write("Partita terminata. Premi INVIO per tornare al menu principale");
readln;
end;
end
else
begin
write("Partita terminata. Premere INVIO per tornare al menu principale");
readln
end;
cancella_lista; {chiama la procedura che cancella la lista creata}
end; {avvia_gioco}
{********************************************************************************************}
{PROCEDURE NUOVA_PARTITA
SCOPO: avviare una nuova partita prendendo come parametri i valori della matrice di default
EFFETTI COLLATERALI:
CALLED BY: main
PARAMETERS: righe,colonne,funghi=parametri che indicano le generalità della matrice}
procedure nuova_partita(var righe,colonne,funghi:integer);
var
d:char; {variabile contenente la selezione del menu}
inizio_gioco: boolean; {vittoria: sarà true quando la partita sarà vinta}
mosse:integer;
{************************************************}
{PROCEDURE CAMBIA_PARAMETRI
SCOPO: modificare i parametri di gioco (righe, colonne e funghi)
EFFETTI COLLATERALI:
CALLED BY: nuova_partita
PARAMETERS: righe,colonne,funghi=parametri che indicano le generalità della matrice}
procedure cambia_parametri(var righe,colonne,funghi:integer);
begin
pulisci_schermo;
writeln("Cambia parametri di gioco");
writeln;
repeat
write("Inserisci la dimensione della larghezza (2-",(max_colonne):1,"): ");
readln(colonne);
until (colonne > 1) and (colonne < (max_colonne+1));
writeln("--------------------------------");
repeat
write("Inserisci la dimensione dell'altezza (2-",(max_righe):1,"): ");
readln(righe);
until (righe > 1) and (righe < (max_righe+1));
writeln("--------------------------------");
repeat
write("Inserisci il numero di funghi (2-",(righe*colonne-2):1,"): ");
readln(funghi);
until (funghi < (righe*colonne-1)) and (funghi > 1);
pulisci_schermo;
end; {cambia_parametri;}
{************************************************}
{PROCEDURE GENERA_MATRICE
SCOPO: creare la matrice contenente i funghi e il numero dei funghi contenuti nelle celle confinanti
EFFETTI COLLATERALI:
CALLED BY: nuova_partita
PARAMETERS: righe,colonne,funghi=parametri che indicano le generalità della matrice}
procedure genera_matrice (righe,colonne,funghi:integer);
var
x,x1,x2,y,y1,y2,i,j,num_funghi:integer;
begin {genera_matrice;}
for i:=1 to max_righe do begin {cancella tutti gli elementi della matrice}
for j:=1 to max_colonne do
matrice[i,j]:=" "
end;
randomize;
num_funghi:=0;
while num_funghi<>funghi do begin {inserisce un fungo in una cella casuale finchè non viene raggiunto il numero di funghi totale}
i:=random(colonne)+1;
j:=random(righe)+1;
if matrice[i,j]<>"@" then begin
matrice[i,j]:="@";
num_funghi:=num_funghi + 1;
end;
end;
for i:=1 to colonne do {aggiunge gli "1" attorno al fungo sommando eventualmente i numeri precedenti}
for j:=1 to righe do begin
if matrice[i,j]="@" then begin
if i<>1 then x1:=i-1 else x1:=i; {considera le celle perimetrali della matrice}
if i<>colonne then x2:=i+1 else x2:=i;
if j<>1 then y1:=j-1 else y1:=j;
if j<>righe then y2:=j+1 else y2:=j;
for x:=x1 to x2 do
for y:=y1 to y2 do
if matrice[x,y]<>"@" then
if matrice[x,y]=" " then
matrice[x,y]:="1"
else
matrice[x,y]:=chr(ord(matrice[x,y])+1);
end;
end;
end; {genera_matrice;}
{************************************************}
begin {nuova_partita}
inizio_gioco:=false;
while not inizio_gioco=true do begin
pulisci_schermo;
writeln("NUOVA PARTITA");
stampa_valori_gioco;
inizializza_matrice_gioco;
disegna_matrice(matricegioco);
writeln;
repeat
write("Desideri cambiare parametri di gioco (S/N)? ");
readln(d);
until (d="s") or (d="S") or (d="n") or (d="N");
if (d="s") or (d="S") then
cambia_parametri(righe,colonne,funghi)
else begin
inizio_gioco:=true;
genera_matrice(righe,colonne,funghi);
inizializza_matrice_gioco;
mosse:=0;
avvia_gioco(false,false);
end;
end;
end; {nuova_partita}
{************************************************}
{PROCEDURE CONTROLLA_LETTURA_FILE
SCOPO: controllare che il file che si sta leggendo è valido
EFFETTI COLLATERALI: se il file richiesto non esiste il programma da un errore; se non esiste nessun file da caricare il programma non permette il ritorno al menu principale
CALLED BY: carica_partita
PARAMETERS: f=variabile di testo contenente il file da leggere, x= stringa contenente una linea del file}
procedure controlla_lettura_file(var f:text; var x:string);
var
nomefile:string; {variabile contenente il nome del file}
begin {controlla_lettura_file}
repeat {viene ripetuto il ciclo finchè il file non contiene come prima riga la stringa "riprendi" o "rivedi"}
pulisci_schermo;
writeln("Aprertura file");
writeln;
write("Inserire il nome del file da caricare: ");
readln(nomefile);
reset(f,nomefile);
readln(f,x);
if (x<>"rivedi") and (x<>"riprendi") then begin {se x non è uguale a tipo mostra messaggio di errore}
writeln;
writeln("Il file che stai tentando di caricare non e' valido.");
readln;
end;
until (x="rivedi") or (x="riprendi");
readln(f);
writeln;
write("Il file caricato e' di tipo: ");
if x="rivedi" then
writeln("Rivedi Partita")
else
writeln("Riprendi Partita")
end; {controlla_lettura_file}
{************************************************}
{PROCEDURE CARICA_MATRICE
SCOPO: inserire i dati letti dal file nella matrice dati
EFFETTI COLLATERALI:
CALLED BY: carica_partita
PARAMETERS: f = variabile di testo contenente il file da leggere}
procedure carica_matrice(var f:text);
var
stop:boolean;
temp_colonne:integer;
t:char;
begin {carica_matrice}
temp_colonne:=0; {variabile ausiliaria che permette il conteggio temporaneo delle colonne}
righe:=0;
colonne:=0;
stop:=false;
funghi:=0;
while stop=false do begin {viene ripetuto il ciclo finche non viene letto il carattere "#"}
while not eoln(f) do begin {legge tutti i caratteri della riga}
read(f,t);
if t="#" then stop:=true {se il carattere è "#" ferma il loop while}
else begin
if t="@" then funghi:=funghi+1;
temp_colonne:=temp_colonne+1; {incrementa di 1 il numero di colonne temporanee}
matrice[temp_colonne,righe+1]:=t; {reimposta le celle della matrice dati}
colonne:=colonne+1;
end;
end;
righe:=righe+1; {incrementa di 1 il numero di righe}
readln(f);
temp_colonne:=0;
end;
righe:=righe-1; {viene sottratta la riga contenente "#"}
colonne:=colonne div righe;
end; {carica_matrice}
{************************************************}
{PROCEDURE INSERISCI_MOSSE_IN_LISTA
SCOPO: inserire le mosse lette dal file nella lista creata
EFFETTI COLLATERALI:
CALLED BY: carica_partita
PARAMETERS: f = variabile di testo contenente il file da leggere}
procedure inserisci_mosse_in_lista(var f:text);
var
t:char;
begin {inserisci_mosse_in_lista}
while not eof(f) do begin
read(f,t);
p^.val_x:=t;
read(f,t);
p^.val_y:=t;
readln(f);
new(p^.next);
p:=p^.next;
end;
p^.next:=nil;
end; {inserisci_mosse_in_lista}
{********************************************************************************************}
{PROCEDURE CARICA PARTITA
SCOPO: caricare da un file di testo le informazioni necessare per ripristinare una partita precedentemente salvata.
Viene inizializzata la matrice dati con in valori contenuti nel file, vengono calcolati numero righe, numero colonne,
numero funghi della matrice e inoltre vengono salvate nella lista le mosse effettuate prima del salvataggio.
Il programma riconosce in automatico se il file è un "Rivedi Partita" o un "Ripristina Partita"
EFFETTI COLLATERALI:
CALLED BY: main
PARAMETERS: }
procedure carica_partita;
var
f:text;
x:string;
begin {carica_partita}
x:="";
controlla_lettura_file(f,x); {chiama la procedura per effettuare il controllo del file}
carica_matrice(f); {copia la matrice contenuta nel file nella matrice dati del programma e modifica i parametri
righe,colonne,funghi}
inserisci_mosse_in_lista(f);
writeln("Informazioni di gioco:");
writeln;
writeln("Righe: ",righe:1);
writeln("Colonne: ",colonne:1);
writeln("Funghi: ",funghi:1);
writeln;
writeln("Premi INVIO per proseguire...");
readln;
inizializza_matrice_gioco;
if x="rivedi" then
avvia_gioco(false,true)
else
avvia_gioco(true,false)
end; {carica_partita}
{********************************************************************************************}
begin {main}
while not (numero_menu in ['0'..'2']) do begin {Ripete il ciclo finchè non viene inserito un valore corretto}
repeat
righe:=num_righe;
colonne:=num_colonne;
funghi:=10;
p:=nil; {porta il puntatore della lista a nil}
new(p); {crea una nuova variabile dinamica che è anche la testa della lista}
head:=p; {head corrisponde alla testa della lista}
pulisci_schermo;
writeln;
writeln("* FUNGHI NASCOSTI *");
writeln;
writeln("1. Nuova partita");
writeln("2. Apri file salvato");
writeln("0. Esci dal gioco");
writeln;
write("Opera una scelta: ");
readln(numero_menu);
writeln;
case numero_menu of
'0': ;
'1': nuova_partita(righe,colonne,funghi); {passa alla procedura le dimensioni di default del campo}
'2': carica_partita;
otherwise
end;
until numero_menu='0'; {esci se il valore inserito è '0'}
end;
end. {main}