2014-04-30 1 views
4

내 응용 프로그램에서 카드 덱을 섞어 쓰려고하는데 다음 코드를 사용합니다. 갑판을 충분히 무작위화할 수 있습니까? 나는 거의 확실하다. 단지 다른 의견을 원할 것이다. 감사!카드 덱을 섞을 수있는 충분한 방법입니까?

for (int i = 0; i < 40000; i++) { 
    int randomInt1 = arc4random() % [deck.cards count]; 
    int randomInt2 = arc4random() % [deck.cards count]; 
    [deck.cards exchangeObjectAtIndex:randomInt1 withObjectAtIndex:randomInt2]; 

편집 : 향후 궁금한 점이 있거나 앞으로 다가올 경우가 있습니다. 이것이 제가 카드 더미를 뒤섞기 위해 사용했던 것입니다. 피셔 - 예이츠 알고리즘을 구현 한 것입니다. 포스트 @MartinR 여기에서 찾을 수있는 아래의 제안에서 나는 그것을 가지고 : [deck.cards 계산] 경우 What's the Best Way to Shuffle an NSMutableArray?

NSUInteger count = [deck.cards count]; 
    for (uint i = 0; i < count; ++i) 
    { 
     // Select a random element between i and end of array to swap with. 
     int nElements = count - i; 
     int n = arc4random_uniform(nElements) + i; 
     [deck.cards exchangeObjectAtIndex:i withObjectAtIndex:n]; 
    } 
+2

참조 http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle – Matt

+2

두 개선 - 1) 스토어'돈 당신 때문에 루프 전에 변수에'[deck.cards 계산] 그 방법을 8 만 번 호출해야합니다. 2) 모듈러스가있는'arc4random' 대신'arc4random_uniform (count)'를 사용하십시오. – rmaddy

+1

* "갑판을 충분히 랜덤화할 수 있습니까?"*는 확률 이론의 전문가에게 더 수학적인 질문입니다. NSArray에 대한 Fisher-Yates 알고리즘의 구현은 다음과 같이 찾을 수 있습니다. [NSMutableArray를 섞는 가장 좋은 방법은 무엇입니까?] (http://stackoverflow.com/questions/56648/whats-the-best-way- to-shuffle-an-nsmutablearray). –

답변

7

귀하의 코드가 < 40000 그러나 다음과 같은 더 나은 오히려 잘 작동합니다

for (int i = [deck.cards count] - 1; i > 0 ; i--) { 
    int randomInt1 = arc4random_uniform(i + 1); 
    [deck.cards exchangeObjectAtIndex:randomInt1 withObjectAtIndex:i]; 
} 

docs :

arc4random_uniform()은 균일하게 분산 된 난수 보다 upper_bound보다 작은 값을 반환합니다. 상한이 2의 거듭 제곱이 아닌 경우 "모듈로 바이어스"를 피하기 때문에 arc4random_uniform()이 "arc4random() % upper_bound"와 같은 구성보다 권장됩니다.

+0

앞으로 바꾸는 이유는 무엇입니까? –

+0

@GuyKogus는 추가 계산없이 'arc4random_uniform'을 사용합니다. – Avt

+0

이것은 올바른 구현이 아닙니다. 내 대답을 참조하십시오. –

3

여기 구현 된 Fisher-Yates 알고리즘이 있습니다. 그리고 네, 배열을 충분히 랜덤화할 것입니다. 여러 번 사용 했으므로 훌륭합니다!

NSUInteger count = [deck.cards count]; 
if (count > 0) { 
    for (NSUInteger i = count - 1; i > 0 ; --i) { 
     [deck.cards exchangeObjectAtIndex:i 
         withObjectAtIndex:arc4random_uniform(i + 1)]; 
    } 
} 
+0

FY 알고리즘 세부 정보를 다시 읽으면 이것이 동일하지 않다는 것을 알게됩니다. 그러나 그것은 여전히 ​​매우 잘 작동합니다. –

+4

이 방법을 셔플 링하는 것은 실제로 미묘한 문제가 있으므로 "여전히 잘 작동합니다"라고 말하지는 않습니다. 참조 : [Naveté의 위험] (http://blog.codinghorror.com/the-danger-of-naivete/). 정확한 FY 셔플은 이것을 피합니다. – Blastfurnace

+3

항상 전체 범위에 걸쳐 색인으로 교체하라는 제안은 실제로 관찰 가능한 편향을 가져옵니다. 피셔 - 예이츠 (Fisher-Yates) 페이지의 [구현 오류] (http://en.wikipedia.org/wiki/Fisher-Yates_shuffle#Implementation_errors) 섹션에서 "모든 반복에서 유효한 배열 인덱스의 전체 범위에서 항상 j를 선택합니다. 비록 그렇게 명확하지는 않지만 편파적 인 결과를 낳는다. " 나는 몬테 카를로프의 대답과 너의 것 모두를 소개했고, 너의 편견은별로 중요하지 않았다. (비록 네가 거기에 앉아 있었다면 알아 차릴 지 모르겠지만 앱 딜 카드를 보았다.) – Rob