Card shuffles: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|Java}}: Add instructions for making the riffle shuffle "perfect")
(consistently use a single global Random object)
Line 13: Line 13:
import java.util.List;
import java.util.List;
import java.util.Random;
import java.util.Random;

public class CardShuffles{
public class CardShuffles{

private static final Random rand = new Random();

public static <T> LinkedList<T> riffleShuffle(List<T> list, int flips){
public static <T> LinkedList<T> riffleShuffle(List<T> list, int flips){
LinkedList<T> newList = new LinkedList<T>();
LinkedList<T> newList = new LinkedList<T>();

newList.addAll(list);
newList.addAll(list);

for(int n = 0; n < flips; n++){
for(int n = 0; n < flips; n++){
//cut the deck at the middle +/- 10%, remove the second line of the formula for perfect cutting
//cut the deck at the middle +/- 10%, remove the second line of the formula for perfect cutting
int cutPoint = newList.size() / 2
int cutPoint = newList.size() / 2
+ (Math.random() >= 0.5 ? -1 : 1 ) * (new Random()).nextInt((int)(newList.size() * 0.1));
+ (rand.nextBoolean() ? -1 : 1 ) * rand.nextInt((int)(newList.size() * 0.1));

//split the deck
//split the deck
List<T> left = new LinkedList<T>();
List<T> left = new LinkedList<T>();
Line 31: Line 33:
List<T> right = new LinkedList<T>();
List<T> right = new LinkedList<T>();
right.addAll(newList.subList(cutPoint, newList.size()));
right.addAll(newList.subList(cutPoint, newList.size()));

newList.clear();
newList.clear();

while(left.size() > 0 && right.size() > 0){
while(left.size() > 0 && right.size() > 0){
//allow for imperfect riffling so that more than one card can come form the same side in a row
//allow for imperfect riffling so that more than one card can come form the same side in a row
//biased towards the side with more cards
//biased towards the side with more cards
//remove the if and else and brackets for perfect riffling
//remove the if and else and brackets for perfect riffling
if(Math.random() >= ((double)left.size() / right.size()) / 2){
if(rand.nextDouble() >= ((double)left.size() / right.size()) / 2){
newList.add(right.remove(0));
newList.add(right.remove(0));
}else{
}else{
Line 44: Line 46:
}
}
}
}

//if either hand is out of cards then flip all of the other hand to the shuffled deck
//if either hand is out of cards then flip all of the other hand to the shuffled deck
if(left.size() > 0) newList.addAll(left);
if(left.size() > 0) newList.addAll(left);
Line 51: Line 53:
return newList;
return newList;
}
}

public static <T> LinkedList<T> overhandShuffle(List<T> list, int passes){
public static <T> LinkedList<T> overhandShuffle(List<T> list, int passes){
LinkedList<T> mainHand = new LinkedList<T>();
LinkedList<T> mainHand = new LinkedList<T>();

mainHand.addAll(list);
mainHand.addAll(list);
for(int n = 0; n < passes; n++){
for(int n = 0; n < passes; n++){
LinkedList<T> otherHand = new LinkedList<T>();
LinkedList<T> otherHand = new LinkedList<T>();

while(mainHand.size() > 0){
while(mainHand.size() > 0){
//cut at up to 20% of the way through the deck
//cut at up to 20% of the way through the deck
int cutSize = (new Random()).nextInt((int)(list.size() * 0.2)) + 1;
int cutSize = rand.nextInt((int)(list.size() * 0.2)) + 1;

LinkedList<T> temp = new LinkedList<T>();
LinkedList<T> temp = new LinkedList<T>();

//grab the next cut up to the end of the cards left in the main hand
//grab the next cut up to the end of the cards left in the main hand
for(int i = 0; i < cutSize && mainHand.size() > 0; i++){
for(int i = 0; i < cutSize && mainHand.size() > 0; i++){
temp.add(mainHand.remove());
temp.add(mainHand.remove());
}
}

//add them to the cards in the other hand, sometimes to the front sometimes to the back
//add them to the cards in the other hand, sometimes to the front sometimes to the back
if(Math.random() >= 0.1){
if(rand.nextDouble() >= 0.1){
//front most of the time
//front most of the time
otherHand.addAll(0, temp);
otherHand.addAll(0, temp);
Line 79: Line 81:
}
}
}
}

//move the cards back to the main hand
//move the cards back to the main hand
mainHand = otherHand;
mainHand = otherHand;
Line 85: Line 87:
return mainHand;
return mainHand;
}
}

public static void main(String[] args){
public static void main(String[] args){
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
Line 91: Line 93:
list = riffleShuffle(list, 10);
list = riffleShuffle(list, 10);
System.out.println(list + "\n");
System.out.println(list + "\n");

list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
System.out.println(list);
System.out.println(list);
list = riffleShuffle(list, 1);
list = riffleShuffle(list, 1);
System.out.println(list + "\n");
System.out.println(list + "\n");

list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
System.out.println(list);
System.out.println(list);
list = overhandShuffle(list, 10);
list = overhandShuffle(list, 10);
System.out.println(list + "\n");
System.out.println(list + "\n");

list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
System.out.println(list);
System.out.println(list);
list = overhandShuffle(list, 1);
list = overhandShuffle(list, 1);
System.out.println(list + "\n");
System.out.println(list + "\n");

list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
System.out.println(list);
System.out.println(list);

Revision as of 08:11, 4 May 2015

Card shuffles is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

There are many techniques that people use to shuffle cards for card games. Some are more effective than others.

The task here is to implement the (seemingly) more common techniques of the riffle shuffle and overhand shuffle for n iterations. Implementing playing cards is not necessary if it would be easier to implement these shuffling methods for generic collections. Where possible, compare this to a standard/built-in shuffling procedure.

Bonus: Implement other methods described here. Allow for "human errors" of imperfect cutting and interleaving.

Java

Works with: Java version 1.5+

<lang java5>import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Random;

public class CardShuffles{

private static final Random rand = new Random();

public static <T> LinkedList<T> riffleShuffle(List<T> list, int flips){ LinkedList<T> newList = new LinkedList<T>();

newList.addAll(list);

for(int n = 0; n < flips; n++){ //cut the deck at the middle +/- 10%, remove the second line of the formula for perfect cutting int cutPoint = newList.size() / 2 + (rand.nextBoolean() ? -1 : 1 ) * rand.nextInt((int)(newList.size() * 0.1));

//split the deck List<T> left = new LinkedList<T>(); left.addAll(newList.subList(0, cutPoint)); List<T> right = new LinkedList<T>(); right.addAll(newList.subList(cutPoint, newList.size()));

newList.clear();

while(left.size() > 0 && right.size() > 0){ //allow for imperfect riffling so that more than one card can come form the same side in a row //biased towards the side with more cards //remove the if and else and brackets for perfect riffling if(rand.nextDouble() >= ((double)left.size() / right.size()) / 2){ newList.add(right.remove(0)); }else{ newList.add(left.remove(0)); } }

//if either hand is out of cards then flip all of the other hand to the shuffled deck if(left.size() > 0) newList.addAll(left); if(right.size() > 0) newList.addAll(right); } return newList; }

public static <T> LinkedList<T> overhandShuffle(List<T> list, int passes){ LinkedList<T> mainHand = new LinkedList<T>();

mainHand.addAll(list); for(int n = 0; n < passes; n++){ LinkedList<T> otherHand = new LinkedList<T>();

while(mainHand.size() > 0){ //cut at up to 20% of the way through the deck int cutSize = rand.nextInt((int)(list.size() * 0.2)) + 1;

LinkedList<T> temp = new LinkedList<T>();

//grab the next cut up to the end of the cards left in the main hand for(int i = 0; i < cutSize && mainHand.size() > 0; i++){ temp.add(mainHand.remove()); }

//add them to the cards in the other hand, sometimes to the front sometimes to the back if(rand.nextDouble() >= 0.1){ //front most of the time otherHand.addAll(0, temp); }else{ //end sometimes otherHand.addAll(temp); } }

//move the cards back to the main hand mainHand = otherHand; } return mainHand; }

public static void main(String[] args){ List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); System.out.println(list); list = riffleShuffle(list, 10); System.out.println(list + "\n");

               list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);

System.out.println(list); list = riffleShuffle(list, 1); System.out.println(list + "\n");

list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); System.out.println(list); list = overhandShuffle(list, 10); System.out.println(list + "\n");

               list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);

System.out.println(list); list = overhandShuffle(list, 1); System.out.println(list + "\n");

list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); System.out.println(list); Collections.shuffle(list); System.out.println(list + "\n"); } }</lang>

Output:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[20, 11, 1, 9, 15, 4, 19, 16, 8, 13, 7, 2, 14, 12, 10, 3, 17, 18, 6, 5]

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[1, 12, 2, 3, 4, 5, 13, 14, 15, 6, 16, 7, 8, 9, 17, 18, 10, 19, 20, 11]

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[20, 3, 10, 4, 2, 8, 1, 18, 13, 19, 14, 6, 9, 12, 16, 15, 5, 7, 11, 17]

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[18, 19, 20, 17, 13, 14, 15, 16, 9, 10, 11, 12, 8, 6, 7, 3, 4, 5, 1, 2]

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[18, 12, 13, 14, 2, 3, 15, 5, 9, 19, 7, 11, 1, 6, 4, 20, 16, 17, 10, 8]