Ci sono numAgenti
agenti che si muovono nello ‘spazio’ di dimesione x,y
. Inizialmente sono posizionati in ordine inverso nella prima riga:
.9.8.7.6.5.4.3.2.1.0.
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
Ogni agente si muove di una posizione (anche in diagonale) per raggiungere lo stato finale:
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
.0.1.2.3.4.5.6.7.8.9.
La gestione degli spostamenti avviene tramite un opportuno monitor Spazio
con i seguenti metodi:
void register(int n, int x, int y)
: ‘registra’ l’agente n nella posizione x,y. Questo metodo viene invocato una sola volta quando gli agenti vengono creati. Serve per inizializzare lo spazio nella configurazione iniziale.boolean move(int n, int x, int y, int dx, int dy)
: muove l’agente n dalla posizionex,y
alla posizionex+dx, y+dy
. Il valoridx
edy
sono nel range [-1,1] in quanto gli agenti si spostano di una sola posizione. Se la posizione è occupata l’agente attende. Il metodo ritorna false nel caso l’agente n non sia nella posizionex,y
.int getAgent(int x, int y)
: ritorna l’id dell’agente nella posizionex,y
. Se la posizione è vuota ritorna -1. Questo metodo viene usato per stampare la situazione ed eseguire test.
Scopo della prova è implementare il monitor ‘Spazio’ come una classe Java il cui costruttore prende in input le dimenzioni x,y dello spazio di gioco (es. Spazio(10,10)
) e con i tre metodi sopra descritti. Utilizzare il programma di test riportato qui sotto.
Programma di test
import java.util.HashSet; import java.util.Set; public class Test extends Thread { private static final int numAgenti =10; // numero agenti private static final int x=10, y=10; // dimensione spazio di gioco private final int num; // id dell'agente private final Spazio s; // monitor spazio di gioco private int my_x,my_y; // costruttore: salva id, monitor e posizione iniziale dell'agente Test(int num, Spazio s) { this.num = num; this.s = s; this.my_x = numAgenti -1 - num; this.my_y = 0; } public void run() { try { code(); } catch (InterruptedException e) { System.out.println("Agente numero "+num+" interrotto!!"); } } // codice dei thread void code() throws InterruptedException { int dx, dy, i, j, a; if (num == numAgenti) { // questo thread stampa solo la situazione e controlla interferenze // vedere nel ramo 'else' per il codice degli agenti boolean done = false; Set <Integer>check = new HashSet <Integer>(); // attende che tutti gli agenti siano registrati sleep(1000); // controlla la registrazione for (i=0;i<x;i++) if (s.getAgent(i,0) != numAgenti-1-i) { System.out.println("Errore: l'agente " + i + " non e' registrato correttamente"); System.exit(1); } // stampa e controlla la situazione ogni secondo while(!done){ // stampa check.clear(); // svuota l'insieme di id synchronized(s) { System.out.println("===="); for (j=0;j<y;j++) { for (i=0;i<x;i++) { a = s.getAgent(i,j); if (a == -1) System.out.print(". "); else { System.out.print("."+a); if (check.contains(a)) { System.out.println("Errore: l'agente " + a + "e' presente 2 volte!"); System.exit(1); } else // lo aggiungiamo check.add(a); } } System.out.println("."); // se tutti gli agenti sono sull'ultima linea if (j+2 == y && check.isEmpty()) done = true; } } // controlla che non ci siano overlap: tutti gli agenti devono essere presenti if (check.size() != numAgenti) { // manca qualche agente! System.out.println("Errore: sono presenti solo gli agenti " + check); System.exit(1); } // se tutti gli agenti sono sull'ultima riga controlla che siano nell'ordine // giusto if (done) { for (i=0;i<x;i++) if (s.getAgent(i,y-1) != i) { System.out.println("Errore: l'agente " + i + " non e' posizionato correttamente"); System.exit(1); } } else sleep(1000); } // se non siamo usciti prima il test e' superato System.out.println("Tutti gli agenti sono posizionati correttamente"); } else { // questo sono gli agenti // si registra s.register(num,my_x,my_y); // il giocatore e' pronto attende che tutti si registrino System.out.println("Agente numero "+num+" registrato!"); sleep(500); // qui avvengono le mosse while (my_y != y-1) { sleep(1000); // si muovono tutti assieme ogni secondo // calcola la mossa dy = 1; // scende sempre di una posizione if (num == my_x) dx = 0; // posizione giusta, non si muove orizzontalmente else { dx = (num - my_x) / Math.abs(num - my_x); // -1,1 a seconda della necessita' } // prova a fare la mossa if (!s.move(num,my_x,my_y,dx,dy)) { System.out.println("Agente numero "+num+ ": la posizione non corrisponde!!"); System.exit(1); } // aggiorna la posizione my_x += dx; my_y += dy; } } } public static void main(String argv[]) throws InterruptedException { int j; Spazio s = new Spazio(x,y); // crea il monitor // crea i thread dei vari colori/numeri for (j=0; j<=numAgenti; j++) { (new Test(j,s)).start(); } } }
Ho provato una soluzione per l’esercizio in questo modo:
(Non ho fatto nessun controllo sul fatto che si potessero muovere per più di una posizione ma ho fatto si che se mi trovo nella posizione 9,9 con 1,1 finisco in 0,0 anche se non so quanto sia giusto
La mia soluzione.
Speriamo che anche l’ esame sia così! 😛
@Andrea: OK non serviva che chiudessi il gioco modulo righe,colonne. Gli agenti non vanno mai fuori dai bordi
@Loris: OK ma commenta! Prendete l’abitudine di commentare sempre il codice via via che lo scrivete.
Dovrebbe essere tutto ok, sembra funzionare bene 🙂
Ecco anche la mia soluzione!
La mia soluzione è molto simile alle vostre, ho usato però notify() anziché notifyAll() come ha fatto anche Andrea. In questo caso quale dei due è più corretto?
@Roberta: la verifica della presenza dell’agente è meglio farla prima del wait. Inutile attendere per poi ritornare false
@Gabriele: OK
@Lorenzo: meglio usare notifyAll quando hai thread che attendono eventi differenti. notify potrebbe sbloccare un thread che si riblocca e magari altri che potrebbero procedere attendono inutilmente. Di fatto in java usi spesso notifyAll avendo un’unica coda di attesa. Usi notify quando in effetti è indifferente quale thread viene sbloccato (coda in cui i thread attendono tutti lo stesso evento).