현재 취미 프로젝트는 프랑스 데크 (52 장, 2에서 에이스까지)의 카드 게임에 대한 몬테카를로 시뮬레이션을 제공합니다.효율적으로 무작위로 세트 비트를 선택하는 방법
최대한 빨리 시뮬레이션하기 위해 일부 카드에서는 여러 개의 카드를 비트 마스크로 사용합니다. 여기에 몇 가지 (간체) 코드는 다음과 같습니다
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);
}
}
비트 마스크로 여러 개의 카드를 보유 구조 :
내가 두 번째 구조체 CardPool에서 무작위로 하나 이상의 카드를 그리려는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;
}
}
하지만, 나는 수영장에서 싱글 비트를 반복하지 않고 어떻게하는지 상상할 수 없다. 이것을 수행하는 알려진 알고리즘이 있습니까? 그렇지 않다면이 일을 빨리 할 생각이 있습니까?
업데이트 : 이 구조는 모든 카드를 꺼내기위한 것이 아닙니다. 그것은 자주 복제되고 배열을 복제하는 것은 선택 사항이 아닙니다. 나는 하나 또는 여러 장의 카드를 그리기위한 비트 연산을 정말로 생각합니다.
업데이트 2 : 비교를 위해 카드를 List로 유지하는 클래스를 작성했습니다. 17 MS - 클래스 : 73 MS 합격자
: 차이는 생각만큼되지 않습니다 - 구조체 :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 복제 작업을 비교. 그러나 미리 계산 된 값을 쉽게 찾아 볼 수 있다는 점을 감안하면 큰 차이가 있습니다. 물론이 클래스를 사용하여 임의의 카드를 그리는 것이 더 빠르지 만 조회를위한 색인을 계산해야합니다. 그러면 문제를 다른 지점으로 전송하는 것입니다.
초기 질문을 반복하십시오. : 정수 값에서 임의의 비트 세트를 선택하는 알려진 알고리즘이 있습니까? 아니면 모든 비트를 반복하는 것보다 빠르게 수행하는 아이디어가 있습니까?
List 또는 Array와 함께 클래스를 사용하는 것에 대한 설명은 우리를 아무 곳에도 데려가 지 않습니다. 이것은 제 질문이 아니며 수업을 사용하는 것이 더 나을지 모르겠다면 스스로 정교 할 수 있습니다.
갱신 3, 조회 코드 : 삭제
CODE : 그것은 성능이 스레드의 대상이 무엇을 앓고 구절을 참조하지 않기 때문에 오해의 소지가있을 수 있습니다.
정확하게 이해하면 52 비트 숫자에서 임의의 비트 세트를 가져와서 제거하고 싶습니다. 여러 번 연속해서하고 싶습니까? 아니면 숫자가 두 번에 걸쳐 다른 방식으로 바뀌나요? 또한, (최대) 52 개의 카드 배열을 만드는 것이 어떻습니까? 그것은 사용하는 것이 더 실용적 일 것입니다. – Nelfeal
배열은 더 실용적 일 것이지만, 정확하지만 성능이 떨어지며 사전에 계산 된 값을 찾기 위해 사전에 색인으로 ulong을 사용합니다. –
동일한 절차에서 반드시 제거해야하는 것은 아니지만 예, 52 비트 숫자에서 임의의 비트를 가져 오려고합니다. 이상적으로는 계속 노력하고 있습니다. –