I assume that shuffle
is inside a class that represents a Deck
.
52 is a magic number. We could simply replace it by a constant variable with the name size
:
public final int size = 52;
public void shuffle() {
/* ... */
while(/* ... */) {
/* ... */
deck.add(rnd.nextInt(size), poke);
}
/* ... */
deck.add(rnd.nextInt(size), poke);
}
One important benefit is that we don't have to change 52
at multiple places if the size should change and typos can be avoided too.
Card poke = deck.get(0);
deck.remove(0);
This snipped can be simplified:
Card pole = deck.remove(0);
Extract SecureRandom
to the class scope to only create an instance of it once instead for every shuffle
invocation.
If you are interested in testing we should try to make shuffle
a pure functions, because they are easy to test. Since we depend on SecureRandom
and randomness makes a method impure we need to override the method nextInt
to return a constant value and inject it as a dependency:
class Test {
class MockedRandom extends SecureRandom {
int number;
MockedRandom(int number) { this.number = number; }
@Override
public int nextInt(int bound) {
return number;
}
}
@Test
void example() {
Deck deck = new Deck(new MockedRandom(5));
deck.shuffle();
assertThat(...)
}
}
A Deck
could contain besides suffle
methods like drawFromTop
, last
, remove
and addRandomly
to make the algorithm more readable:
public void shuffle() {
while (first().equalsNot(last())) {
addRandomly(drawFromTop());
}
addRandomly(drawFromBottom());
}
I do not know which data structure you use for deck
but if it is not an LinkedList
you should think if the operation deck.add(rnd.nextInt(52), poke);
could cause a performance issue for you.
class Deck {
private final SecureRandom rnd = new SecureRandom();
private final int size = 52;
private LinkedList<Card> deck;
public void shuffle() {
while (first().equalsNot(last())) {
addRandomly(drawFromTop());
}
addRandomly(drawFromBottom());
}
/**
* Adds card at a random position
*
* @param card to add
*/
private void addRandomly(Card card) {
deck.add(rnd.nextInt(size), card);
}
/**
* shows last card in the deck without to modify it
*/
public Card last() {
return deck.getFirst();
}
/**
* shows first card in the deck without to modify it
*/
public Card first() {
return deck.getLast();
}
/**
* removes first card from the deck and returns it
*/
public Card drawFromTop() {
return deck.removeFirst();
}
/**
* removes last card from the deck and returns it
*/
public Card drawFromBottom() {
return deck.removeLast();
}
}