私の現在の趣味プロジェクトは、フランス語デッキ(52枚、エースから52枚まで)のカードゲームのモンテカルロシミュレーションを提供しています。効率的にセットビットをランダムに選択する
可能な限り高速にシミュレーションするために、複数のカードをいくつかの箇所でビットマスクとして表現しています。ここではいくつかの(簡体字)のコードは次のとおりです。
public struct Card
{
public enum CardColor : byte { Diamonds = 0, Hearts = 1, Spades = 2, Clubs = 3 }
public enum CardValue : byte { Two = 0, Three = 1, Four = 2, Five = 3, Six = 4, Seven = 5, Eight = 6, Nine = 7, Ten = 8, Jack = 9, Queen = 10, King = 11, Ace = 12 }
public CardColor Color { get; private set; }
public CardValue Value { get; private set; }
// ID provides a unique value for each card, ranging from 0 to 51, from 2Diamonds to AceClubs
public byte ID { get { return (byte)(((byte)this.Value * 4) + (byte)this.Color); } }
// --- Constructors ---
public Card(CardColor color, CardValue value)
{
this.Color = color;
this.Value = value;
}
public Card(byte id)
{
this.Color = (CardColor)(id % 4);
this.Value = (CardValue)((id - (byte)this.Color)/4);
}
}
ビットマスクとして複数のカードを保持する構造体:
私は2番目の構造体 CardPoolからランダムに1枚以上のカードを描きたいpublic struct CardPool
{
private const ulong FULL_POOL = 4503599627370495;
internal ulong Pool { get; private set; } // Holds all cards as set bit at Card.ID position
public int Count()
{
ulong i = this.Pool;
i = i - ((i >> 1) & 0x5555555555555555);
i = (i & 0x3333333333333333) + ((i >> 2) & 0x3333333333333333);
return (int)((((i + (i >> 4)) & 0xF0F0F0F0F0F0F0F) * 0x101010101010101) >> 56);
}
public CardPool Clone()
{
return new CardPool() { Pool = this.Pool };
}
public void Add(Card card)
{
Add(card.ID);
}
public void Add(byte cardID)
{
this.Pool = this.Pool | ((ulong)1 << cardID);
}
public void Remove(Card card)
{
Remove(card.ID);
}
public void Remove(byte cardID)
{
this.Pool = this.Pool & ~((ulong)1 << cardID);
}
public bool Contains(Card card)
{
ulong mask = ((ulong)1 << card.ID);
return (this.Pool & mask) == mask;
}
// --- Constructor ---
public CardPool(bool filled)
{
if (filled)
this.Pool = FULL_POOL;
else
this.Pool = 0;
}
}
が、私はプール内の単一のビットを反復せずにそれを行う方法を想像することはできません。 これを実現するアルゴリズムはありますか?もしそうでなければ、これを速くする考えはありますか?
更新: この構造体は、すべてのカードを引き出すものではありません。それは頻繁にクローンされ、アレイのクローン作成はオプションではありません。私は実際に1つまたは複数のカードを描くためのビット操作を考える。
更新2: 私は、比較のためにカードをListとして保持するクラスを作成しました。 17ミリ秒 - クラス:73ミリ入所
:違いは、私が思ったほどあまりないです - 構造体 :public class CardPoolClass
{
private List<Card> Cards;
public void Add(Card card)
{
this.Cards.Add(card);
}
public CardPoolClass Clone()
{
return new CardPoolClass(this.Cards);
}
public CardPoolClass()
{
this.Cards = new List<Card> { };
}
public CardPoolClass(List<Card> cards)
{
this.Cards = cards.ToList();
}
}
フルデッキの1.000.000クローン操作を比較します。 しかし、あらかじめ計算された値の簡単な検索をあきらめていることを考慮に入れると、これは大きな違いになります。 もちろん、このクラスではランダムなカードを描く方が速いでしょうが、別の場所に問題を転送するだけのルックアップのためのインデックスを計算する必要があります。
私は私の最初の質問繰り返し:これはすべてのビットを反復処理するよりも早く行って取得するためのアイデアを整数値からランダムにセットされたビットを選択するか、誰かを持っているため、既知のアルゴリズムはありますか?
リストや配列でクラスを使うことについての議論はどこにもわかりませんが、これは私の質問ではなく、クラスを使う方が良いと自分で説明することができます。
Update3と、ルックアップコード:
CODE DELETED:それは、スレッドの対象が何であるかに苦しんでいるパフォーマンスの通路を参照していないので、これは誤解を招くかもしれません。
私が正しく理解している場合は、52ビットの数値からランダムなセットビットを取得(および削除)したいと考えています。あなたはそれを何回も連続してやりたいのですか、あるいはその数が2つのドローの間で別の方法で変わるのですか?また、(最大)52枚のカードを並べるだけではどうですか?それはより実用的です。 – Nelfeal
配列はより実用的で、正確ですが、パフォーマンスは低くなります。さらに、ulongを辞書のインデックスとして使用して、事前計算された値を検索します。 –
同じ手順で必ずしも削除する必要はありませんが、はい、52ビットの数値からランダムなビットを取得します。理想的には連続して作業する。 –