Triky ha scritto:
Ciao, avrei un'altra richiesta di chiarimento
Ti vorrei chiedere per favore (anzi ti prego
) una descrizione dettagliata della sequenza di generazione dei tavoli nella modalità TorneoGufo ed in particolare di come vengono spostati i giocatori quando sopravviene un'esclusione (es. presupponendo che i giocatori siano preassegnati tutti insieme provvisoriamente, se abbiamo i tavoli: Tav. 1 di 4 giocatori A B C D - Tav. 2 di 4 Giocatori E F G H, il giocatore D non puo' giocare con C e deve essere sostituito, lo scambia con il giocatore E ?)
Faccio un paio di premesse:
1) Il programma scrive un log in forma sintetica nel foglio excel ed in forma dettagliata su un file in una sottocartella di quella del programma: non è di facile lettura ma più o meno descrive quello che fa durante l'elaborazione.
2) Descrivere a parole un algoritmo soprattutto se complicato è un'impresa: adesso ci provo ma in genere è più facile obiettare il particolare caso sollevato da qualcuno.
Allora, il programma è concepito per rendere "democratico" il torneo o il campionato. Su grandi numeri, solo facendo estrazioni casuali tutti giocheremmo più o meno con tutti, tutti giocheremo lo stesso numero di volte al tavolo da 5 ecc. ecc. ma siccome il numero di turni di cui è composto un torneo o campionato non è certo grande (anche se ho appreso da te che fate un campionato di ben venti turni...) il programma interviene per inserire la suddetta democrazia pur lasciando un ampio fattore di casualità: praticamente in tutte le formule tranne quella del secondo turno del raduno nazionale e del Master, non può succedere sistematicamente che lanciando due volte lo stesso sorteggio escano due volte gli stessi tavoli.
Detto ciò, mi chiedi della modalità torneo Gufo che vede la composizione dei tavoli secondo questo ordine di priorità (qui copio direttamente dal programma)
codice:
switch (numeroTurno) {
case 1:
priorita.add(PrioritaSorteggio.IMPEDITO_STESSO_CLUB);
partiteTurno = GeneratoreTavoliNew.generaPartite(giocatoriPartecipanti, null, TipoTavoli.DA_4_ED_EVENTUALMENTE_DA_5, priorita);
break;
default:
// [..] Parte non interessante
priorita.add(PrioritaSorteggio.MINIMIZZAZIONE_PARTECIPAZIONE_TAVOLO_DA_5);
priorita.add(PrioritaSorteggio.IMPEDITO_STESSO_CLUB);
priorita.add(PrioritaSorteggio.MINIMIZZAZIONE_SCONTRI_DIRETTI);
partiteTurno = GeneratoreTavoliNew.generaPartite(giocatoriPartecipanti, partitePrecedenti, TipoTavoli.DA_4_ED_EVENTUALMENTE_DA_5, priorita);
break;
}
La sequenza è quindi questa:
- Vengono generati i tavoli vuoti in base alla particolare formula (che per il Torneo Gufo prevede tavoli da 4 e 5)
- tutti i giocatori vengono caricati e successivamente mischiati casualmente
- i giocatori iniziano ad essere aggiunti ad uno dei tavoli a sua volta scelto casualmente fino al loro completamento
- il programma inizia ad esaminare i vari tavoli per vedere se ci sono incompatibilità per i vari criteri: se le trova, scorre gli altri tavoli partendo dal primo e cerca di scambiare 2 giocatori per vedere se l'incompatibilità si riduce
- una volta finita con l'analisi per la prima incompatibilità si passa alla seconda e poi alla terza: ogni volta che viene provato uno scambio di giocatori viene anche controllato che non venga "peggiorata" la o le incompatibilità di livello superiore. Per chiarire questo punto posto un altro pezzo di codice
codice:
private static boolean verificaSeScambiabili(PrioritaSorteggio priorita, List<PrioritaSorteggio> listaPriorita, Partita partita1, GiocatoreDTO giocatore1, Partita partita2, GiocatoreDTO giocatore2, Partita[] partitePrecedenti){
/* Verifica che siano scambiabili in senso stretto per la Priorità che ho in canna*/
boolean siPossonoScambiare = checkCongruence(true, partita1, giocatore1, partita2, giocatore2, partitePrecedenti, priorita);
int indexOfPriority = listaPriorita.indexOf(priorita);
/* Se sono scambiabili per la priorità in canna, verifico che siano scambiabili in senso largo anche per quelle di livello superiore */
for (int index = indexOfPriority - 1; index >= 0 && siPossonoScambiare; index--){
siPossonoScambiare = checkCongruence(false, partita1, giocatore1, partita2, giocatore2, partitePrecedenti, listaPriorita.get(index));
}
return siPossonoScambiare;
}
Ora, il lavoro grosso che mi ha impegnato molto a livello intellettuale è chiaramente quello del punto 4: per ognuno dei criteri ho dovuto trovare sotto forma informatica la risposta alla seguente domanda: quando, in base a questo criterio, questo tavolo è meglio di quello di prima?
Il criterio del numero di volte al tavolo da 5 è il più semplice: conta il numero di volte che ognuno ha già giocato al tavolo da 5. Se io ho giocato due volte al tavolo da 5 e ci sono finito adesso casualmente per la terza volta e tu ci hai giocato una sola volta, il programma ci scambia. Potrebbe esserci qualcuno che non ci ha mai giocato e che quindi avrebbe ancora più "diritto" ad andarci ma...niente paura, il programma se ne accorge ed alla fine lo pesca. L'elaborazione di questo algoritmo fa quindi sì che vada al tavolo da 5 sempre chi ci ha giocato di meno ed un caso di parità di partecipazioni, interviene la casualità.
E' un criterio la cui bontà è anche facilmente controllabile in un torneo locale non molto numeroso.
Facciamo l'esempio di un torneo di 18 giocatori: saranno 2 tavoli da 4 e 2 da 5.
Quando verrà lanciato il secondo turno, gli 8 giocatori che hanno giocato al primo ai tavoli da 4 finiranno sicuramente ai due tavoli da 5 insieme a due malcapitati che se li dovranno sorbire una seconda volta. Al terzo turno, però i due malcapitati di cui sopra giocheranno sicuramente ad un tavolo da 4.
Tornando per un attimo al secondo turno, faccio notare che il portare 8 giocatori di due tavoli su altri due tavoli comporta che ci saranno 4 coppie di giocatori che si rincontreranno una seconda volta consecutiva: questo perchè pur essendoci anche il criterio di minimizzazione degli scontri diretti, quello della minimizzazione del numero di tavoli da 5 ha la precedenza.
Il criterio della separazione per club, di poca importanza in un torneo locale ma di grande in uno di rilevanza nazionale, conta per ogni tavolo il numero di combinazioni dei cosìddetti scontri diretti tra giocatori dello stesso club: se ce ne sono 2 allo stesso tavolo, c'è uno scontro, se ce ne sono 3, gli scontri sono 3, se ce ne sono 4, gli scontri sono 6: nel provare a scambiare con un giocatore di una altro tavolo (ed ovviamente di un altro club), il programma verifica che il totale di tutte queste combinazioni di entrambi i tavoli diminuisca.
Il criterio della minimizzazione degli scontri tra stessi giocatori conta per l'appunto quante volte quel giocatore ha già incontrato quell'altro e cerca di scambiare uno dei due con uno di un altro tavolo sempre verificando che il totale degli scontri diretti di tutti i giocatori su entrambi i tavoli dopo lo scambio sia minore di prima; anche in questo caso, come negli altri, il programma non si ferma mai al primo scambio "utile" ma trova sempre la miglior combinazione possibile per tutti i tavoli.