Corsi di laurea in Ingegnera Elettronica e Ingegneria Gestionale Fondamenti di Programmazione / Fondamenti di Informatica I
Prova scritta del 15 febbraio 2016
Esercizio 2 (15 punti)
Un file di testo contiene la descrizione dei salti di un punto in un piano rappresentato da una matrice di interi di dimensioni 20x20. La posizione iniziale del punto sia { 0, 0 } e la descrizione dei salti sia nel formato deducibile dal seguente esempio:
x +3; y +15; x +8; y -5; x -3; y +7; x -2;
y -12; x +9;
Una riga del file può contenere uno o più salti, il primo termine identifica la coordinata e il secondo la lunghezza e la direzione del salto. Per esempio, se la posizione corrente del punto è { 10, 10 } il salto y +5; porta il punto nella posizione { 10, 15 }, e il successivo salto x -2; porta il punto nella posizione { 8, 15 }.
Si scriva un programma che riceva sulla linea di comando il nome di un file di salti nel formato di cui sopra, tracci nella matrice i salti in esso descritti e disegni sul video il percorso effettuato dal punto. In ogni posizione della matrice in cui il punto approda va scritto il numero progressivo del salto (attribuendo 1 alla posizione di partenza). Qualora il punto passi più volte nella stessa posizione, la cella dovrà riportare solo il numero dell’ultimo salto.
Nel caso dell’esempio sopra riportato, il programma deve stampare il disegno qui di fianco (gli assi x e y di riferimento sono quelli delle normali coordinate cartesiane).
#include <stdio.h>
#include <stdlib.h>
#define N 20 struct salto {
char coordinata;
int spostamento;
};
void traccia_salti (FILE *fp);
void carica_salti (FILE *fp, int piano[N][N], int x_iniziale, int y_iniziale);
void esegui_salto (int piano[N][N], struct salto m, int *px, int *py, int contatore);
void visualizza_piano (int piano[N][N]);
int estrai_numero (char s[]);
int main (int argc, char *argv[]) {
FILE *fp;
if (argc != 2) {
printf ("ERRORE: salti_punto_nel_piano <nomefile>\n");
exit (EXIT_FAILURE);
}
if ((fp = fopen (argv[1], "r")) == NULL) {
printf ("errore apertura file di ingresso\n");
exit (EXIT_FAILURE);
}
traccia_salti (fp);
. . . . . . . . . . . 8 . 7 . . . . . . . . . . . 3 . . . 4 . . . . . . . . . . . . . . . . . . . . . . . 6 . . 5 . . . . . . . . . . . . . . . . . . . . . . . 9 . . . . 10 . . . . . . . . . . . . . . . . . . . . 1 . . 2 . . . .
fclose (fp);
return EXIT_SUCCESS;
}
void traccia_salti (FILE *fp) {
int piano[N][N] = { 0 };
carica_salti (fp, piano, 0, 0);
visualizza_piano (piano);
return;
}
void carica_salti (FILE *fp, int piano[N][N], int x_corrente, int y_corrente) {
char str_1[8], str_2[8];
struct salto m;
int cnt;
piano [x_corrente][y_corrente] = 1;
cnt = 1;
while (fscanf (fp, "%s %s", str_1, str_2) != EOF) {
m.coordinata = str_1[0];
m.spostamento = estrai_numero (str_2);
cnt++;
esegui_salto (piano, m, &x_corrente, &y_corrente, cnt);
} return;
}
int estrai_numero (char s[]) {
s[strlen(s)-1] = '\0'; /* rimuove il punto e virgola */
return atoi(s);
}
void esegui_salto (int piano[N][N], struct salto m, int *px, int *py, int contatore) {
int i;
if (m.coordinata == 'x') *px += m.spostamento;
else
*py += m.spostamento;
piano[*py][*px] = contatore;
return;
}
void visualizza_piano (int piano[N][N]) {
int x, y;
for (y = N-1; y >= 0; y--) {
for (x = 0; x < N; x++) {
if (piano[y][x] == 0) printf (" . ");
else
printf ("%2d ", piano[y][x]);
}
printf ("\n");
} return;
}
Esercizio 2 (15 punti)
Un file di testo contiene le date di nascita e il soprannome di un numero imprecisato di persone. Ogni riga contiene i dati di una persona, nel formato che può essere dedotto dall’esempio a lato. Si osservi che i nomi dei mesi sono sempre indicati dalle prime tre lettere minuscole del nome in italiano e che i soprannomi sono sempre composti da una sola parola.
3-feb-1970: DarthVader 23-ago-1968: Spider 18-set-2000: Quercia
1-nov-1998: ColpoDellaStrega
Si assuma già disponible la funzione int confronta_date (struct data d1, struct data d2); che, ricevendo le due date nella consueta struttura struct data composta da tre campi interi, restituisce 0 se le due date sono uguali, un valore minore di zero se la data d1 è precedente a d2 e un valore maggiore di zero altrimenti.
Si scriva una funzione in linguaggio C che riceva come argomenti il puntatore a un file di testo nel formato sopra descritto (il file è quindi già stato aperto dalla funzione chiamante) e che restituisca, in un’apposita struttura, soprannome e data di nascita della persona più giovane presente nel file. Per semplicità si può assumere che il file contenga sempre almeno una riga di dati. Nel caso in cui siano più persone di età minima nate esattamente lo stesso giorno dovrà essere restituita la prima di esse presente nel file.
#include <stdio.h>
#include <stdlib.h>
struct data {
int giorno;
int mese;
int anno;
};
int confronta_date (struct data d1, struct data d2) /* non richiesta nella prova di esame */
{
/* restituisce -1 se d1 < d2, 0 se d1 == d2, +1 se d1 > d2 */
if (d1.anno < d2.anno) return -1;
else if (d1.anno > d2.anno) return +1;
else {
/* stesso anno */
if (d1.mese < d2.mese) return -1;
else if (d1.mese > d2.mese) return +1;
else {
/* stesso anno e stesso mese */
if (d1.giorno < d2.giorno) return -1;
else if (d1.giorno > d2.giorno) return +1;
else
return 0;
} } }
struct persona {
char soprannome[64];
struct data data_di_nascita;
};
struct persona il_piu_giovane (FILE *fp);
struct data estrai_data (char s_data[]);
int numero_mese (char nome_mese[]);
int main (int argc, char *argv[]) /* non richiesto nella prova di esame */
{
FILE *fp;
struct persona p;
if (argc != 2) {
printf ("USO: il_piu_giovane <nomefile>\n");
exit (EXIT_FAILURE);
}
if ((fp = fopen (argv[1], "r")) == NULL) {
printf ("errore apertura file %s\n", argv[1]);
exit (EXIT_FAILURE);
}
p = il_piu_giovane (fp);
printf ("%s, %d/%d/%d\n", p.soprannome,
p.data_di_nascita.giorno, p.data_di_nascita.mese, p.data_di_nascita.anno);
fclose (fp);
return EXIT_SUCCESS;
}
struct persona il_piu_giovane (FILE *fp) {
char s_data[128];
struct persona p_corrente, p_piu_giovane, p_vuota = { "", { -1, -1, -1 } };
int minimo_inizializzato = 0; /* facoltativo: consente di gestire anche file vuoti */
while (fscanf (fp, "%s %s", s_data, p_corrente.soprannome) != EOF) {
p_corrente.data_di_nascita = estrai_data (s_data);
if (!minimo_inizializzato) {
p_piu_giovane = p_corrente;
minimo_inizializzato = 1;
} else {
if (confronta_date (p_corrente.data_di_nascita, p_piu_giovane.data_di_nascita) > 0) {
p_piu_giovane = p_corrente;
} } }
if (minimo_inizializzato) return p_piu_giovane;
else
return p_vuota;
}
struct data estrai_data (char s_data[]) {
struct data d;
char t[64];
int i, j;
i = 0;
j = 0;
while (s_data[i] != '-') t[j++] = s_data[i++];
t[j] = '\0';
d.giorno = atoi(t);
i++;
j = 0;
while (s_data[i] != '-') t[j++] = s_data[i++];
t[j] = '\0';
d.mese = numero_mese(t);
i++;
j = 0;
while (s_data[i] != ':') t[j++] = s_data[i++];
t[j] = '\0';
d.anno = atoi(t);
i++;
return d;
}
int numero_mese (char nome_mese[]) {
char nomi_mesi[13][4] =
{ "", "gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic" };
int i;
i = 0;
while (i < 13) {
if (strcmp (nomi_mesi[i], nome_mese) == 0) return i;
i++;
}
return -1;
}