Navigatore GPS - Dario Malchiodi

Transcript

Navigatore GPS - Dario Malchiodi
Navigatore GPS
Progetto valido per gli appelli di Giugno e Luglio 2009
1
Descrizione
Il progetto consiste nel realizzare un programma che permetta di memorizzare una mappa e di
elaborarla al fine di trovare il percorso più breve che unisca due punti in essa contenuti.
2
Grafi
Un grafo è una struttura dati che permette di memorizzare un insieme di associazioni tra coppie
di oggetti. Più formalmente:
Definizione 1 Un grafo è univocamente determinato da una coppia G = (V, E), dove V rappresenta un insieme i cui elementi vengono definiti nodi e E ⊆ V 2 è un insieme di archi, ognuno dei
quali collega due nodi in V .
I grafi vengono utilizzati in svariati ambiti matematici e informatici: noi faremo riferimento a essi
al fine di descrivere una mappa. In altre parole, l’insieme V conterrà una serie di luoghi (potrebbero essere città all’interno di uno stato oppure palazzi in una città) e l’insieme E conterrà dei
collegamenti tra luoghi (tipicamente, autostrade in uno stato o strade in una città). Chiameremo
altresı̀ peso di un arco la lunghezza della distanza, misurata in chilometri ed espressa come numero
con la virgola, che unisce i due luoghi corrispondenti. Inoltre, per comodità prevederemo di poter
associare anche altre informazioni sia ai nodi (per esempio, la latitudine e la longitudine del luogo
che rappresentano) sia agli archi (al fine di indicare, sempre per esempio, il nome di una strada
che collega due nodi).
È necessario porre particolare attenzione al fatto che i grafi che considereremo sono orientati :
la presenza di un arco che collega il nodo i al nodo j non implica la presenza di un arco nel verso
opposto (cioè da j a i). Analogamente, in caso esista sia un arco che collega il nodo i al nodo j,
sia un arco che effettua il collegamento opposto, non è detto che questi debbano necessariamente
avere lo stesso peso. Invece presupporremo che, dato un nodo di partenza e un nodo di arrivo,
esista sempre al più un solo arco che li collega.
2.1
Rappresentazione di grafi
È possibile utilizzare vari modi per rappresentare un grafo G = (V, E). Noi saremo particolarmente
interessanti a quelli basati sulle matrici di adiacenza e sulle matrici di incidenza, le cui definizioni
sono le seguenti.
1
7
1
4
3
1
3
2
2
5
3
6
5
Figura 1: Un grafo di esempio.
Definizione 2 La matrice di adiacenza di un grafo G = (V, E) è una matrice quadrata n × n,
dove n è il numero di nodi contenuti in V , il cui generico elemento alla riga i-esima e alla colonna
j-esima, che indicheremo con vij , è definito nel seguente modo:
(
0 se il nodo i non è collegato con il nodo j,
vij =
d altrimenti, dove d è il peso dell’arco che collega il nodo i al nodo j.
Definizione 3 La matrice di incidenza di un grafo G = (V, E) è una matrice n × m, dove n e
m indicano rispettivamente il numero di nodi e di archi nel grafo, e il cui generico elemento zij è
definito nel seguente modo:


se il j-esimo arco parte dal nodo i e ha peso d,
d
zij = −d se il j-esimo arco arriva al nodo i e ha peso d,


0
altrimenti.
Se consideriamo per esempio il grafo illustrato in Figura 1, in cui V = {1, 2, 3, 4, 5}, E =
{(1, 2), (1, 4), (2, 3), (2, 5), (3, 4), (3, 5), (4, 1), (5, 4)} e i cui pesi sono mostrati nella figura, la corrispondente matrice di adiacenza sarà la seguente matrice 5 × 5 (in quanto il grafo è composto da
cinque nodi):


0 1 0 7 0
 0 0 2 0 6 


 0 0 0 3 3 


 7 0 0 0 0 
0 0 0 5 0
Analogamente, la matrice di incidenza del medesimo grafo sarà la seguente matrice 5×8 (in quanto
il grafo ha cinque nodi e otto archi):


1
0
0
0
0
0
7 -7
 -1 2
0
0
0
6
0
0 


 0 -2 3
3
0
0
0
0 


 0
0
0 -3 -5 0 -7 7 
0
0 -3 0
5 -6 0
0
2
3
Ricerca del cammino minimo su un grafo
Il problema del cammino minimo su un grafo può essere formulato nel modo seguente: dato un
grafo G = (V, E), e dati due nodi vstart , vend ∈ V , è richiesto di determinare il percorso più corto
che permette, partendo da vstart , di raggiungere vend attraversando archi in E. Un cammino si
può descrivere elencando in che ordine vengono attraversati i suoi nodi, mentre la sua lunghezza si
ottiene sommando i pesi degli archi che lo compongono. Per esempio, tornando al grafo illustrato in
Figura 1, per procedere da vstart = 1 a vend = 4 è possibile utilizzare sia il cammino 1 → 2 → 5 → 4,
che ha lunghezza 12, sia il cammino 1 → 4, che ha lunghezza 7, sia altri cammini. Tra questi, il
cammino minimo è 1 → 2 → 3 → 4, che ha lunghezza 6.
Determinare automaticamente il cammino minimo tra due nodi di un grafo è un problema rilevante nel campo dell’informatica. Tra le soluzioni possibili, consideriamo quella indicata dall’algoritmo di Floyd-Warshall. Indicato con n il numero di nodi del grafo, l’algoritmo inizia calcolando
(0)
la matrice D(0) il cui generico elemento dij , per i, j = 1, . . . , n, è
(0)
dij


se i = j,
0
= p se tra i nodi i e j vi è un arco, dove p è il peso di quest’ultimo,


∞ altrimenti.
Successivamente, per tutti i valori k = 1, . . . , n viene calcolata la matrice D(k) , il cui generico
elemento è
n
o
(k)
(k−1) (k−1)
(k−1)
dij = min dij
, dik
+ dkj
(n)
Al termine di questo conto, se dij è un valore diverso da 0 e da ∞, esso rappresenta la lunghezza
del cammino minimo per andare dal nodo i al nodo j. Per poter calcolare il cammino vero e proprio,
(0)
andrà calcolata inizialmente la matrice P (0) , il cui generico elemento pij per i, j = 1, . . . , n, è
(0)
pij
(
NaN se i = j o se i nodi i e j non sono uniti da un arco,
=
i
altrimenti.
Si determinano poi le matrici P (k) per k = 1, . . . , n, il cui generico elemento sarà
(
k−1
pk−1
se dk−1
≤ dk−1
(k)
ij
ij
ik + dkj ,
pij =
pk−1
altrimenti.
kj
(n)
Una volta determinata la matrice P (n) , il suo elemento pij contiene il predecessore del nodo j nel
cammino di lunghezza minima che unisce il nodo i al nodo j.
È importante notare due cose:
• per poter calcolare la matrice D(k) è sufficiente conoscere D(k−1) , cosı̀ come per poter calcolare
P (k) è sufficiente conoscere P (k−1) e D(k−1) ;
• i valori ∞ e NaN si possono rappresentare facilmente facendo riferimento alle costanti
Double.POSITIVE INFINITY e Double.NaN.
3
Esempio
Se riconsideriamo il grafo in Figura 1, applicando l’algoritmo di
seguenti matrici D(0) , . . . , D(5) , P (0) , . . . , P (5) :



NaN
1
0.0 1.0 ∞ 7.0 ∞
NaN NaN
 ∞ 0.0 2.0 ∞ 6.0



(0)


D(0) = 
 ∞ ∞ 0.0 3.0 3.0 P = NaN NaN
 4
7.0 ∞ ∞ 0.0 ∞ 
NaN
NaN NaN
∞ ∞ ∞ 5.0 0.0
D(1)


0.0 1.0 ∞ 7.0 ∞
 ∞ 0.0 2.0 ∞ 6.0



=
 ∞ ∞ 0.0 3.0 3.0
7.0 8.0 ∞ 0.0 ∞ 
∞ ∞ ∞ 5.0 0.0
D(2)


0.0 1.0 3.0 7.0 7.0
 ∞ 0.0 2.0 ∞ 6.0 



=
 ∞ ∞ 0.0 3.0 3.0 
7.0 8.0 10.0 0.0 14.0
∞ ∞
∞ 5.0 0.0
D(3)


0.0 1.0 3.0 6.0 6.0
 ∞ 0.0 2.0 5.0 5.0 



=
 ∞ ∞ 0.0 3.0 3.0 
7.0 8.0 10.0 0.0 13.0
∞ ∞
∞ 5.0 0.0

D(4)
0.0
1.0
3.0 6.0
12.0 0.0
2.0
5.0

10.0
11.0
0.0
3.0
=

 7.0
8.0 10.0 0.0
12.0 13.0 15.0 5.0

D(5)
0.0
1.0
3.0 6.0
12.0 0.0
2.0
5.0

10.0
11.0
0.0
3.0
=

 7.0
8.0 10.0 0.0
12.0 13.0 15.0 5.0

6.0
5.0 

3.0 

13.0
0.0

6.0
5.0 

3.0 

13.0
0.0
P (1)

NaN
NaN

=
NaN
 4
NaN

Floyd-Warshall otterremo le

NaN
1
NaN
2
NaN
2 

NaN
3
3 

NaN NaN NaN
NaN
5
NaN

1
NaN
1
NaN
NaN
2
NaN
2 

NaN NaN
3
3 

1
NaN NaN NaN
NaN NaN
5
NaN

2
1
2
2
NaN
2 

NaN
3
3 

2
NaN
2 
NaN
5
NaN
P (2)
NaN
1
NaN NaN

=
NaN NaN
 4
1
NaN NaN
P (3)

NaN
1
2
3
3
NaN NaN
2
3
3 



NaN
NaN
NaN
3
3
=


 4
1
2
NaN
3 
NaN NaN NaN
5
NaN

P (4)


NaN
1
2
3
3
 4
NaN
2
3
3 



4
1
NaN
3
3
=


 4
1
2
NaN
3 
4
1
2
5
NaN
P (5)


NaN
1
2
3
3
 4
NaN
2
3
3 



4
1
NaN
3
3
=


 4
1
2
NaN
3 
4
1
2
5
NaN
Volendo ricostruire il cammino minimo per andare, per esempio, dal nodo 1 al nodo 4, si parte
(5)
considerando il valore p14 = 3: ciò indica che nel cammino minimo il predecessore del nodo 4 sarà
il nodo 3. A questo punto basta procedere ricorsivamente, trovando il predecessore del nodo 3 nel
4
5
1,37.11,43.74,Stazione ferroviaria,4,7,via Lunga,2,1,via Breve
2,37.11,43.71,Ristorante,3,2,vicolo Corto,5,6,via Larga
3,37.22,43.73,Municipio,4,3,vicolo Stretto,5,3,vicolo Basso
4,37.13,43.74,Banca centrale,1,7,via Lunga
5,37.13,43.71,Museo di arte moderna,4,5,via Alta
Figura 2: Un esempio di file di configurazione basato su matrice di adiacenza.
(5)
cammino minimo che va dal nodo 1 al nodo 3: siccome p13 = 2, tale predecessore sarà il nodo 2.
(5)
Infine, siccome p12 = 1, che è il nodo di partenza, abbiamo stabilito che il cammino minimo che
va dal nodo 1 al nodo 4 è 1 → 2 → 3 → 4 (derivato considerando in ordine inverso i nodi ottenuti).
(5)
La sua lunghezza sarà d14 = 6, come facilmente verificabile analizzando la Figura 1.
4
Il formato dei dati
Per poter costruire il grafo che descrive una mappa sarà necessario reperire in qualche modo le
informazioni corrispondenti. Noi le leggeremo da due tipi di file di testo, basati rispettivamente su
una matrice di adiacenza e su una matrice di incidenza. I paragrafi seguenti descrivono il formato
di questi due tipi di file.
4.1
Descrizione basata su matrice di adiacenza
I file che descriveranno una mappa basandosi sulla matrice di adiacenza del grafo corrispondente
avranno il seguente formato: la prima linea del file conterrà esclusivamente il numero di nodi del
grafo; inoltre, per ogni nodo del grafo il file conterrà una linea di valori separati da virgola, che
indicheranno nell’ordine:
• un numero intero che identificherà univocamente il nodo: tali numeri devono essere espressi
partendo da 1 e incrementandoli di una unità per ogni riga;
• due numeri con la virgola che indicheranno rispettivamente la latitudine e la longitudine;
• una stringa che conterrà una descrizione del nodo;
• la descrizione degli archi che partono dal nodo, data da una serie di zero o più terne i cui
valori saranno, nell’ordine:
– il numero identificativo del nodo di arrivo;
– il peso dell’arco, espresso da un numero con la virgola il cui valore sarà misurato in
chilometri;
– una stringa che descrive l’arco.
A titolo di esempio, la Figura 2 riporta un esempio di file codificato utilizzando il formato descritto
in questo paragrafo.
5
5 8
1,37.11,43.74,Stazione ferroviaria
2,37.11,43.71,Ristorante
3,37.22,43.73,Municipio
4,37.13,43.74,Banca centrale
5,37.13,43.71,Museo di arte moderna
1,4,7,via Lunga
1,2,1,via Breve
2,3,2,vicolo Corto
2,5,6,via Larga
3,4,3,vicolo Stretto
3,5,3,vicolo Basso
4,1,7,via Lunga
5,4,5,via Alta
Figura 3: Un esempio di file di configurazione basato su matrice di incidenza.
4.2
Descrizione basata su matrice di incidenza
I file che descriveranno una mappa basandosi sulla matrice di incidenza del grafo corrispondente
avranno il seguente formato: la prima linea del file conterrà il numero di nodi e il numero di
archi del grafo, separati da uno spazio; le linee successive descriveranno i nodi del grafo: più
precisamente, per ogni nodo sarà presente una linea di quattro valori separati da virgola, che
indicheranno nell’ordine:
• un numero intero che identificherà univocamente il nodo: tali numeri devono essere espressi
partendo da 1 e incrementandoli di una unità per ogni riga;
• due numeri con la virgola che indicheranno rispettivamente la latitudine e la longitudine;
• una stringa che conterrà una descrizione del nodo.
Il contenuto del file proseguirà con una riga vuota seguita da una serie di righe che descrivono gli
archi: precisamente, per ogni arco nel grafo sarà presente una linea di quattro valori separati da
virgola, che indicheranno nell’ordine:
• il numero identificativo del nodo di partenza;
• il numero identificativo del nodo di arrivo;
• il peso dell’arco, espresso da un numero con la virgola il cui valore sarà misurato in chilometri;
• una stringa che descrive l’arco.
A titolo di esempio, la Figura 3 riporta un esempio di file codificato utilizzando il formato descritto
in questo paragrafo.
6
5
Grafi e GPS
Come abbiamo precedentemente accennato, tramite un grafo è possibile descrivere una mappa
in cui compaiono luoghi e strade che li collegano. Pertanto, l’uso di un algoritmo come quello di
Floyd-Warshall permette di risolvere il problema che demandiamo al nostro GPS. Per essere precisi,
per funzionare correttamente l’algoritmo richiede che i pesi associati agli archi non assumano valori
negativi (in realtà la limitazione non sarebbe cosı̀ stringente, ma nell’ambito di questo progetto non
è il caso di essere cosı̀ precisi). Questo per noi non rappresenta un problema, visto che le distanze
tra due punti non possono assumere valori negativi. Chiaramente, nella vostra implementazione del
progetto dovrete verificare, all’atto della costruzione di un grafo, che i pesi indicati non assumano
valori negativi.
Nota
Nella descrizione delle classi che segue faremo spesso riferimento ad array bidimensionali. Non
fatevi spaventare: si tratta semplicemente di array di array. Per esempio, l’istruzione
int[][] array = new int[3][6];
dichiara array come variabile contenente un array bidimensionale di interi (cioè un array di array di
interi). Contemporaneamente, alla variabile viene assegnato un array contenente tre array, ognuno
dei quali contiene sei interi. Tenete presente che non necessariamente tutti gli array in un array
bidimensionale hanno la stessa lunghezza: per esempio, ciò non capita nella seguente istruzione
int array[][] = {new int[3], new int[5]};
Detto questo, niente panico: siccome gli array bidimensionali che utilizzeremo nel progetto servono
a descrivere delle matrici, questi saranno visibili come array di array della stessa dimensione. Ciò
non vi esimerà, peraltro, dal dover controllare che gli array bidimensionali passati come argomenti
agli opportuni costruttori, siano effettivamente array di array della stessa dimensione.
5.1
Le classi da realizzare
È necessario realizzare in JAVA le seguenti classi:
• Matrix, le cui istanze rappresentano generiche matrici. L’implementazione di questa classe
deve prevedere di:
– poter istanziare una matrice specificando un array bidimensionale di valori double. Il
costruttore dovrà verificare che l’array passato al costruttore sia composto da array
non vuoti e tutti della medesima dimensione, pena l’emissione di un’eccezione di tipo
IllegalArgumentException (la cui classe non va creata appositamente, essendo già
prevista nel package java.lang);
– poter istanziare un elemento della classe specificando il numero di righe, il numero di
colonne e un valore double, che verrà utilizzato per riempire tutti gli elementi della
matrice;
7
– invocare i metodi getNumRows, getNumColumns, getRow, getColumn, getElementAt,
setElementAt e toString, dall’ovvio significato e la cui segnatura deve essere implementata tenendo conto del fatto che i primi argomenti dei metodi, qualora la loro presenza risulti sensata, devono indicare una posizione all’interno della matrice, specificando
prima la riga e poi la colonna;
• AdjacencyMatrix, le cui istanze rappresentano generiche matrici di adiacenza; il costruttore
della classe dovrà accettare come argomento un array bidimensionale di valori double, verificando, oltre a quanto richiesto per la classe Matrix, che la matrice ottenuta sia effettivamente
una matrice di adiacenza.
• IncidencyMatrix, le cui istanze rappresentano generiche matrici di incidenza; il costruttore
della classe dovrà accettare come argomento un array bidimensionale di valori double, verificando, oltre a quanto richiesto per la classe Matrix, che la matrice ottenuta sia effettivamente
una matrice di incidenza.
• Node, le cui istanze rappresentano generici nodi in un grafo che descrive una mappa; l’implementazione di questa classe deve prevedere di:
– istanziare la classe specificando, nell’ordine, due valori con la virgola che indichino
rispettivamente la latitudine e la longitudine del nodo, e una stringa che lo descriva;
– poter invocare i metodi getLatitude, getLongitude e getDescription, dall’ovvio
significato;
– poter invocare il metodo toString, che restituisca una descrizione testuale dell’istanza
nel formato (lat: <la>, lon: <lo>), dove <la> e <lo> siano sostituiti da latitudine
e longitudine effettiva;
– poter invocare il metodo distanceFrom, che accetta come argomento un’istanza di Node
e che restituisce la distanza in linea d’aria (la distanza euclidea) tra il nodo su cui è
stato invocato il metodo e il nodo specificato come argomento;
– nel caso in cui, per comodità, si intenda utilizzare le istanze di Node come chiavi in una
mappa in qualsiasi parte del codice, sarà anche necessario ridefinire opportunamente
anche i metodi equals e hashCode.
• Graph, le cui istanze rappresentano generici grafi i cui nodi sono istanze della classe Node;
l’implementazione di questa classe deve prevedere di:
– istanziare la classe passando come argomenti al costruttore, nell’ordine, un array di
Node e un’istanza di AdjacencyMatrix, dove questi argomenti rappresentano gli insiemi
dei nodi e degli archi del grafo, secondo quanto precedentemente indicato; il costruttore
dovrà lanciare una IllegalArgumentException nel caso in cui i due argomenti abbiano
dimensioni incompatibili e utilizzare la stringa vuota come descrizione di tutti gli archi;
– istanziare la classe passando come argomenti al costruttore, nell’ordine, un array di
Node e un’istanza di IncidencyMatrix, dove questi argomenti rappresentano gli insiemi
dei nodi e degli archi del grafo, secondo quanto precedentemente indicato; il costruttore
dovrà lanciare una IllegalArgumentException nel caso in cui i due argomenti abbiano
dimensioni incompatibili e utilizzare la stringa vuota come descrizione di tutti gli archi;
8
– istanziare la classe in uno dei due modi precedentemente descritti, specificando come
ulteriore argomento al costruttore un array bidimensionale di stringhe che permetta di
associare una descrizione testuale a ogni arco del grafo;
– invocare i metodi public int size() e public Node getNode(int i) dall’ovvio significato;
– invocare il metodo computeShortestPaths, che non riceve argomenti e restituisce l’istanza della classe Matrix corrispondente alla matrice P (n) precedentemente descritta,
dove n indica il numero dei nodi del grafo.
• GPS, che rappresenta la classe principale del progetto; l’implementazione dovrà permettere
di:
– istanziare la classe specificando come argomento del costruttore una stringa che rappresenti il nome di un file i cui contenuti permetteranno di costruire un’istanza di Graph:
in particolare, se il nome del file termina per .inc i contenuti dovranno essere formattati come descritto nel Paragrafo 4.2, altrimenti si utilizzerà il formato descritto nel
Paragrafo 4.1; il costruttore dovrà lanciare una IllegalArgumentException nel caso in
cui il file specificato non sia formattato correttamente. Tale eccezione, unitamente ad
altre eventuali eccezioni dovute all’uso dei file, dovranno essere gestite in un eventuale
metodo main usato per testare il corretto funzionamento del programma. Lo stesso vale
per altre eccezioni eventualmente lanciate da altri metodi, anche in altre classi.
– invocare il metodo public Node getNearestNode(double lat, double lon), i cui
argomenti indicheranno rispettivamente la latitudine e la longitudine di un punto, e il
cui valore restituito sarà un riferimento al nodo del grafo più vicino al punto specificato;
– invocare il metodo public String[] getPath(String descStart, String descEnd),
i cui argomenti indicheranno rispettivamente la descrizione di un nodo di partenza e di
un nodo di arrivo e il cui valore restituito è un array di stringhe che descrive il cammino
minimo tra i due nodi: più precisamente, l’array avrà un elemento per ogni arco nel
cammino, e questo elemento conterrà la descrizione dell’arco stesso. Il metodo deve
verificare la validità delle stringhe passate come argomento, lanciando eventualmente
una IllegalArgumentException;
– invocare il metodo public String sayPath(String descStart, String descEnd),
che dovrà comportarsi in modo analogo a getPath, con l’importante differenza che
il cammino dovrà essere descritto in un’unica stringa che conterrà una riga per ogni
pezzo del percorso. Tale riga dovrà avere il formato da <nodo partenza> prendere
<descrizione collegamento> per <distanza> km. fino a <nodo arrivo>, dove
i testi tra parentesi angolari andranno opportunamente sostituiti con i valori legati
alla particolare invocazione del metodo. Inoltre, nel caso in cui più archi successivi nel
cammino abbiano la stessa descrizione, vi dovrà essere un’unica riga nella stringa restituita, dove <nodo partenza> sarà il nodo di partenza del primo arco, <nodo arrivo>
sarà il nodo di arrivo dell’ultimo arco e <distanza> sarà la somma dei pesi degli archi;
– poter invocare i metodi public String[] getPath(double la, double lo, String
descEnd) e public String sayPath(double la, double lo, String descEnd), il
cui comportamento sarà ovviamente analogo a quanto descritto nei punti precedenti,
con la sola differenza che in questo caso il punto di partenza del cammino sarà il nodo
più vicino al punto di cui si sono specificate le coordinate.
9
Esempio
Sempre considerando il grafo in Figura 1, invocando sul corrispondente oggetto della classe GPS il
metodo
sayPath("Stazione ferroviaria", "Banca centrale")
Si dovrà ottenere come output la seguente stringa:
Da Stazione ferroviaria prendere via Breve per 1.0 km. fino a Ristorante
Da Ristorante prendere vicolo Corto per 2.0 km. fino a Municipio
Da Municipio prendere vicolo Stretto per 3.0 km. fino a Banca centrale
Nell’ipotesi in cui anche l’arco che collega il nodo 3 con il nodo 4 avesse vicolo Corto come
descrizione, la stringa da ottenere in output sarebbe stata:
Da Stazione ferroviaria prendere via Breve per 1.0 km. fino a Ristorante
Da Ristorante prendere vicolo Corto per 5.0 km. fino a Banca centrale
A parte quanto espressamente richiesto, è lasciata piena libertà sull’implementazione delle singole classi e sull’eventuale introduzione di classi aggiuntive, a patto di seguire correttamente le
regole del paradigma di programmazione orientata agli oggetti e i principi di buona programmazione. Si suggerisce di porre particolare attenzione alla scelta dei modificatori relativi a variabili
d’istanza e metodi, alla creazione di metodi di accesso alle variabili di istanza quando questi siano
ritenuti necessari, alla definizione di classi e metodi astratti e di metodi o di variabili statici dove
questi risultino opportuni, nonché alla dichiarazione e alla gestione delle eccezioni che possono
venire lanciate dai vari metodi e alle relazioni di ereditarietà tra le varie classi. Si ricorda altresı̀
di rispettare alla lettera il formato descritto per interpretare i contenuti dei file e dei messaggi di
output.
Non è richiesto l’utilizzo di particolari modalità grafiche di visualizzazione: è sufficiente una
qualunque modalità di output basata sull’uso dei caratteri.
È invece espressamente richiesto di non utilizzare package non standard di Java (si possono quindi utilizzare java.util, java.io e cosı̀ via, ma non prog.io). I progetti che useranno
pacchetti non standard non saranno accettati.
6
Modalità di consegna
Il progetto può essere svolto al massimo da tre persone che intendono sostenere l’intero esame di
Fondamenti di Architettura e Programmazione - Laboratorio di Programmazione negli appelli di
Giugno o Luglio 2009, e deve essere consegnato entro la mezzanotte tra giovedı̀ 11 e venerdı̀ 12
Giugno 2009, tramite il sito di sottoposizione pubblicato all’indirizzo
http://homes.dsi.unimi.it/~malchiod/LP/sottoposizione
Per sottomettere un progetto è necessario che tutti i componenti del gruppo si registrino;
successivamente un componente potrà creare un gruppo a cui affiliare i rimanenti componenti.
La sottoposizione è fatta a nome del gruppo e vale per tutti i suoi componenti. Va sottolineato
che ogni sottoposizione cancella automaticamente eventuali sottoposizioni precedenti dello stesso
progetto.
10
Dovranno essere consegnati tutti i sorgenti Java che permettano al programma di essere eseguito
correttamente, unitamente alla documentazione descritta nel capoverso che segue, compressi in un
archivio di tipo ZIP che estragga i file nella directory in cui si trova l’archivio stesso,
senza creare una nuova directory.
È inoltre richiesto di consegnare, entro venerdı̀ 12 Giugno 2009, una copia cartacea della stampa
del codice sorgente prodotto nella casella di posta (fisica, non elettronica) del docente di riferimento,
situata all’ingresso del DSI/DICo, indicando chiaramente nome, cognome e numero di matricola
di tutti i componenti del gruppo, nonché il turno e il docente di riferimento. A questa copia
cartacea dovrà essere allegato un breve documento in cui saranno illustrate le principali scelte
implementative e le strategie utilizzate per svolgere il progetto. Questo documento dovrà essere
incluso nell’archivio ZIP inviato tramite il sito di sottoposizione, memorizzandolo in un formato
non proprietario (sono accettabili per esempio pdf, rtf e txt). Nella copia cartacea indicare anche
in quali appelli i singoli componenti del gruppo intendono discutere il progetto.
Le sottoposizioni che non seguono queste specifiche e i programmi che non risultano compilabili
correttamente non verranno valutati.
È richiesto di indicare chiaramente all’inizio di tutti i documenti consegnati nome, cognome e
matricola dei vari componenti del gruppo.
7
Valutazione
La discussione con i singoli studenti verterà sulle modalità di implementazione adottate e sulla
padronanza di alcuni dei concetti necessari per realizzare il progetto e/o spiegati a lezione. La
valutazione del progetto sarà fatta in base alla:
• conformità dell’implementazione scelta per risolvere il problema con il paradigma di programmazione a oggetti;
• conformità del codice presentato alle regole di buona programmazione;
• adeguatezza della documentazione presentata;
• assenza di errori nel programma.
Dario Malchiodi
Dip. di Scienze dell’Informazione
Via Comelico 39/41 20135 Milano
Stanza T304 Tel. +39 02 503 16338
e-mail [email protected]
Walter Cazzola
Dip. di Informatica e Comunicazione
Via Comelico 39/41 20135 Milano
Stanza P121 Tel. +39 02 503 16300
e-mail [email protected]
11