2015-06-10 30 views
5

Sam napisałem tę metodę, chcę wiedzieć, czy jest lepszy sposób na zrobienie tego?Java: przetasuj talię 32 kart?

public Card[] shuffle(){ 
    for(int i = 0; i < Deck.length; i++){ 
     int x = i + (int) (Math.random() * (32 - i)); 
     Card temp = Deck[i]; 
     Deck[i] = Deck[x]; 
     Deck[x] = temp; 
    } 
    return Deck; 
} 
+6

' Collections.shuffle (convertArrayToCollectionHere) ' –

+2

Nie wygląda zbyt źle. Oprócz oczywistej alternatywy, która została już wskazana, polecam przyjąć konwencje nazewnictwa Java i używać małych liter dla metod i nazw zmiennych. –

+0

@jangroth dzięki za poradę. –

Odpowiedz

-1

Myślę, że można uzyskać lepsze rezultaty, jeśli wybrać element, który ma być wymieniane z całej talii, a nie tylko od pozostałych kart, tak:

public Card[] Shuffle(){ 
    for(int i = 0; i < Deck.length; i++){ 
     int x = (int) (Math.random() * 32); 
     Card temp = Deck[i]; 
     Deck[i] = Deck[x]; 
     Deck[x] = temp; 
    } 
    return Deck; 
} 
+2

Co zaskakujące, wybranie karty z pełnego zakresu jest w rzeczywistości gorsze. [Here] (http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Potential_sources_of_bias) to dobra dyskusja na temat błędów implementacji; używanie pełnego zakresu jest częstym problemem. – dasblinkenlight

+0

@dasblinkenlight Zaskakująco, istotnie. Dziękuję za wskazanie tego. –

+0

Może to prowadzić do złego przetasowania, co oznacza, że ​​losowa liczba może nigdy nie wybrać niektórych kart z talii. –

2

nie możliwość sprawdzenia, czy (32 - i) zawsze daje dowolną wartość mniejszą niż 0. Algorytm nazywa Fisher-Yates tasowania algorytmu, które przypominają bardzo podobny do Ciebie:

private int [] shuffleMyArray (int [] array) { 
    int size = array.length, i = 0; 
    int temp = 0; 
    while (size != 0) { 
     i = ((int) (Math.random() * size--)); 
     if (i < 0) { 
      i = 0; 
     } 
     temp = array [ size ]; 
     array [ size ] = array [ i ]; 
     array [ i ] = temp; 
    } 
    return array; 
} 

EDIT 1:

Wyjście obu algorytmów będzie lepiej Ci zrozumieć różnicę między nimi, zobaczyć, jak Fisher-Yates weź pod uwagę wszystkie indeksy, podczas tasowania.

WYJŚCIE:

Actual Array 
0 1 2 3 4 
Your Implementation output 
i: 0 x: 3 
i: 1 x: 4 
i: 2 x: 3 
i: 3 x: 4 
i: 4 x: 4 
Fisher Yates implementation output 
i: 4 size: 4 
i: 2 size: 3 
i: 1 size: 2 
i: 0 size: 1 
i: 0 size: 0 
+1

Tutaj znalazłem bardzo dobrą stronę do nauki takich [algorytmów] (http://bost.ocks.org/mike/algorithms/#shuffling) –

+1

Tak, masz rację, nie sprawdziłem. Czy możesz wyjaśnić, dlaczego powinienem? Najwyraźniej nigdy nie będzie mniej niż zero. –

+1

@ HaroutTatarian: Jesteś w tym prawdziwy. Nigdy nie patrzyłem tak dokładnie w tym ograniczonym czasie, gdy szykowałem się do wyjścia do pracy. Teraz, odkąd tu przybyłem, udało mi się dostarczyć wam dane wyjściowe obu algorytmów, tylko po to, aby sprawdzić, w jaki sposób obie metody przyjmują różne wskaźniki do zamiany. Opcja ta jest wystarczająco opisowa, aby odróżnić, które podejście jest bardziej wydajne. –

1

Zamierzam uczynić deck argument, a metoda static. W ten sposób jest samowystarczalny. W języku Java konwencje nazewnictwa powodują, że zmienne i nazwy metod zaczynają się od małej litery. Następnie najkrótsza droga wiem jest shuffle pokładu w miejscu Collections.shuffle(List) i Arrays.asList(T...) jak

public static void shuffle(Card[] deck) { 
    Collections.shuffle(Arrays.asList(deck)); 
} 

Jeśli chcesz zachować oryginalny deck, a następnie można go skopiować i return jak

public static Card[] shuffle(Card[] deck) { 
    List<Card> al = new ArrayList<>(Arrays.asList(deck)); 
    Collections.shuffle(al); 
    return al.toArray(new Card[deck.length]); 
}