Prova di Laboratorio di Programmazione 6 febbraio 015 ATTENZIONE: Non è possibile usare le classi del package prog.io del libro di testo. Oltre ai metodi richiesti in ciascuna classe, è opportuno implementare altri metodi che si ritengono utili per svolgere l esercizio nel modo più corretto ed elegante, per esempio il metodo tostring() e, quando necessario, i metodi di accesso ai campi. Le operazioni di stampa vanno effettuate esclusivamente nella classe che definisce il metodo main(). Lo scopo del tema è di modellare il viaggio di un auto che ha un autonomia (intesa come massima quantità di benzina che il suo serbatoio può contenere) che gli permette di percorrere k chilometri. All inizio, alla fine del percorso e nelle tappe intermedie sono presenti dei distributori di benzina. Esercizio 1 Si implementino le seguenti classi. Classe Posizione Un istanza della classe Posizione è descritta da due attributi, rappresentati da numeri reali, che corrispondono alle coordinate x e y di un punto su un piano cartesiano. La classe implementa il metodo: public static double distanza(posizione p1,posizione p) che calcola la distanza euclidea tra due posizioni. Classe Distributore Un istanza della classe Distributore rappresenta un distributore, ed è caratterizzato da: posizione (di tipo Posizione); disponibilita (di tipo double). L attributo disponibilita contiene la disponibilità di benzina, per semplicità espressa dal numero di chilometri che possono essere percorsi da un auto rifornita con tutto il carburante disponibile nel distributore. La classe implementa i metodi: public static double calcoladistanza(distributore start, Distributore end) : calcola la distanza tra due distributori passati come argomento del metodo. public boolean erogabenzina(double km): prova a erogare una quantità di benzina che permette all auto di percorrere km chilometri. Restituisce true se l operazione è andata a buon fine (e in tal caso riduce la disponibilità), false altrimenti. Classe AutoNavigatore. Un oggetto della classe AutoNavigatore rappresenta un auto con un semplicissimo navigatore; il navigatore permette di svolgere un percorso tra due distributori, memorizzandone le posizioni e la lunghezza del percorso effettuato. La classe ha due attributi: ArrayList<Distributore> listadistributori: è una lista di N distributori che possono essere inclusi in un eventuale percorso. listadistributori viene passata come argomento del costruttore. double autonomia è l autonomia dell auto (ovvero, il parametro k citato nella introduzione: il serbatoio dell auto può contenere al massimo una quantità di benzina che le permettere di percorrere un numero di chilometri pari al valore contenuto nella variabile autonomia). Anche il valore dell autonomia dell auto viene passato come argomento del costruttore. 1
Il calcolo di un percorso tra alcuni distributori in listadistributori viene eseguito dal metodo public ArrayList<Distributore> percorri(arraylist<integer> listatappe): riceve come argomento una lista di interi che rappresentano gli indici dei distributori in listadistributori. I distributori indicati sono le tappe consecutive del percorso da percorrere. Più precisamente, si suppone che l auto parta dal primo distributore trovato in listatappe, che chiameremo A, e che l auto abbia inzialmente 0 km di benzina nel serbatoio. Se il secondo distributore in listatappe, che chiameremo B, dista d km da A, l auto deve rifornirsi di una quantità di benzina pari a d km, in modo da raggiungere così B. Ciò è possibile solo se d autonomia dell auto (ovvero se il serbatoio dell auto è abbastanza capiente, in modo da contenere così la benzina necessaria per percorrere d km) e se il distributore A ha ancora una disponibilità di benzina sufficiente per erogare d km (ovvero se d disponibilita). Raggiunto B, il navigatore dovrà applicare gli stessi criteri per valutare se l auto può raggiungere la terza tappa in lista, e così via. Se uno dei criteri precedentemente descritti non è valido, il percorso va interrotto. Il metodo restituisce la lista dei distributori visitati, che può essere più corta della lista delle tappe da effettuare se il percorso viene interrotto (per un esempio concreto del metodo, leggete il prossimo paragrafo). public static double lunghezzapercorso(arraylist<distributore> listatappe): riceve come argomento una lista di distributori, e calcola la lunghezza totale del percorso che li collega. Scrivere un programma Prog1 che riceve da linea di comando il parametro N che rappresenta il numero di distributori tra cui possono essere calcolati i vari percorsi, e il parametro k che rappresenta l autonomia dell auto. Il programma inizialmente legge da standard input N righe che descrivono N distributori. Ogni riga ha il formato: coordx coordy disponibilita Tali valori sono le coordinate delle posizioni di un distributore e il carburante inizialmente presente in quel distributore. Leggete questi valori usando Scanner.nextDouble(). Successivamente il programma legge una lista di interi che rappresentano le tappe del percorso da effettuare e di cui calcolare la lunghezza. Leggeteli utilizzando Scanner.nextInt() e usate Scanner.hasNext() per rilevare la fine del file. Avendo eseguito tali passi il programma cerca di effettuare il percorso stampando poi a video un messaggio di notifica riguardo l esito del percorso, il numero di tappe effettivamente raggiunte, la sua lunghezza e la distanze media tra le coppie di tappe consecutive (sia che il percorso sia stato interrotto sia che esso sia stato terminato). Non è necessario fare controlli sulla correttezza dell input. Non vanno fatte assunzioni sul numero di righe in input. L input va letto da standard input e non da file. Per testare il programma, consigliamo di utilizzare la redirezione fornita dalla shell (si vedano gli esempio sotto). Esempio di funzionamento del metodo AutoNavigatore.percorri() Supponiamo che l argomento del metodo AutoNavigatore.percorri() sia il percorso con le seguenti tappe: partire dal distributore A, contenente 75 km di benzina; arrivare al distributore B, distante 5 km da A e contenente 30 km di benzina; arrivare al distributore C, distante 30 km da B e contenente 60 km di benzina; arrivare al distributore A (lo stesso da cui il percorso parte), distante 50 km da C; arrivare al distributore D, distante 15 km da A e contenente 15 km di benzina; terminare nel distributore B, distante 0 km da D.
Si noti che in realtà i distributori sono descritti da indici nella lista complessiva dei distributori. Questo esempio usa delle lettere per semplicità. Se l auto avesse una autonomia di 30 km potrebbe rifornirsi con 5 km di benzina (lasciandone quindi 50 in A) e raggiungere B. Da qui potrebbe riempire tutto il serbatoio con i 30 km di benzina necessari a raggiungere C, lasciando 0 km di benzina in B. A questo punto il percorso si interromperebbe perchè l auto ha una autonomia (30 km) minore della distanza dalla prossima tappa in A (50 km). Se l auto avesse un autonomia di 60 km potrebbe partire da A, arrivare in B, arrivare in C, rifornirsi e lasciare 10 km di benzina in C, tornare in A e rifornirsi dei 15 km necessari ad andare in D (lasciandone 35 in A). A questo punto il percorso si interromperebbe perché la distanza di B da D (0 km) è maggiore della quantità di benzina disponibile in D (15 km). Supponendo infine che l auto avesse una autonomia di 60 km e che in D ci fossero 30 km di benzina, l auto potrebbe terminare il percorso in B. Nel primo caso il percorso A B C sarebbe lungo 5 + 30 = 55 km (distanza media tra tappe consecutive: 7, 5 km). Nel secondo caso il percorso A B C A D sarebbe lungo 5 + 30 + 50 + 15 = 10 km (distanza media tra tappe consecutive: 30 km). Nel terzo caso il percorso A B C A D B sarebbe lungo 5 + 30 + 50 + 15 + 0 = 140 km (distanza media tra tappe consecutive: 8 km). Esempio Il file in.txt contiene le righe seguenti:.5 3.0 100 1. 4.0 50 0.4 10.0 00 0.0 0.0 30.0 3.0 10 5.0 7.0 0 10.0 11.0 10 0 1 3 0 4 Esempi di esecuzione: > java Prog1 7 30 <in.txt Numero di tappe percorse: 7 Distanza totale: 61.77513141593606 Distanza media: 10.9585535988768 > java Prog1 7 0 <in.txt Numero di tappe percorse: 3 Distanza totale: 7.69303685495 Distanza media: 3.846610163471475 3
> java Prog1 7 5 <in.txt Numero di tappe percorse: Distanza totale: 1.64011946685677 Distanza media: 1.64011946685677 Esercizio Si realizzi la seguente classe che eredita da AutoNavigatore: Classe AutoNavigatoreIntelligente. Gli oggetti della classe sono istanze di AutoNavigatore dotate di un metodo aggiuntivo public ArrayList<Distributore> calcolamigliore(): cerca di calcolare un buon percorso tra il primo e l ultimo distributore della lista. Per fare ciò, il navigatore sceglie ad ogni passo la prossima tappa tramite il seguente algoritmo. Quando l auto è in un distributore, che chiameremo A, la prossima tappa viene scelta tra tutti i distributori raggiungibili, cioè a distanza minore o uguale ad autonomia e minore o uguale alla quantità di carburante residuo in A. Tra tutti i distributori raggiungibili che non sono ancora stati utilizzati nel percorso, viene scelto il distributore più vicino all ultimo. Se l ultimo è il distributore più vicino, viene aggiunto al percorso e il metodo termina. Se da A non ci sono distributori che rispettano i criteri precedentemente descritti il metodo termina il calcolo del percorso. In ogni caso, il percorso calcolato viene restituito come risultato. Scrivere un programma Prog che riceve da linea di comando il parametro N che rappresenta il numero di distributori tra cui possono essere calcolati i vari percorsi, e il parametro k che rappresenta l autonomia dell auto. Usando gli stessi formati di riga descritti per Prog1, Prog legge da standard input una lista di N righe che descrivono N distributori. Il programma quindi cerca di calcolare il percorso migliore tra il primo e l ultimo distributore. Sia che il percorso risulti interrotto o che si riesca a raggiungere l ultimo distributore, il programma stampa il numero di tappe, la lunghezza del percorso pianificato e la distanza media tra due distributori. Non è necessario fare controlli sulla correttezza dell input. L input va letto da standard input e non da file. Per testare il programma, consigliamo di utilizzare la redirezione fornita da shell (si veda l esempio sotto). Esempio Si noti che le righe di in.txt che descrivono le tappe non vengono lette da Prog. > java Prog 7 30 <in.txt Numero di tappe percorse: Distanza totale: 10.965856099730654 Distanza media: 10.965856099730654 > java Prog 7 10 <in.txt Numero di tappe percorse: 3 Distanza totale: 11.1011480346115 Distanza media: 5.560057401730575 > java Prog 7 5 <in.txt Numero di tappe percorse: 4 Distanza totale: 10.839107887895 Distanza media: 3.6130346759651 4
Istruzioni per la consegna Consegnare soltanto i file sorgenti (non i file.class): come un unico file compresso creato col comando zip nome_cognome *.java Eseguire l upload del file all indirizzo upload.di.unimi.it. Non consegnate file che non compilano. Se decidete di ritirarvi create (e consegnate tramite il metodo di upload) un file di testo dal nome ritirato.txt. 5