How to "shuffle" an array? [duplicate] - java

This question already has answers here:
Random shuffling of an array
(31 answers)
Closed 5 years ago.
I am having a tough time trying to create a "shuffleDeck()" method.
What I am trying to do is create a method that will take an array parameter (which will be the deck of cards) shuffle the cards, and return the shuffled array list.
This is the code:
class Card
{
int value;
String suit;
String name;
public String toString()
{
return (name + " of " + suit);
}
}
public class PickACard
{
public static void main( String[] args)
{
Card[] deck = buildDeck();
// display Deck(deck);
int chosen = (int)(Math.random()* deck.length);
Card picked = deck[chosen];
System.out.println("You picked a " + picked + " out of the deck.");
System.out.println("In Blackjack your card is worth " + picked.value + " points.");
}
public static Card[] buildDeck()
{
String[] suits = {"clubs", "diamonds", "hearts", "spades" };
String[] names = {"ZERO", "ONE", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "Jack", "Queen", "King", "Ace" };
int i = 0;
Card[] deck = new Card[52];
for ( String s: suits )
{
for ( int v = 2; v<=14; v++)
{
Card c = new Card();
c.suit = s;
c.name = names[v];
if ( v == 14)
c.value = 11;
else if ( v>10)
c.value = 10;
else
c.value = v;
deck[i] = c;
i++;
}
}
return deck;
}
public static String[] shuffleDeck( Card[] deck)
{
/** I have attempted to get two index numbers, and swap them.
I tried to figure out how to loop this so it kind of simulates "shuffling".
*/
}
public static void displayDeck( Card[] deck)
{
for ( Card c: deck)
{
System.out.println(c.value + "\t" + c);
}
}
}

How about:
List<Card> list = Arrays.asList(deck);
Collections.shuffle(list);
Or one-liner:
Collections.shuffle(Arrays.asList(deck));

