Gere uma cor aleatória para cada usuário e mantenha o controle das cores criadas. Cada cor DEVE ser diferente

4

No meu aplicativo, todo usuário que se conecta ao servidor precisa obter uma cor distinta aleatória e eu preciso acompanhá-los. Cerca de 20 a 30 serão conectados ao mesmo tempo. Quando um usuário se desconecta, sua cor é descartada.

Minha pergunta é se fiz isso corretamente em relação ao desempenho e à segurança do 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();
}

EDITAR:

Obrigado a todos por sua ajuda e conselhos, você me ajudou muito sobre esse problema e eu também consegui aprender algumas coisas extras :) Já que a aleatoriedade não era realmente necessária, eu criaria apenas cerca de 60 cores aleatórias off-line e armazene-os em uma matriz ou em um dicionário e atribua-os aos usuários conforme necessário.

    
por Nikola.Lukovic 24.02.2016 / 12:30
fonte

4 respostas

3

É importante saber quantas cores distintas você tem disponíveis e quão distintas elas devem ser. Por exemplo, um usuário pode ter "amarelo pálido" e outro usuário ter "amarelo ligeiramente mais pálido"?

Se você pode ter muitas cores distintas, basta gerá-las usando um algoritmo determinístico, começando em 0,0,0 e trabalhando até 255,255,255 (isso dá 256 * 256 * 256 cores diferentes!). Se você precisa que as cores sejam mais distintas, você ainda pode usar o algoritmo fixo, mas usar um grande valor - por exemplo, incrementar o valor em 64 ao invés de 1 (o que lhe dá 256/64 ^ 3 ou 64 cores diferentes). p>

Depois de ter esse tipo de algoritmo, basta fornecer um número a cada usuário. Você terá que manter uma lista desses números, mas você pode manter um 'array booleano' de cada um ou simplesmente pesquisar todos os usuários que estiverem procurando o menor número não utilizado.

Como alternativa, calcule as cores off-line e armazene os valores em uma matriz. Cada usuário obtém um índice nesse array. Para um novo usuário, basta procurar em todos os usuários pelo próximo índice não utilizado ou armazenar um sinalizador "usado / gratuito" ao lado da cor e atualizar o array à medida que os usuários forem indo e vindo.

    
por 24.02.2016 / 12:47
fonte
16

Acredito que você esteja tornando isso um pouco difícil para você mesmo, junto com a possibilidade de gerar #ffffff e #fffffe como duas cores "distintas". No entanto, você não será capaz de perceber a diferença.

Tentar gerar uma nova cor na hora que seja visualmente diferente das outras cores é um desafio. É factível, mas desafiador - especialmente porque o sistema visual humano é não-linear (somos capazes de distinguir dois verdes diferentes que estão mais separados do que dois vermelhos diferentes).

E, portanto, não gere cores aleatórias durante o processo.

Faça uma lista de 50 ou 100 (você terá algumas dificuldades quando chegar a 100) cores aleatórias e apenas use um índice nessa lista. Cada vez que uma cor é liberada, coloque-a de volta no final da lista de cores a ser alocada.

Relacionados:

Na questão UX, os links nas próprias experiências são especialmente interessantes:

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.

    
por 24.02.2016 / 16:16
fonte
4

Você perguntou sobre segurança de thread. Absolutamente este código não é thread-safe. Os métodos de Random não são documentados como sendo seguros para chamar de vários encadeamentos e, na verdade, eles não são seguros. Veja

link

para detalhes.

Como eu disse no meu comentário, considere eliminar o requisito de aleatoriedade. Provavelmente você pode obter algum requisito bem menos oneroso.

    
por 24.02.2016 / 23:37
fonte
3

Em vez de usar List e lock , eu usaria ConcurrentDictionary com a cor sendo Key e o valor não utilizado (basta colocar algum lixo lá) (seria bom ter ConcurrentSet no .NET) e TryAdd e TryRemove métodos. Isso eliminará o bloqueio recursivo, tornando as coisas um pouco mais rápidas e previsíveis.

    
por 24.02.2016 / 12:40
fonte