Progetto ingegneria del software: la torre di Hanoi Docente: Rosario Culmone Studente: Edmondo Barocci Matr. 078426 1
Indice 1. Analisi 3 1.1 Analisi del testo 3 1.2 Vocabolario dei termini 4 1.3 Use case diagram 5 1.4 Activity diagram 6 1.5 Codifica in Alloy 7 1.6 Codifica di reti di Petri 9 2. Progettazione 10 2.1 Class Diagram 10 2.2 Sequence Diagram 11 2.3 State Diagram 12 2.4 Collaboration Diagram 13 2.5 Object Diagram 14 2.6 Design Pattern 15 2.7 Ocl 16 3. Codifica 21 3.1 Codifica in Java con specifiche codice in JML 21 4. Test 24 4.1 JUNIT con modalità di test di unità 24 5. Documentazione 25 5.1 Deployment Diagram 25 6. Note 26 6.1 Annotazioni non formali 26 6.2 Strumenti utilizzati 26 2
1.Analisi 1.1 Analisi del testo Si vuole realizzare un programma applicativo che implementi il gioco della torre di Hanoi: un rompicapo di logica inventato da Edouard Lucas in cui inizialmente un certo numero di dischi di diametro diverso vengono impilati su un asta in ordine decrescente ed altre due aste vengono lasciate vuote, lo scopo del gioco è quello di spostare tutti i dischi sulla terza asta,uno alla volta, utilizzando la seconda come appoggio, col minor numero di spostamenti. L'unica regola è che un disco non può essere spostato sopra un altro disco piu piccolo. Il programma, a seconda della scelta di livello dell'utente,e quindi del numero di dischi, deve posizionare inizialmente tutti i dischi sull'asta di sinistra e lasciare poi all'utente la gestione dello spostamento di posizione dei dischi, sollevando e posando un disco, e cambiando asta di riferimento; il programma deve inoltre vincolare l'utente in cambiamenti di posizione verso uno stato consentito: un disco non puo essere spostato su un altro disco di diametro minore. Il programma deve sempre permettere all'utente di resettare il gioco e quindi di aggiungere o togliere un disco. 3
1.2 Vocabolario dei termini Termine Relazione Termine Torre di Hanoi has as aspect Asta Torre di Hanoi Is used by Utente Torre di Hanoi is quantified as Disco Asta contains Disco Disco has as aspect Diametro Disco has as aspect Posizione Disco has as aspect Stato Livello is quantified as Disco Posizione has as aspect Disco Posizione has as aspect Asta Spostamento is quantified as Disco Stato Is used by Spostamento Numero di dischi is quantified as Disco Diametro Is used by Stato 4
1.3 Use case diagram 5
1.4 Activity diagram 6
1.5 Codifica in Alloy one sig Hanoi { Aste : set Asta }{#Aste=3} sig Asta { ndischi : set Disco } sig Disco { diametro : one Int, inferiore : lone Disco } {diametro >0 } fact unicaasta { all d : Disco one a:asta d in a.ndischi } //ogni disco è in un unica asta fact mindischi {all h:hanoi #h.aste.ndischi >= 3 } //numero minimo di dischi = 3 fact nodoppio { all x, y :Disco x!= y implies x.diametro!= y.diametro } //due dischi non possono avere lo stesso diametro fact noasfuse { all a : Asta some h : Hanoi a in h.aste } //non ci sono aste sfuse fact samepole {all d : Disco one a: Asta d in a.ndischi and d.inferiore in a.ndischi } //un disco e il suo inferiore sono nello stessa asta fact nostinf { all x, y :Disco x!= y implies x.inferiore!= y.inferiore} //due dischi non possono avere lo stesso inferiore fact noinfrec { all x, y :Disco x.inferiore = y implies y.inferiore!= x } //due dischi non possono essere l'uno inferiore dell'altro e viceversa fact noanelli { no x: Disco x in x.^inferiore } //un disco non è nella sua chiusura transitiva, quindi non ci sono anelli fact therule { all x, y :Disco x.inferiore = y implies y.diametro > x.diametro } //un disco non puo stare sopra un disco di diametro minore fact therule2 { all x, y :Disco x.inferiore = y implies y.diametro < (x.diametro +2)} //un disco è sopra un disco di diametro maggiore di 1 pred Mostra() { #Disco >0} //predicato show con un numero di istanza Disco maggiore di zero run Mostra for 15 //esegue Mostra //assert hanoi { all x :Disco some y, z:asta x in y.ndischi or x in z.ndischi } //controlla //check hanoi for 10 //verifica l'assert hanoi per 10 unità 7
8
1.6 Codifica di reti di Petri 9
2.Progettazione 2.1 Class Diagram 10
2.2 Sequence Diagram 11
2.3 State Diagram 12
2.4 Collaboration Diagram 13
2.5 Object Diagram 14
2.6 Design Pattern Singleton: Prototype: 15
Hanoi.use 2.7 Ocl model Hanoi - - classes class Hanoi attributes unico : Hanoi livello : Integer operations Hanoi(livello : Integer) gethanoi() : Hanoi getlivello() :Integer tostring() : String aggiungidisco() rimuovidisco() Sposta(vecchiaAsta:Asta, nuovaasta:asta) : Boolean ReStart() end class Asta attributes ndischi : Integer operations Asta(nDischi:Integer) getndischi():integer setndischi(dischi:integer) getfirst():disco solleva():disco posa(d:disco):boolean end class Disco attributes diametro : Integer inferiore : Disco operations Disco(diametro:Integer) getinferiore():disco getdiametro():integer setinferiore(disco:disco) setdiametro(diametro:integer) clone():disco end - - associations association aste between Hanoi[1] role contenute Asta[3] role contiene end association dischi between Asta[1] role contenuti Disco[0..*] role contiene end 16
- - constraints constraints context Hanoi inv: livello >= 3 context Hanoi::Hanoi( livello : Integer) pre: livello >= 3 context Hanoi::rimuoviDisco() post : self.livello = self.livello@pre - 1 context Hanoi::aggiungiDisco() post : self.livello = self.livello@pre + 1 context Asta::Asta(nDischi : Integer) pre: ndischi >= 0 context Asta inv: ndischi >= 0 context Asta::solleva() : Disco pre : self.ndischi >= 1 post : self.ndischi = self.ndischi@pre - 1 context Asta::posa(d:Disco) : Boolean post : self.ndischi = self.ndischi@pre + 1 context Disco::Disco( diametro : Integer) pre: diametro >= 0 context Disco inv : (self.inferiore <> null) implies (self.diametro < self.inferiore.diametro) context Disco::setInferiore( disco: Disco) pre : disco.diametro > self.diametro context Disco::setDiametro( diametro : Integer) pre : (self.inferiore <> null) implies (diametro < self.inferiore.diametro) 17
18
HanoiClone.cmd!create solo : Hanoi!create sx : Asta!create dx : Asta!create cx : Asta!set solo.livello := 3!set sx.ndischi := 3!set cx.ndischi := 0!set dx.ndischi := 0!create uno : Disco!create due : Disco!create tre : Disco!set uno.diametro := 1!set uno.inferiore := due!set due.diametro := 2!set due.inferiore := tre!set tre.diametro := 3!insert (solo,sx) into aste!insert (solo,cx) into aste!insert (solo,dx) into aste!insert (sx,uno) into dischi!insert (sx,due) into dischi!insert (sx,tre) into dischi!openter solo sposta(sx,cx)!openter sx getndischi()!opexit 3!openter sx getfirst()!opexit uno!openter uno getdiametro()!opexit 1!openter cx getndischi()!opexit 0!openter sx solleva()!delete (sx,uno) from dischi!openter uno clone()!create unoclone : Disco!set unoclone.diametro := 1!opexit unoclone!destroy uno!openter sx setndischi(2)!set self.ndischi := 2!opexit!opexit unoclone!openter cx posa(unoclone)!insert (cx,unoclone) into dischi!set unoclone.inferiore := null!openter cx setndischi(1)!set self.ndischi := 1!opexit!opexit true!opexit true 19
20
3.Codifica 3.1 Codifica in Java con specifiche codice in JML public final class Hanoi{ private /*@ spec_public @*/ Asta[] aste; private /*@ spec_public @*/ int livello; //@ invariant aste!= null; //@ invariant aste.length == livello;... /*@ @ normal_behaviour @ requires @ da!= null; @ requires @ a!= null; @ requires @ da!= a; @ requires @ da.ndischi > 0; @ ensures @ da.getfirst().diametro < a.getfirst().diametro ==> \result == true; @ @ also @ @ exception_behavior @ signals(invalidmoveexception e) @ (da == null) (a == null) @ (da == a) (da.ndischi <= 0) @ (da.getfirst().diametro > a.getfirst().diametro ); @ @*/ public boolean sposta(asta da, Asta a) throws InvalidMoveException{ //@ assert livello == \old(livello);... }... } 21
public class Asta{ private /*@ spec_public @*/ int ndischi ; private /*@ spec_public @*/ Disco[] dischi; //@ invariant ndischi >=0;... /*@ @ normal_behaviour @ assignables ndischi @ requires ndischi >=1; @ ensures ndischi == \old(ndischi) + 1; @ @ also @ @ exception_behavior @ signals(nodiscsexception e )ndischi < 1; @*/ public Disco solleva() throws NoDiscsException{... } /*@ normal_behaviour @ assignables ndischi @ requires disco!= null; @ ensures ndischi == \old(ndischi) - 1; @ @ also @ @ exception_behavior @ signals(nulldiscexception e )disco == null; @*/ public boolean posa(disco disco) throws NullDiscException{... } } 22
public class Disco implements Cloneable { private /*@ spec_public @*/ int diametro ; private /*@ spec_public @*/ Disco inferiore ; //@ invariant inferiore!=null => diametro < inferiore.diametro; //@ invariant diametro > 0;... /*@ normal_behaviour @ assignables inferiore @ requires @ inferiore!= null; @ requires @ diametro < Disco.diametro; @ @ also @ @ exception_behavior @ signals(hanoiruleexception e )diametro >= Disco.diametro; @*/ void setinferiore ( Disco inferiore ) throws HanoiRuleException{... } } 23
4.Test 4.1 JUNIT con modalità di test di unità import org.junit.*; import static org.junit.assert.*; public class TestHanoi { private Hanoi solo; @Before public void setup(){ solo = new Hanoi(3); } } @Test public void testsposta(){ asserttrue (solo.sposta(aste[0],aste[1])); asserttrue (solo.sposta(aste[0],aste[2])); assertfalse(solo.sposta(aste[0],aste[1])); } public class TestAsta { private Asta centrale; @Before public void setup(){ centrale = new Asta(3); } @Test public void testsolleva(){ assertequals(centrale.ndischi,2); } @Test public void testposa(disco disco){ 24
5.Documentazione 5.1 Deployment Diagram 25
6.Note 6.1 Annotazioni non formali La torre di Hanoi è un rompicapo di logica inventato nel 1883 da Edouard Lucas: matematico francese. Il numero minimo di mosse per la risoluzione del problema è 2 n -1, con n : numero di dischi; la soluzione, date le 3 aste, può essere calcolata con il seguente algoritmo ricorsivo: spostare n-1 dischi dalla prima alla terza asta, spostare l'n-esimo disco dalla prima alla seconda asta, spostare n-1 dischi dalla terza alla seconda asta. Quindi con un gioco a 3 dischi le mosse sono 7 : asta A asta B, asta A asta C, asta B asta C, asta A asta B, asta C asta A, asta C asta B, asta A asta B. 6.2 Strumenti utilizzati - Alloy http://alloy.mit.edu/alloy/download.html - UML http://argouml.tigris.org/, http://www.umlet.com/ - Reti di Petri http://pipe2.sourceforge.net/ - OCL http://sourceforge.net/apps/mediawiki/useocl/index.php?title=main_page 26