One way is to convert the array to a list, and use java.util.Collections.shuffle(array) to shuffle it:
Card[] deck = ...;
List<Card> list = Arrays.asList(deck);
Collections.shuffle(list);
If you do still need an array instead of a List, you can add:
list.toArray(deck);
Here is a TIO (Try-it-online) link to see the array to list conversion and shuffling in action.
Code of the TIO copied below as reference:
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
class M{
public static void main(String[] a){
// Original array
Integer[] array = new Integer[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
System.out.println("before: " + Arrays.toString(array));
// Convert array to list
List<Integer> list = Arrays.asList(array);
// And shuffle that list
Collections.shuffle(list);
System.out.println("after as list: " + list);
// (Optional) then convert the list back to an array,
// and save it in its initial variable (`array` in this case)
list.toArray(array);
System.out.println("after as array: " + Arrays.toString(array));
}
}

I see two ways to do it:
-> You can use a shuffle algorithm like the Fisher-Yates shuffle algorithm if you want to implement yourself the method.
-> You can use the shuffle method from Collections

If this is for a school project (as I think it is), you might not be allowed to use built-in functions such as Collections::shuffle(). If this is the case, then you must try to simulate randomness (which in programming can be surprisingly hard).
The most common way to create a sense of randomness is to use an RNG (random number generator).
As you said
I have attempted to get two index numbers, and swap them.
Correct. One way to shuffle is to pick one card at a time and randomly select another card to swap the position with.
You know the deck always has 52 cards.
You have a random generator
to select a random index.
You have a programming language with
loop-structures.
With these tools you can implement your own shuffle-function quite easily.

Related

Java: How do I make an array and fill it with objects in my constructor?

I am trying to create a constructor that creates an array and fills that array with custom objects. This array would represent a deck of cards.
public class DeckOfCards {
public static Card[] deck = new Card[52];
//constructor
DeckOfCards(){
Card[] deck = new Card[52];
deck[0]=new Card("Ace","Clubs"); deck[1]=new Card("Two","Clubs");
deck[2]=new Card("Three","Clubs");..(ect)...deck[49]=new
Card("Jack","Diamonds");
deck[50]=new Card("Queen","Diamonds"); deck[51]=new Card("King","Diamonds");
}
I feel like this constructor should create an array and fill it with card objects but it doesn't recognize any objects instantiated from DeckOfCards() as arrays.
You are declaring the deck again inside your constructor. I would initialize the deck this way. Iterating through two arrays, simplest one.
DeckOfCards(){
suit = ['Hearts','Diamonds','Clubs','Spades'];
number=['Ace','One','Two','Three','Four','Five','Six','Seven','Eight','Nine','Ten','Jack','Queen','King'];
for (int i=0;i<4;i++){
for (int j=0;j<13;j++){
deck[i+j]=new Card(number[j],suit[i]);
}
}
}
You have an scope problem since you are declaring again
Card[] deck = new Card[52];
inside the constructor, leaving without effect the global member, do instead use the deck object.... (by the way, no need for static objects...)
DeckOfCards(){
deck[0]=new Card("Ace","Clubs"); deck[1]=new Card("Two","Clubs");
deck[2]=new Card("Three","Clubs");..(ect.).deck[49]=new
Card("Jack","Diamonds");
deck[50]=new Card("Queen","Diamonds"); deck[51]=new Card("King","Diamonds");
}
First, you don't need to initialise deck again in the constructor. Just use the class-level variable you defined.
Second, deck should not be static, so remove that word.
Third, make the constructor public.
And last but not least, you should probably initialise the deck in a smarter way.
public class DeckOfCards {
public Card[] deck = new Card[52];
//constructor
public DeckOfCards(){
String[] numbers = { "Ace", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King" };
String[] suits = { "Spades", "Clubs", "Diamonds", "Hearts" };
int i = 0;
for (String suit: suits) {
for (String number: numbers) {
deck[i] = new Card(number, suit);
i++;
}
}
}
}
Delete that line and it will be fine :
Card[] deck = new Card[52];

Sorting deck of Cards using custom sorting algorithms

I am trying to implement different sorting algorithms on a deck of cards. I've implemented a base card class using enums to build the suits and faces. My class is based on Dietel's & Dietel's Java Book. However, I am struggling in passing the deck of cards into the sorting algorithms I implemented as I am not able to pass in an array which I can sort. I don't know if my approach is correct, I've read many of the posts on stackexchange where some recommend using Comparable (Implementing a Deck of Cards in Java) which I can't see working with my sorting algorithms. See (How to Sort the Cards. (Is my code wrong?)) and (Implementing a Deck of Cards in Java) and (Java Sorting object in ArrayList). By having the DeckOfCards return a sequence of numbers e.g. 1.1, 1.2, 1.3, I think I have a sequence which can be sorted. I also read about ordinals but all the comments on those seemed to oppose the approach. Appreciate any help on this attempt. Kindly note, that I've implemented merge sort and selection sort in the same way and its the same problem - I am clearly missing something here!
Below is my code:
//Card class
class Card
{
//public static enum Face {Ace, Deuce, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King};
public static enum Face {Ace(1), King(2), Queen(3), Jack(4), Ten(5), Nine(6), Eight(7), Seven(8), Six(9), Five(10), Four(11), Three(12), Deuce(13);
int rank;
Face(int r){ rank = r;}
int getRank() {return rank;}
}
//public static enum Suit {Clubs, Diamonds, Hearts, Spades };
public static enum Suit {Spades(1), Hearts(2), Diamonds(3), Clubs(4);
int order;
Suit(int o){ order = o;}
int getOrder() {return order;}
}
private final Face face; // face of card
private final Suit suit; // suit of card
// two-argument constructor
public Card( Face cardFace, Suit cardSuit )
{
face = cardFace; // initialize face of card
suit = cardSuit; // initialize suit of card
}
// return face of the card
public Face getFace() { return face;}
// return suit of Card
public Suit getSuit() { return suit;}
// return String representation of Card
public String toString()
{
//return String.format( "%s.%s", suit.getOrder(), face.getRank() );
return String.format( "%s.%s", suit, face );
}
}
// class DeckOfCards declaration
public class DeckOfCards
{
private List< Card > list; // declare List that will store Cards
// set up deck of Cards and shuffle
public DeckOfCards()
{
Card[] deck = new Card[ 52 ];
int count = 0; // number of cards
// populate deck with Card objects
for ( Card.Suit suit : Card.Suit.values() )
{
for ( Card.Face face : Card.Face.values() )
{
deck[ count ] = new Card( face.getRank(), suit.getOrder() );
count++;
}
}
list = Arrays.asList( deck ); // get List
//Collections.shuffle( list ); // shuffle deck
}
// output deck
public void printCards()
{
// display 52 cards in two columns
for ( int i = 0; i < list.size(); i++ )
System.out.printf( "%-20s%s", list.get( i ),
( ( i + 1 ) % 2 == 0 ) ? "\n" : "" );
}
public static void main( String[] args )
{
DeckOfCards cards = new DeckOfCards();
cards.printCards();
//cards.InsertionSort();
}
}
//Insertion Sort
public static void insertionSort(DeckOfCards[] listToSort)
{
for (int i = 0; i < listToSort.length-1; i++)
{
for (int k = i+1; k>0; k--)
{
if(listToSort[k] < listToSort[k-1]) //Code breaks here
{
swap(listToSort, k, k-1);
}
else
{
break;
}
print(listToSort);
}
}
}
The issue is that listToSort[k] < listToSort[k-1] is attempting to compare two DeckOfCards objects using the < operator, which is not allowed in Java - See: Compare two objects with or operators in Java.
As that post points out, you should instead be using a Comparator for the Card objects.
public class CardComparator implements Comparator<Card> {
#Override
public int compare(Card o1, Card o2) {
// ...
// Use Card.getFace().getRank() and Card.getSuit().getOrder()
// ...
}
}
In your DeckOfCards class, I'd also recommend adding a method such as:
public List<Card> getCards() { ... }
which returns a List of the cards in the deck. Then, in your insertionSort method, instead of listToSort[k], you would have listToSort.getCards().get(k). Also, instead of using < you can use a new instance of your CardComparator to determine whether or not to swap the cards.
public static void insertionSort(DeckOfCards cardsToSort) {
final Comparator cardComparator = new CardComparator();
for (int i = 0; i < cardsToSort.size() - 1; i++) {
for (int k = i + 1; k > 0; k--) {
final Card card1 = cardsToSort.getCards().get(k);
final Card card2 = cardsToSort.getCards().get(k - 1);
if(cardComparator.compare(card1, card2) < 0) {
swap(cardsToSort, k, k-1);
} else {
break;
}
}
}
}
listToSort is an array of DeckOfCards. On the line indicated with //Code breaks here you're trying to compare two DeckOfCards objects, which you just can't do in java (Operator overloading in other languages would allow you do do this).
How about you write a method, such as .getSortValue() to give you a value to sort it by. Alternatively you could write something to compare the values within the card like:
if(listToSort[k].getSuit().getOrder()*13+listToSort[k].getFace().getOrder() < listToSort[k- 1].getSuit().getOrder()*13+listToSort[k-1].getFace().getOrder())
...which is a bit long, but I would assume does what you want.
Note the *13 means that each combination of suit and face is unique
TLDR:
If you want to sort it in any other order, you'll have to come up with a value from each card that you can compare properly
The proper approach would be to split the whole deck into suits and then sort each suite individually. Your version of insertion sort is not working because the sorting is done using the face values i.e aces, 2,3,4 ... And I wouldn't count this as sorting a deck .
private HashMap<Suite,ArrayList<Cards>> deck ;
//scan through the whole deck
for(int i = 0;i < 52; ++i) {
`switch(cards[i]) {`
`case Aces :`
deck.put(Suite.Aces,cards[i]) ;
break;
.....
}
}
//Now sort
sort(deck.get(Suite.Aces)) ;
sort(deck.get(Suite.Diamond)) ;

Basic Poker Program - Printing Deck

I'm working on a poker project that just deals the 5 top cards from a shuffled deck and lets the user to reject all, some, or none. I understand that there should be ideally 2-3 classes, one with the actual main and the other two being the card and deck. I have created the Deck class and a very basic Tester program that is just supposed to print the shuffled cards. However, when I print the deck, I get something along the lines of "Deck####d##a". What am I doing wrong?
import java.util.Random;
public class Deck {
// Constructing a deck from two arrays
String[] suit = { "Clubs", "Diamonds", "Hearts", "Spades" };
String[] rank = { "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King" };
String[] deck = new String[suit.length * rank.length];
// Storing public variables
int suits = suit.length;
int ranks = rank.length;
int deckSize = deck.length;
public Deck()
{
for(int i = 0; i < suits; i++)
{
for(int j = 0; j < ranks; j++)
{
deck[ranks*i + j] = rank[j] + " of " + suit[i];
}
}
}
// Fisher-Yates Shuffle
public void shuffle()
{
Random rand = new Random();
for (int i = 0; i < deckSize; i++)
{
int x = rand.nextInt(deckSize);
String temp = deck[x];
deck[x] = deck[i];
deck[i] = temp;
}
}
}
And the tester class:
import java.util.Scanner;
public class DeckTester {
public static void main(String[] args) {
Deck deck = new Deck();
System.out.println(deck);
}
}
Output: Deck####d###a
You're seeing the default `toString() method from the Object class, and you're finding that it's not too helpful. You're also not creating a Card or a true Deck class and so you can't give any class a decent toString() method.
Solutions:
Create a Card class.
Give it a rank and a value field.
Give it a toString() method.
Create a Deck class
Give it a collection of Cards.
Give it a decent toString() method.
e.g.,
// for Deck
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Card card: cards) {
sb.append(card.toString() + ", ");
}
return sb.toString();
}
Printing an object calls its toString() method. If your class or any of its ancestors do not override toString(), it calls the default, which is the toString() method of Object.
But the default toString() is not very clever - it just gives you the name and hash code of the deck.
So it is very recommended, for any class that you're going to print (and even for those you don't, but you may want to debug) to override the toString() method. In the overridden method, you should construct a string that represents the contents of your class. It could be as simple as calling Arrays.toString() in your case.
Also, note that you have defined a shuffle() method, but you are not actually calling it from anywhere, so once you do succeed in printing your deck, it will not be shuffled.

