function taskSelectionRandom
% Funzione che realizza la logica di assegnazione SMTI Revised
% (WeddingPlanner) in versione randomizzata.

global X pool t;

%% aggiornamento liste:
for n = 1 : length(X) %per ogni agente:
    [X(n).list,X(n).score,X(n).index] = deal([]); %pulisci liste e punteggi.
    for h = 1 : length(pool) %scorre il pool
        if ismember(n,[pool(h).list]) %se il task e' compatibile:
            X(n).list(end+1) = pool(h).ID;  % aggiungi l'ID alla lista
            X(n).score(end+1) = computeScore(pool(h)); %calcola punteggio
            X(n).index(end+1) = h; %salva posizione nel pool
        end
    end
    %riordina liste e punteggi:
    [X(n).score,sortIndex] = sort(X(n).score,2,'descend');
    X(n).list = X(n).list(sortIndex);
    X(n).index = X(n).index(sortIndex);
%     message(['AGENT' num2str(n) '. preference list:']);
%     message([X(n).list' X(n).score' X(n).index']);
end

%% assegnazione:
oldAssignment = -ones(1,length(pool)); %memoria delle assegnazioni
iterCounter = 0;        %contatore delle iterazioni
maxIter = length(X);    %massimo numero di iterazioni ammissibili (per garantire terminazione algoritmo)
while any([pool.a]~=oldAssignment) && iterCounter < maxIter  %se ci sono state variazioni nelle assegnazioni
    oldAssignment = [pool.a];   %aggiorna memoria delle assegnazioni
    iterCounter = iterCounter+1; %incrementa contatore assegnazioni
    for n = randperm(length(X))   %per ogni agente:
        assignmentDone = false; %flag che memorizza se e' avvenuta un'assegnazione
        for score = sort(unique(X(n).score),2,'descend') %per ogni diverso
                            %valore dei punteggi (in ordine decrescente):
            % crea liste brevi per i task con pari punteggio (=score)
            tempList = X(n).list(logical(X(n).score==score));
            tempIndex = X(n).index(logical(X(n).score==score));
            
            % Se l'eventuale task in esecuzione e' gia' tra i migliori, passa
            % all'agente successivo:
            if isstruct(X(n).tsk) && ismember(X(n).tsk.ID,tempList)
                assignmentDone = true; %miglior task gia' assegnato.
%                 message(['Agent' num2str(n) ' is still executing:']);
%                         message(X(n).tsk);
            end

            % Se ci sono task non assegnati tra i migliori, assegna il
            % primo e passa all'agente successivo:
            if ~assignmentDone
                for h = tempIndex%(randperm(length(tempIndex))) %per ogni miglior task:
                    if any([pool(h).a] == 0) %se il task non e' assegnato:
                        if isstruct(X(n).tsk) %libera agente dal task in esecuzione:
                            pool(logical([pool.ID]==X(n).tsk.ID)).a = 0;
                        end
                        %assegna il nuovo task:
                        pool(h).a = n;
                        X(n).tsk = pool(h);
                        assignmentDone = true; %passa ad agente successivo
                        message(['Agent' num2str(n) ' now executes:']);
                        message(X(n).tsk);
                        break;
                    end
                end
            end
            
            % Se tutti i migliori task sono assegnati valuta lo swap ed in
            % caso esegui assegnazione:
            if ~assignmentDone
                for h = tempIndex(randperm(length(tempIndex)))  %per ogni miglior task:
                    % se lo swap e' conveniente (strettamente):
                    thisIndex = X(n).index; % vettore degli indici dell'agente corrente
                    otherIndex = X(pool(h).a).index; %vettore degli indici dell'agente concorrente
                    % se l'agente corrente ha il task considerato piu'
                    % vicino alla fine della sua lista rispetto all'agente
                    % concorrente considera lo swap conveniente. In caso di
                    % pareggio valuta il numero di task che gli agenti
                    % possono eseguire. In caso di pareggio ulteriore sceglie casualmente:
                    if  ( length(thisIndex)-find(h==thisIndex) < length(otherIndex)-find(h==otherIndex) ) ||...
                        ( length(thisIndex)-find(h==thisIndex) == length(otherIndex)-find(h==otherIndex) &&...     
                                                          length(X(n).list) < length(X(pool(h).a).list) ) ||...
                        ( length(thisIndex)-find(h==thisIndex) == length(otherIndex)-find(h==otherIndex) &&...     
                         length(X(n).list) == length(X(pool(h).a).list) && randi([0 1])  ) 
                        
                        if isstruct(X(n).tsk) %libera agente dal task in esec.
                            pool(logical([pool.ID]==X(n).tsk.ID)).a = 0;
                        end
                        % assegna task:
                        message(['Agent' num2str(n) ' (after Agent'...
                                 num2str(pool(h).a) ') now executes:']);
                        X(pool(h).a).tsk = [];  % libera agente perdente
                        pool(h).a = n;          % aggiorna pool
                        X(n).tsk = pool(h);     % aggiorna agente
                        assignmentDone = true;  % passa ad agente successivo
                        message(X(n).tsk);
                        break;
                    end
                end
            end
            % Se e' stata fatta un'assegnazione smetti di valutare gli
            % score piu' bassi e passa all'agente successivo:
            if assignmentDone, break; end
            % altrimenti passa ad uno score piu' basso..
        end
    end
end
end
