web-dev-qa-db-ja.com

すべてのユーザーに対してランダムな色を生成し、作成された色を追跡します。すべての色は異なる必要があります

私のアプリでは、サーバーに接続するすべてのユーザーがランダムに異なる色を取得する必要があり、それらを追跡する必要があります。同時に20〜30本程度接続されます。ユーザーが切断すると、彼の色は消えます。

私の質問は、パフォーマンスとスレッドセーフティに関してこれを正しく行ったかどうかです。

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();
}

編集:

あなたの助けとアドバイスをありがとう、あなたはこの問題について私をたくさん助けてくれました、そして私はいくつかの余分なものを学ぶこともできました:)ランダムさは本当に必要ではなかったので、オフラインで約60のランダムな色を作成して保存しますそれらを配列または辞書に入れ、必要に応じてユーザーに割り当てるだけです。

4
Nikola.Lukovic

使用できる明確な色の数と、それらの明確さを知ることは重要です。たとえば、あるユーザーが「淡い黄色」を使用し、別のユーザーが「わずかに薄い黄色」を使用することはできますか?

多くの異なる色を使用できる場合は、決定論的アルゴリズムを使用してそれらを生成し、0,0,0から255,255,255まで作業します(これにより256 * 256 * 256の異なる色が得られます!)。色をより明確にする必要がある場合でも、固定アルゴリズムを使用できますが、大きなステッピング値を使用します。たとえば、値を1ではなく64増やします(これにより、256/64 ^ 3または64の異なる色が得られます)。

この種のアルゴリズムを取得したら、各ユーザーに番号を与えるだけです。これらの数値のリストを維持する必要がありますが、各数値の「ブール配列」を保持するか、すべてのユーザーを検索して未使用の最小の数値を探すことができます。

または、オフラインで色を計算し、値を配列に格納します。各ユーザーはその配列へのインデックスを取得します。新規ユーザーの場合は、すべてのユーザーを調べて次の未使用のインデックスを探すか、「使用済み/無料」のフラグを色と一緒に保存し、ユーザーの出入りに応じて配列を更新します。

3
gbjbaanb

私はあなたがこれをあなた自身に少し難しくしていると信じています-#ffffff#fffffeを2つの「異なる」色として生成する可能性とともに。ただし、違いを認識することはできません。

他の色と視覚的に区別できる新しい色をその場で生成しようとすることは困難です。実行可能ですが、挑戦的です-特に人間の視覚システムは非線形です(2つの異なる赤よりも近くにある2つの異なる緑を区別できます)。

したがって、その場でランダムな色を生成しないでください。

50または100のリスト(100になるといくつかの困難があります)のランダムな色を作成し、そのリストへのインデックスを使用します。色が解放されるたびに、割り当てられる色のリストの最後に戻します。

関連:

UXの質問では、独自の実験内のリンクが特に興味深いです。

私は 自分自身調査これに を実行し、ユーザーと一連の色を生成するために ページ を考え出しました-指定可能な視覚的分離。

16
user40980

スレッドセーフについて質問しました。絶対にこのコードはスレッドセーフではありません。 Randomのメソッドは、複数のスレッドから安全に呼び出すことができると文書化されておらず、実際には安全ではありません。見る

http://blogs.msdn.com/b/pfxteam/archive/2009/02/19/9434171.aspx

詳細については。

コメントで述べたように、ランダム性の要件を削除することを検討してください。おそらく、それほど面倒ではない要件でうまくいくでしょう。

4
Eric Lippert

Listlockを使用する代わりに、 ConcurrentDictionary を使用し、色をKey、値を未使用にします(ジャンクをそこに入れるだけです)(ConcurrentSet in .NET)および TryAdd および TryRemove メソッド。これにより、再帰的なロックがなくなり、処理が少し速くなり、予測可能になります。

3
Euphoric