How to shuffle two array for poker evaluator

I am working on a poker program. I am having some issues figuring out how to shuffle. I have to use arrays. I can't use enums or Lists. i know there are much better ways to make this program but the point is to understand arrays.
I am having some issues figuring out how to shuffle my deck of cards. I'm trying to keep this as simple as possible so I have one class to get the cards of the deck and shuffle them.
import java.util.Arrays;
import java.util.Random;
public class Card
{
String[] suits = { "Spades", "Clubs", "Hearts", "Diamonds" };
String[] values = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"};
public Card()
{
}
public void getCards()
{
for(int indexSuit = 0; indexSuit < suits.length; indexSuit++)
{
String suit = suits[indexSuit];
System.out.print(suit + " ");
for(int indexType = 0; indexType < values.length; indexType++)
{
String type = values[indexType];
System.out.print(type + " ");
}
}
}
public void shuffle(String[] suit, String[] value)
{
Random rndSuits = new Random();
Random rndType = new Random();
for(int indexSuit = suits.length - 1; indexSuit > 0; indexSuit--)
{
int index = rndSuits.nextInt(indexSuit + 1);
String temp = suits[indexSuit];
suits[indexSuit] = suit[index];
suit[index] = temp;
System.out.print(temp);
for(int indexType = values.length -1; indexType > 0; indexType--)
{
int index2 = rndType.nextInt(indexType + 1);
String temp2 = values[indexType];
values[indexType] = value[index2];
value[index2] = temp2;
System.out.print(temp2);
}
}
}
public void deal()
{
}
}
Here is my main:
public class FiveCardPoker
{
public static void main(String[] args){
Card timsCards = new Card();
timsCards.getCards();
timsCards.shuffle(args, args);
}
}
I was trying to write the shuffle method based on another question I found on here, but it was only for a single array. I'm not sure if logic is correct for the shuffle method. I'm also not exactly sure how to call it in my main method.
How Do I get my arrays from the Card class to the Main class when I call timsCards.shuffle?
EDIT: So I have tried editing it like this, but it doesn't seem to be doing anything.
public void shuffle()
{
Collections.shuffle(Arrays.asList(suits));
Collections.shuffle(Arrays.asList(values));
System.out.println(Arrays.toString(values) + " of " + Arrays.toString(suits));
}
Ideal way that I can think of is, You can create some Collection out of these arrays and use
Collections.shuffle() method.
Code -
String[] suits = {"Spades", "Clubs", "Hearts", "Diamonds"};
List<String> list = Arrays.asList(suits);
Collections.shuffle(list);
System.out.println(list); //Prints shuffled list
Javadoc
As for your last question, regarding how to get the array from inside the shuffle function into the main function, you should have your shuffle function return an array, and call it like this:
shuffledCards[] = timsCards.Shuffle(...);
I realize that other people have provided other solutions, but you mentioned the purpose is to understand arrays so I figured I'd mention that this will accomplish the same thing.
Also, although I admittedly haven't tested it, it seems as if your shuffle array will shuffle each suit within itself, but not the deck as a whole. You may want to think about a more creative solution to that (If you aren't going to use Collections.shuffle())
If you want to write a shuffle method yourself you could do it like this.
static Random rnd = new Random();
static void shuffle(Object[] array) {
for(int index1 = array.length - 1; index1 > 0; index1--) {
int index2 = rnd.nextInt(index1 + 1);
Object temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
}
public static void main(String[] args) {
String[] suits = { "Spades", "Clubs", "Hearts", "Diamonds" };
String[] values = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"};
shuffle(suits);
shuffle(values);
}
That way you are able to shuffle arrays of any arbitrary objects, not just strings. You may want to fill an array with objects representing cards and then shuffle that.
There are several thing to improve in your example.
Firstly, suits ("Spades", "Clubs", "Hearts", "Diamonds") and values should be manipulated with an Enum type and not a String. It will be easier to read and debug. You can implement an array of enum if you want.
Only ONE Random object is good enough. And you should use a seed if you hope an unpredictable shuffle...
How you shuffle each array is correct, but NOT the global one. Here you suffle suits, and inside a suit you shuffle the values, but all diamonds stay together...
If you want to shuffle a deck of cards (as I imagine) then you should implement only ONE collection/array: an array of Cards and each Card is a uniq couple suit,value.
For your last question, I recommand to implement 'shuffle' as a factory (so it should be static) that returns a shuffle deck of cards. If you prefer an object method (NO STATIC) then you should implement a Deck class, then shuffle will mean shuffle THIS deck.

Appending two strings to one index in an Array in Java

I've fixed it exactly how I want it now. If anyone else has the same issue I think this is the easiest and most efficient way of trying to set up a deck of cards. You can pick out individual cards using a random variable in deck[random][0] and deck[random][1].
Thanks for all the help, here is my code:
public class NewDeck {
public static void main(String[] args) {
String[] suits = new String[] { "Clubs", "Diamonds", "Spades", "Hearts" };
String[] faces = new String[] { "Ace", "King", "Queen", "Jack" };
String[][] deck = new String[suits.length * (faces.length + 9)][2];
int a = 0;
for (String y : suits) {
for (String x : faces) {
deck[a][0] = x;
deck[a][1] = y;
a++;
}
}
for (String y : suits) {
for (int p = 2; p < 11; p++) {
deck[a][1] = y;
String pp = Integer.toString(p);
deck[a][0] = pp;
a++;
}
}
for (int p = 0; p < deck.length; p++) {
System.out.print(deck[p][0] + " of ");
System.out.println(deck[p][1]);
}
}
}
You should add parameter types to your strings and create a Pair class. Note that you will need a Java compiler of version 1.5 or higher for the generics.
class Pair {
private final String face;
private final String suit;
Pair(String suit, String face) {
this.face = face;
this.suit = suit;
}
#Override
public String toString() {
return "(" + suit + ", " + face + ")";
}
}
Then you can use this Pair class as follows, using the appropriate List methods get and size:
List<Pair> deck = new ArrayList<Pair>();
List<String> suits = new ArrayList<String>();
suits.add("Hearts");
suits.add("Diamonds");
suits.add("Clubs");
suits.add("Spades");
List<String> faces = new ArrayList<String>();
faces.add("Ace");
faces.add("King");
faces.add("Queen");
faces.add("Jack");
for(int suit = 0; suit < suits.size(); suit++){
for(int face = 0; face < faces.size(); face++){
deck.add(new Pair(suits.get(suit), faces.get(face)));
}
}
If you override the toString method of Pair you can also System.out.println(deck) to get your desired string representation of the ArrayList.
Probably you need to change this
deck.add(suits[suit], faces[face]);
with
deck.add(suits[suit] + faces[face]);
as your idea is to concatenate elements from the list and add it the deck list.
You can not store two values at one index of List. But what you can do is
Option 1
Store concatenated \string like
Change
deck.add(suits[suit], faces[face]);
with
deck.add(suits[suit] + "," + faces[face]);
then output deck[2] = suit, face
Option 2
Change list of string to list of Object and this object contains detail of suit and face
public class Deck {
private String suit;
private String face;
// getter and setters;
}
and list become
List<Deck> deck
and add entry as
deck.add(new Deck(suits[suit], faces[face]))

Categories