Genera un colore casuale per ogni utente e tiene traccia dei colori creati. Ogni colore deve essere diverso

4

Nella mia app ogni utente che si connette al server deve ottenere un colore distinto a caso e devo tenerne traccia. Circa 20 a 30 saranno collegati nello stesso tempo. Quando un utente si disconnette, il suo colore viene rimosso.

La mia domanda è se l'ho fatto correttamente per quanto riguarda le prestazioni e la sicurezza dei thread.

public class RandomColorGenerator
{
    private static IList<Color> currentColors = new List<Color>();
    private static Random random = new Random((int)DateTime.UtcNow.Ticks);
    private object lockObject = new object();

    public Color GetRandomColor ( )
    {
        var color = Color.FromArgb(random.Next(200, 255), random.Next(150, 255), random.Next(150, 255));
        lock ( lockObject )
        {
            if ( currentColors.Contains(color, new ColorEqualityComparer()) )
                return GetRandomColor();
            else
                {
                    currentColors.Add(color);
                    return color;
                }
        }
    }

    public void DismissRandomColor (Color color)
    {
        lock ( lockObject )
        {
            var tmpColor = currentColors.SingleOrDefault(x=>x.ToArgb() == color.ToArgb());
            currentColors.Remove(tmpColor);
        }
    }
}


public class ColorEqualityComparer : IEqualityComparer<System.Drawing.Color>
{
    public bool Equals (Color x, Color y) => x.ToArgb() == y.ToArgb();

    public int GetHashCode (Color obj) => obj.GetHashCode();
}

EDIT:

Grazie a tutti per il vostro aiuto e i vostri consigli, mi avete aiutato molto su questo problema e sono anche riuscito a imparare un paio di cose extra :) Dato che la casualità non era davvero necessaria, creerò solo circa 60 colori casuali offline e memorizzarli in un array o in un dizionario e assegnarli agli utenti in base alle esigenze.

    
posta Nikola.Lukovic 24.02.2016 - 12:30
fonte

4 risposte

3

È importante sapere quanti colori distinti hai a disposizione e quanto devono essere distinti. Ad esempio, un utente può avere "giallo pallido" e un altro utente ha "un giallo leggermente più chiaro"?

Se puoi avere molti colori distinti, generali semplicemente usando un algoritmo deterministico, partendo da 0,0,0 e lavorando fino a 255,255,255 (questo ti dà 256 * 256 * 256 colori diversi!). Se hai bisogno che i colori siano più distinti, puoi comunque utilizzare l'algoritmo fisso ma utilizzare un grande valore di passo - ad esempio incrementare il valore di 64 anziché 1 (che ti dà 256/64 ^ 3 invece o 64 colori diversi).

Una volta che hai questo tipo di algoritmo devi solo dare a ciascun utente un numero. Dovrai mantenere un elenco di questi numeri ma puoi mantenere un "array booleano" di ognuno o semplicemente cercare tra tutti gli utenti che cercano il numero inutilizzato più piccolo.

In alternativa, calcola i colori offline e memorizza i valori in una matrice. Ogni utente ottiene un indice in quella matrice. Per un nuovo utente è sufficiente consultare tutti gli utenti per il prossimo indice non utilizzato oppure memorizzare una bandiera "used / free" accanto al colore e aggiornare la matrice man mano che gli utenti vanno e vengono.

    
risposta data 24.02.2016 - 12:47
fonte
16

Credo che lo stiate facendo un po 'troppo duro con voi stessi, insieme alla possibilità di generare #ffffff e #fffffe come due colori "distinti". Tuttavia, non sarai in grado di percepire la differenza.

Cercare di generare un nuovo colore al volo che sia visivamente diverso dagli altri colori è impegnativo. È fattibile, ma impegnativo, soprattutto perché il sistema visivo umano non è lineare (siamo in grado di distinguere due diversi green che sono più strettamente separati rispetto a due rossi diversi).

E così, non generare colori casuali al volo.

Fai una lista di 50 o 100 (avrai qualche difficoltà quando arrivi a 100) colori casuali e usa semplicemente un indice in quella lista. Ogni volta che viene rilasciato un colore, rimettilo alla fine dell'elenco di colori da assegnare.

Related:

Nella domanda UX, i collegamenti all'interno dei propri esperimenti sono particolarmente interessanti:

I have done my own investigations into this and come up with a page for generating a set of colors with user-specifiable visual separation.

    
risposta data 24.02.2016 - 16:16
fonte
4

Hai chiesto informazioni sulla sicurezza dei thread. Assolutamente questo codice non è thread-safe. I metodi di Random non sono documentati come sicuri da chiamare da più thread, e in effetti non sono sicuri. Vedere

link

per i dettagli.

Come ho detto nel mio commento, prendere in considerazione la possibilità di abbandonare il requisito di casualità. Probabilmente puoi cavartela con requisiti molto meno onerosi.

    
risposta data 24.02.2016 - 23:37
fonte
3

Invece di usare List e lock , userei ConcurrentDictionary con colore che è Key e valore inutilizzato (basta mettere qualche junk in là) (sarebbe bello avere ConcurrentSet in .NET) e TryAdd e TryRemove metodi. Questo eliminerà il blocco ricorsivo, renderà le cose leggermente più veloci e prevedibili.

    
risposta data 24.02.2016 - 12:40
fonte

Leggi altre domande sui tag