I'm trying to find a way to delete a specific card or a random card in a deck and return that deleted card. I've created classes for Card and DeckHand. In the DeckHand class, I'm trying to create a delete method that allows the user to pick a card value, delete ONE instance of that card value from the deck, then returns the card that was deleted, and lastly, shorten the array by 1. I'm also trying to make a deleteAny method that deletes a random card from the deck, returns the card that was deleted, and shorten the array by 1.
For the delete method, I'm having trouble finding a way to say:
*if the value input by the user isn't in the deck, print an error message.
*if it is, then find the first instance of a card with that value, delete it, and return the card.
I don't understand how to find the first instance of a card with the value and then finding a way to set an available suit to create the instance of the card to then delete it and shift the positions in the array.
I started trying to do an deleteAny method that deletes a random card. I'm able to get the card output to the user that's getting removed, but I'm getting an error with my method. Any ideas?
Card Class:
class Card {
private int _value, _suit;
private String[] _cardValues = {null, "Ace", "2", "3", "4","5", "6", "7",
"8", "9", "10", "Jack", "Queen", "King"};
private String[] _cardSuits = {null, "Clubs", "Diamonds", "Hearts", "Spades"};
public Card(int value,int suit) {
_value = value;
_suit = suit;
}
public int getCardValue() {
return _value;
}
public int getCardSuit() {
return _suit;
}
public String toString() {
return _cardValues[_value] + " of " + _cardSuits[_suit];
}
}
Deck class:
class DeckHand{
private Card[] _deckHand;
private int _deckSize;
private static final int MAXSIZE = 52;
private Card[] newDeck;
public DeckHand() {
_deckHand = new Card[MAXSIZE];
_deckSize = 0;
}
public DeckHand(int deckSize) {
_deckHand = new Card[MAXSIZE];
int index = 0;
for (int suit = 1; suit <= 4; suit++) {
for (int rank = 1; rank <= 13; rank++) {
_deckHand[index] = new Card(rank, suit);
index++;
}
}
_deckSize = deckSize;
}
//Here's the delete method, but I have no idea what I'm doing here.
public void delete(int value) {
for (int i = 0; i<_deckSize; i++) {
if(_deckHand[i].getCardValue()==value) {
_deckHand[value] = _deckHand[_deckSize-1];
newDeck = new Card[_deckHand.length-1];
} else
System.out.println("\n--------------------------------------"
+ "\nThe deck does not contain that value"
+ "\n--------------------------------------");
}
}
//Here's the deleteAny method, but I'm getting an error
public void deleteAny(Card newCard) {
if(_deckSize >= MAXSIZE) {
newDeck = new Card[_deckHand.length-1];
for(int i = 0; i<_deckSize; ++i)
if(_deckHand[i].equals(newCard)) {
newDeck[i] = _deckHand[i];
}
_deckHand = newDeck;
}
//the error says it has to do with this next line
_deckHand[_deckSize-1] = newCard;
_deckSize-=1;
}
}
Main:
Here's part of my main method that uses these delete and deleteAny methods:
case 3:
System.out.println("\nWhich card would you "
+ "like to remove from the deck?");
valueOption();
System.out.print("\tOption: ");
value = keyboard.nextInt();
if(pickDeck == 1) {
standard.delete(value);
} else {
System.out.println("\n-------------------------"
+ "-------------------------------\n"
+ "The card value \"" + values[value]
+ "\" appears "
+ empty.count(value)
+ " times in the deck."
+ "\n---------------------------------"
+ "-----------------------");
}
break;
case 4:
Random generator = new Random();
value = generator.nextInt(13)+1;
suit = generator.nextInt(4)+1;
newCard = new Card(value,suit);
System.out.println("\n--------------------------"
+ "---------------------"
+ "\n" + newCard + " was removed from the "
+ "deck."
+ "\n--------------------------"
+ "---------------------");
if(pickDeck==1)
standard.deleteAny(newCard);
else
empty.deleteAny(newCard);
break;
If you need to remove an element from an array without using system.arraycopy or array.utils you might do something like the remove function that follows. (It is only static because I tested this up in one file.)
import java.util.Arrays;
public class HelloWorld{
public static String[] remove(String[] arr,int index){
String[] ret = new String[arr.length-1];
for(int i = 0; i<index; i++){
ret[i]=arr[i];
}
for(int i = index+1; i<arr.length; i++){
ret[i-1]=arr[i];
}
return(ret);
}
public static void main(String []args){
System.out.println("Hello World");
String[] r = {"This","Is","ATest"};
System.out.println(Arrays.toString(remove(r,0)));
System.out.println(Arrays.toString(remove(r,1)));
System.out.println(Arrays.toString(remove(r,2)));
}
}
My answer uses most of your method from above. I've tweaked it to incorporate means of checking if we've found the value before.
public Card delete(int value) {
Card result = new Card(-1,-1); // Starter card to check if value has been found.
newDeck = new Card[_deckHand.length-1]
int location = -1 // Initial location. This changes once we find the value.
for (int i = 0; i<_deckHand.length; i++) {
if(_deckHand[i].getCardValue()==value) { // We've found a match
if(result.value==-1){ // Check if our starter card still has its original value
result = new Card(_deckHand[i].getCardValue(),_deckHand[i].getCardSuit());
location = i; // Adjust location
}
}
// make a helper that does the rest. That way you can delete any card from the deck.
if(location != -1){ // See if location has been adjusted (i.e. value has been found)
for(int i = 0; i < location; i++){ // Copy the remnants of _deckHand to newDeck
newDeck[i]=_deckHand[i];
}
for(int j = location+1; j<_deckHand.length-1; j++){
newDeck[j]=_deckHand[j];
}
_deckHand = new Card[newDeck.length]
_deckHand = newDeck // Change _deckHand to newDeck
return result; // Return the card that was removed from _deckHand.
} else { // `else` indicates that the value has not been found
System.out.println("\n--------------------------------------"
+ "\nThe deck does not contain that value"
+ "\n--------------------------------------");
}
}
Edit:
Didn't see the last part about deleteAny(). You could make a helper method called helperDelete(value,location) that takes the value to delete and the position of the card which you want to delete. Using the same strategy as above, once you find the location of the initial value that you want, remove it from the deck, copy the deck into a new, shortened deck, and set your deck instance to be the new deck.
This should allow you to remove the card at a random position value, as needed by deleteAny(), and at a specified location value, as needed by delete().
Related
I am currently working on a CS project that classifies player's hands. I solved the first half of the project to print out the deck, shuffled deck and the hands of player1, player2 and remaining deck. The problem comes up when I have to evaluate the hands. My code has to somehow evaluate which classification the hands are, and print out whether player1 or player2 wins. I have three classes so far:
public class Card {
static String[] card_suit = {"hearts", "diamonds", "clubs", "spades"};
static int[] card_rank = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};// 11 is Jack, 12 is Queen, 13 is King and 14 is Ace
public int[] getRank() {
return card_rank;
}
public String[] getSuit() {
return card_suit;
}
}
public class Driver {
public static void main(String[] args) {
Card card = new Card();
Deck deck = new Deck();
deck.getDeck();
System.out.print("ORIGINAL DECK: ");
deck.printDeck();
deck.shuffleDeck();
System.out.print("SHUFFLED DECK: ");
deck.printDeck();
System.out.println();
System.out.print("PLAYER ONE: ");
System.out.println(java.util.Arrays.toString(deck.playerOneHands()));
System.out.print("PLAYER TWO: ");
System.out.println(java.util.Arrays.toString(deck.playerTwoHands()));
System.out.print("REMAINING DECK: ");
System.out.println(java.util.Arrays.toString(deck.remainingDeckCards()));
}
}
import java.util.Arrays;
import java.util.Collections;
public class Deck extends Card {
Card card = new Card();
private String[] deck_card = new String[52];
public String[] getDeck() {
int i = 0;
for(int s = 0; s < 4; s++) {
for(int r = 0; r < 13; r++) {
deck_card[i]=(card_suit[s] + " of " + card_rank[r]);
i++;
}
}
return deck_card;
}
public void printDeck() {
System.out.println (java.util.Arrays.toString (deck_card));
}
public void shuffleDeck() {
Collections.shuffle(Arrays.asList(deck_card));
}
public String[] playerOneHands() {
String [] firsthand = new String[5];
for(int a = 0; a < 5; a++) {
firsthand[a] = deck_card[a];
}
return firsthand;
}
public String[] playerTwoHands() {
String[] secondhand = new String[5];
for(int a = 0; a < 5; a++) {
secondhand[a] = deck_card[a+5];
}
return secondhand;
}
public String[] remainingDeckCards() {
String[] remainDeck = new String[42];
for(int a = 0; a < 42; a++){
remainDeck[a] = deck_card[a+10];
}
return remainDeck;
}
}
What I thought it would work is because the Deck class extends from the Card class, I can use the getRank method to compare each hand, but I am not sure how to construct the conditionals.
Any help is greatly appreciated. Thanks.
For modelling the game, first identify entities like Card, Deck etc. (which mostly you have done). I would add few more like Player, Evaluator(explained below) etc.
Rank and Suit are NOT string/ int but they are predefined (not going to change in life time of game) possible variations in Cards. Always use domain vocabulary for best model. Each Card belongs to one Suit and one Rank. (think of making Rank and Suit as enums, this will avoid unknown values breaking the code at run time.
Not giving set method for suite and rank in Card is essential (they form an identity of Card in combination)
Full Deck (at initialization) is formed by cross product of Suit and Rank. Meaning Deck has (contains) multiple cards. Remember Card can be alive outside of Deck (when in players hand) as well, hence its not composition. Inheriting Deck from Card is absolutely wrong. It translates to statement Deck is a kind of Card, which is not correct. Deck will have collection of Cards. Using inheritance, will lead to violation of Liskov's Substitution Principle (One of the SOLID).
To model Deck, consider the fact that Deck does not contain duplicate cards, Deck does not change its order once formed (unless shuffled). This being tricky selection between Set and List, I would go for List with added programmatic constraint for avoiding duplicates (needs to be done only when initialization).
But instead of Modelling Deck as java collection, it will be best to let class Deck contain java collection of suitable choice and Deck class work as wrapper by defining required API (from domain perspective) like shuffle, getTopCard() etc. This is called as Object Adapter design pattern. This makes our design platform (implementation) independent.
You need to model few more classes like Player holds CardInHand etc.
About evaluating Cards in hand, its better to model it as separate class as its different concern and rules can change independent of other classes.
Poker game is best assignment to learn Object Oriented Programming.
Without wanting to do your homework for you...
This is a problem:
class Deck extends Card
A deck isn’t a subtype of a card. A deck has cards, so:
class Deck {
List<Card> cards;
}
is a better choice.
Also, the following code does nothing to the deck:
public void shuffleDeck() {
Collections.shuffle(Arrays.asList(deck_card));
}
It shuffles a copy of the deck, leaving the deck untouched.
Also, you shouldn’t be building strings in a loop. Instead, implement (override) a toString() method on Card and Deck.
Also, make suit an enum.
Also, delete card_rank entirely - it serves no purpose. Instead, add a int rank; field to Card, or better make rank an enum.
Fix these things first, then re-attack the problem by writing a method that is passed a Hand (a new class) that has a List and a method that returns a HandType (another enum) by evaluating if the hand is a straight flush, else four of a kind, else ... all the way down to high card - highest to lowest.
It seems that you class Card only has static fields; I would change it so that an instance of Card would represent a single card from a Deck. I would also make the suites an enum type. You can also add integer constants for the figures and aces. The class can implement Comparable<Card>:
public class Card implements Comparable<Card> {
public enum Suite {CLUBS, DIAMONDS, HEARTS, SPADES};
public static final int JACK = 11;
public static final int QUEEN = 12;
public static final int KING = 13;
public static final int ACE = 14;
public final Suite suite;
public final int rank;
public Card(Suite suite, int rank) {
if (suite == null) {
throw new IllegalArgumentException("Suite cannot be null");
}
if (rank < 2 || rank > 14) {
throw new IllegalArgumentException(
"Value must be between 2 and 14");
}
this.suite = suite;
this.rank = rank;
}
public Suite getSuite() {
return suite;
}
public int getRank() {
return rank;
}
#Override
public String toString() {
StringBuilder buf = new StringBuilder();
if (rank >= 2 && rank <= 10) {
buf.append(rank);
} else {
switch (rank) {
case JACK:
buf.append("jack");
break;
case QUEEN:
buf.append("queen");
break;
case KING:
buf.append("king");
break;
case ACE:
buf.append("ace");
break;
}
}
buf.append(" of ");
buf.append(suite.toString().toLowerCase());
return buf.toString();
}
#Override
public int compareTo(Card other) {
if (rank > other.rank) {
return 1;
} else if (rank < other.rank) {
return -1;
} else {
return suite.compareTo(other.suite);
}
}
}
Note that you could also have two subclasses of Card: one for the numbers and one for the figures.
The Deck is a collection of 52 cards. It is initialised by adding each card to a list. One can shuffle a deck, or take a card from the deck:
public class Deck {
private final List<Card> cards = new ArrayList<>();
public Deck() {
for (Card.Suite suite: Card.Suite.values()) {
for (int i = 2; i <= 14; ++i) {
cards.add(new Card(suite,i));
}
}
}
public void shuffle() {
Collections.shuffle(cards);
}
public boolean isEmpty() {
return cards.isEmpty();
}
public Card take() {
if (cards.isEmpty()) {
throw new IllegalStateException("Deck is empty");
}
return cards.remove(0);
}
}
You can take shuffle and take 5 cards from the deck like this:
Deck deck = new Deck();
deck.shuffle();
for (int i = 0; i < 5; ++i) {
Card card = deck.take();
System.out.println(card);
}
Now a Hand is a set of five cards taken from a Deck. We can declare Hand as implementing Comparable<Hand> so that we can know which of two hands have the highest value:
public class Hand implements Comparable<Hand> {
private final Card[] cards = new Card[5];
public Hand(Deck deck) {
for (int i = 0; i < 5; ++i) {
cards[i] = deck.take();
}
Arrays.sort(cards);
}
#Override
public int compareTo(Hand other) {
...
}
}
Now here comes the fun part: you must identify the hand type as one of the following (enum type):
public enum HandType {
SINGLE, PAIR, TWO_PAIRS, THREE, STRAIGHT, FLUSH, FULL_HOUSE, FOUR,
STRAIGHT_FLUSH, ROYAL_FLUSH;
}
Note that the constants are arranged from the lowest to the highest. In addition, the cards must be arranges so that in case of a tie, you can compare the cards to identify the winner.
I would suggest you make groups of cards of same rank; in the case where you have five different groups, it still can be a flush or a straight.
Another approach would consist in declaring a subclass of Hand for each HandType, but I don't think you would gain much by doing this.
public class Hand implements Comparable<Hand> {
public enum HandType {
SINGLE, PAIR, TWO_PAIRS, THREE, STRAIGHT, FLUSH, FULL_HOUSE, FOUR,
STRAIGHT_FLUSH, ROYAL_FLUSH;
}
private final Card[] cards = new Card[5];
private final int[] groupSize;
private final HandType type;
public Hand(Deck deck) {
for (int i = 0; i < 5; ++i) {
cards[i] = deck.take();
}
groupSize = group(cards);
type = identifyType(groupSize, cards);
}
#Override
public int compareTo(Hand other) {
int r = type.compareTo(other.type);
if (r != 0) {
return r;
}
for (int i = cards.length; --i >= 0; ) {
int r1 = cards[i].getRank();
int r2 = other.cards[i].getRank();
if (r1 < r2) {
return -1;
} else if (r1 > r2) {
return 1;
}
}
return 0;
}
#Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(type);
buf.append(": ");
buf.append(cards[0]);
for (int i = 1; i < 5; ++i) {
buf.append(", ");
buf.append(cards[i]);
}
return buf.toString();
}
private static int[] group(Card[] cards) {
Arrays.sort(cards);
List<List<Card>> groups = new ArrayList<>();
int val = -1; // invalid rank
List<Card> currentGroup = null;
for (Card card: cards) {
if (val == card.getRank()) {
currentGroup.add(card);
} else {
if (currentGroup != null) {
groups.add(currentGroup);
}
currentGroup = new ArrayList<>();
currentGroup.add(card);
val = card.getRank();
}
}
if (currentGroup != null) {
groups.add(currentGroup);
}
// identify groups of cards of same value
// sort groups by size and highest card
Collections.sort(groups, (List<Card> group1, List<Card> group2) -> {
int s1 = group1.size();
int s2 = group2.size();
if (s1 < s2) {
return -1;
} else if (s1 > s2) {
return 1;
} else {
return group1.get(s1-1).compareTo(group2.get(s2-1));
}
});
int[] groupSize = new int[groups.size()];
int g = 0;
int i = 0;
for (List<Card> group: groups) {
groupSize[g++] = group.size();
for (Card card: group) {
cards[i++] = card;
}
}
assert sum(groupSize) == 5;
return groupSize;
}
private static HandType identifyType(int[] groupSize, Card[] cards) {
switch (groupSize.length) {
case 2:
// can be a full house or four cards
if (groupSize[0] == 1) {
return HandType.FOUR;
} else if (groupSize[0] == 2) {
return HandType.FULL_HOUSE;
} else {
assert false;
return null;
}
case 3:
if (groupSize[0] == 1) {
// three cards or double pair
if (groupSize[1] == 1) {
return HandType.THREE;
} else {
assert groupSize[1] == 2 && groupSize[2] == 2;
return HandType.TWO_PAIRS;
}
} else {
assert false;
return null;
}
case 4:
// one pair
return HandType.PAIR;
case 5:
// all different values: check for flush
Card prev = cards[0];
boolean sameSuite = true;
boolean straight = true;
for (int i = 1; i < 5; ++i) {
Card card = cards[i];
straight &= card.getRank() == prev.getRank()+1;
sameSuite &= card.getSuite() == prev.getSuite();
}
if (sameSuite) {
if (straight) {
if (cards[4].getRank() == Card.ACE) {
return HandType.ROYAL_FLUSH;
}
return HandType.STRAIGHT_FLUSH;
} else {
return HandType.FLUSH;
}
} else {
if (straight) {
return HandType.STRAIGHT;
} else {
return HandType.SINGLE;
}
}
default:
assert false;
return null;
}
}
private static int sum(int[] groupSize) {
int sum = 0;
for (int s: groupSize) {
sum += s;
}
return sum;
}
}
I am utilizing the standard array-driven approach to creating, shuffling, and drawing a 52-card deck of standard playing cards. My challenge is coming in the form of having two identical, but distinct, decks drawing simultaneously, side-by-side.
Originally I thought having two instances of the class Deck in the executable DeckDrawTest class would be sufficient, but when I asked for the class to draw 104 (52 x 2) times, I got all 52 cards of one deck and 52 null entries. I then made a duplicate Deck class called Deck2, and changed all the method and variable names while keeping the functionality the same - no dice, same results. I then tried to overcome a potential multiple inheritance problem by duplicating the Card class that both Deck and Deck2 drew from, making another class identical to Card called Card2 but with different variable names. Has not changed the outcome. Code is presented below.
Card
public class Card
{
private final String name;
private final String suit;
public Card(String cardName, String cardSuit) {
this.name = cardName;
this.suit = cardSuit;
}
public String toString() {
return name + "of " + suit;
}
}
Deck2 (which draws from Card for now, will fix names once I get it functional):
public class Deck2
{
private static final SecureRandom randomClam = new SecureRandom();
private static final int DECKSIZE2 = 52;
private Card[] deck = new Card[DECKSIZE2];
private int currentCard = 0;
public Deck2() {
String[] names2 = {"A ", "2 ", "3 ","4 ", "5 ", "6 ", "7 ", "8 ", "9 ", "10 ", "J ", "Q ", "K "};
String[] suits2 = {"♠ ", "♥ ", "♣ ", "♦ "};
for (int count = 0; count < deck.length; count ++) {
deck[count] =
new Card(names2[count % 13], suits2[count /13]);
}
}
public void shuffle2() {
currentCard = 0;
for (int first2 = 0; first2 < deck.length; first2++) {
int second2 = randomClam.nextInt(DECKSIZE2);
Card temp2 = deck[first2];
deck[first2] = deck[second2];
deck[second2] = temp2;
}
}
public Card dealCard(){
if (currentCard < deck.length) {
return deck[currentCard++];
}
else {
return null;
}
}
}
DeckDrawTest (which is drawing from Deck and Deck2)
public class DeckDrawTest
{
public static void main(String[] args) {
Deck myDeck = new Deck();
myDeck.shuffle();
Deck2 yourDeck = new Deck2();
yourDeck.shuffle2();
for(int i = 1; i <=104; i++){
System.out.printf("%-20s", myDeck.dealCard(), "%-20s", yourDeck.dealCard());
if(i %2 == 0) {
System.out.println();
System.out.println();
}
}
}
}
So how do I get this program to draw from two distinct, but identical, decks, instead of just drawing from one?
Your variable i goes up to 104, but in each loop you call dealCard on both decks. That's where the null values come from. You only need to loop up to 52:
for (int i = 1; i <=52; i++) {
Your output using printf is wrong, the function only expects one formatter. Your version just outputs the value of myDeck.dealCard() and also calls (but not uses) yourDeck.dealCard(). To create a line with the output of both calls, use something like this:
System.out.printf("%-20s %-20s", myDeck.dealCard(), yourDeck.dealCard());
I have a hashmap<Integer, Card> Card is a class. I have initialized the hashmap with keys from 0-51 and the values are array of Card, as follows
Card [] card = new Card[52]
for (int i=1; i<=13; i++)
for (int j=0; j<4; j++)
card[++index] = new Card( ((i*10)+j) );
and I populate the hashmap as follows:
for (int i=1; i<=13; i++)
for (int j=0; j<4; j++)
deck.put( ++key, card[++index] );
Now, what I want to do is to shuffle the values side of the hashmap, i do not want,for an example, the key[1] corresponds to card[0] and key[1] corresponds to card[1]. I want, for an exampel, the key[1] corresponds to card[38]. I want the values side to be shuffled. I tried the following:
Collections.shuffle(card,new Random()); But it seems it accepts only ArrayList and List.
HashMaps do not have a predictable order, and shuffling an unordered data structure doesn't make sense. From the Java reference docs:
This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
If you are using keys from 0-51, you should just add all of the cards to an ArrayList. Then you can use Collections.shuffle(arrayList)
can I shuffle an array?
Yes. Here's one way.
Integer[] t = { 1, 2, 3, 4, 5 };
Collections.shuffle(Arrays.asList(t));
System.out.println(Arrays.toString(t));
You should consider adjusting your design to include a Deck and Card class. Examples are shown below. Your "encoding" for a card has a potential flaw 10*suit + card will have suit 0 card 13 have the same value as suit 1, card 3. If you want to compare two cards to see which "wins", you should add a method to the Card class that does this.
Try this:
Deck Class
package com.example.cards;
import java.util.Arrays;
import java.util.Collections;
public class Deck {
// Class fields
// Object fields
private Integer[] deckOrder;
private int nextCard;
private Card[] cards;
public Deck() {
deckOrder = new Integer[52];
cards = new Card[52];
for (int i=0; i < deckOrder.length; i++) {
deckOrder[i] = i;
cards[i] = new Card(i/13,i % 13);
}
}
public void shuffle() {
Collections.shuffle(Arrays.asList(deckOrder));
nextCard = 0;
}
public Card deal() {
if (nextCard < deckOrder.length) {
nextCard++;
return cards[deckOrder[nextCard-1]];
} else {
return null;
}
}
}
Card Class
package com.example.cards;
public class Card {
// Class fields
public final static String[] suit = {"Spades","Hearts","Diamonds","Clubs"};
public final static String[] card = {"Ace","King","Queen","Jack","Ten","Nine"
,"Eight","Seven","Six","Five","Four"
,"Three","Two"};
// Object fields
private int suitIndex;
private int cardIndex;
public Card(int suit, int card) {
suitIndex = suit;
cardIndex = card;
}
public int getSuitIndex() { return suitIndex;}
public int getCardIndex() { return cardIndex;}
public String getSuit() { return suit[suitIndex];}
public String getCard() { return card[cardIndex];}
public int getEncodedCard() { return 100*suitIndex + cardIndex;}
}
Test driver
package com.example.cards;
public class TestShuffle {
public static void main(String[] args) {
Deck myDeck = new Deck();
for (int deal = 1; deal < 3; deal++) {
System.out.println("======================Deal " + deal);
for (int i = 0; i < 52; i++) {
Card nextCard = myDeck.deal();
System.out.println("Card " + i + ". " + nextCard.getCard()
+ " of " + nextCard.getSuit() + "(encoded "
+ nextCard.getEncodedCard() + ")");
}
myDeck.shuffle();
}
}
}
try this:
public static void main(String args[]) {
Map<String, Object> x = new HashMap<String, Object>();
x.put("x", 1); x.put("y", 2); x.put("z", 3); x.put("w", 4);
System.out.println(x);
List<Object> vs = new ArrayList<Object>(x.values());
Collections.shuffle(vs);
System.out.println(vs);
Iterator<Object> vIter = vs.iterator();
for (String k : x.keySet()) x.put(k, vIter.next());
System.out.println(x);
}
output :
{w=4, x=1, y=2, z=3}
[2, 3, 1, 4]
{w=2, x=3, y=1, z=4}
What you can do is extract your key value pairs as a List of Map.Entry and shuffle it and put your Map.Entry values in the cleared map
Set<Map.Entry<Integer,Card> cardEntrySet= deck.entrySet();
List<Map.Entry<Integer,Card> cardsEntryList = new ArrayList<>(cardEntrySet);
Collections.shuffle(cardsEntryList);
deck.clear();
for(Map.Entry<Integer,Card> entry :cardsEntryList){
deck.put(entry.getKey(),entry.getValue());
}
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]))
I am currently working on a hand of cards class that uses enums that requires me to add methods that:
Add cards into the hand
Calculate the total value of all the cards currently in the hand (so if there were 3 10's in the hand then the total value would be 30)
The problem however is that I can't find out how to add up all the total while still implimenting the method within the hand class (as the task asks us to).
Any help will be greatly appreciated
Heres the code for my Suit enum
public enum Suit
{ HEARTS, CLUBS, DIAMONDS, SPADES; }
Here is the code for my Rank enum.This one has a few added methods including a getValue method
public enum Rank {
ONE(1),TWO(2),THREE(3),FOUR(4),FIVE(5), SIX (6), SEVEN(7), EIGHT(8), NINE(9), TEN(10), KING(10), QUEEN(10),
JACK(10);
private final int cardValue;
private Rank ( int nDays) {
cardValue = nDays;
}
public int getValue() {
return cardValue;
}
}
This is the Card class that uses the Rank and Suit enums to print off the details (excuse the mess)
public class Card {
private Rank rank;
private Suit suit;
public Card (Rank theRank) {
this(theRank,Suit.HEARTS);
}
public Card (Rank theRank, Suit theSuit) {
rank = theRank;
suit = theSuit;
}
public Rank getRank( ) { return rank; }
public Suit getSuit ( ) { return suit; }
public String toString ( ) { return ( rank + " of " + suit +"\n Value of card = " + rank.getValue() ); }
}
And this is the Hand class that requires the addCard method and the totalValue method. I have done the addCard method and now need to do totalValue method)
public class Hand {
private Card theCards[ ];
private Rank rank;
private int numCards; private int totalValue;
private static final int max = 5;
public Hand ( )
{
theCards = new Card [max];
numCards = 0;
}
public void addCard( Card aCard )
{
if (numCards < max)
theCards[numCards++] = aCard;
else
{
System.out.println("Cannot add any more cards as hand is full");
}
}
public void totalValue ()
{
int handValue = 0;
for(Card C: theCards)
{
//get the rank values to appear then print them off
//Add up all values of cards and display the total
totalValue = handValue + C.getValue(); //This was just a test to see if calling up the value of card C would work
}
System.out.println("The total value of all the cards is: " + totalValue);
}
public String toString ( )
{
String s = "";
for (int i = 0; i < numCards; ++i) { s += "\n" + theCards[i];
}
return s;
}
As far as implimentation goes its just a case of creating card objects and adding them to the Hand object so I don't think I'll need to post that here. Thank you to anyone who can help me with my problem.
Card doesn't have a getValue() method but Rank does. So get the card's Rank via its getRank() method and then call getValue() on the rank returned.
The value of a Card is available through its rank field. Right now you are trying to call getValue() directly on the Card, but there's no such method (yet).
Also, you'd normally return the total value of the hand from the totalValue() method, rather than simply printing it; this allows other code to actually use the value.
I managed to figure out how to make it print without returning any nullexception errors. Basicly I simply converted the array into an arraylist as it was much more practical. Here is the final version of the Hand class.
import java.util.*;
public class Hand {
private ArrayList<Card> theCards = new ArrayList<Card >() ;
private static final int max = 5;
public void addCard( Card aCard )
{
if (theCards.size() < max)
theCards.add(aCard);
else
{
System.out.println("Cannot add any more cards as hand is ull");
}
}
public void totalValue() {
int totalValue = 0;
for (Card card : theCards) {
totalValue += card.getRank().getValue();
}
System.out
.println("The total value of all the cards is: " + totalValue);
}
public void outputAllCards ( )
{
System.out.println("Outputting all card etails\n========================");
for (Card card : theCards)
{
System.out.println(card.toString());
}
System.out.println("========================");
} }
I put in a println in order to print a message out when the totalValue method was called. I tried returning by turning the method into a string or int but this didn't work
The value is inside the rank. Does the rank object inside hand play any role (such as doubling value of the corresponding cards in the hand, you have to specify the game rules)? You just have to add up the rank values. I rewrote your code to leave out some unneccessary counters/vars. On the other side it is better to keep a list instead of an array if it can grow.
import java.util.ArrayList;
import java.util.List;
public class Hand {
private final List<Card> cards = new ArrayList<Card>();
private Rank rank;
private static final int MAX = 5;
public void addCard(Card aCard) {
if (cards.size() < MAX) {
cards.add(aCard);
} else {
System.out.println("Cannot add any more cards as hand is full");
}
}
public void totalValue() {
int totalValue = 0;
for (Card card : cards) {
totalValue += card.getRank().getValue();
}
System.out
.println("The total value of all the cards is: " + totalValue);
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Card card : cards) {
sb.append('\n').append(card.toString());
}
return sb.toString();
}
}