Skip to content

Instantly share code, notes, and snippets.

@Michael0x2a
Created November 3, 2015 23:59
Show Gist options
  • Save Michael0x2a/6d7be7b0ff80480adc75 to your computer and use it in GitHub Desktop.
Save Michael0x2a/6d7be7b0ff80480adc75 to your computer and use it in GitHub Desktop.
/**
* Michael Lee
* Tuesday, April 14, 2015
* Sample program: StackDeck2.java
*
* This class represents a deck of cards, which you can shuffle
* and manipulate.
*/
import java.util.*;
public class StackDeck2 implements Deck {
private Stack<String> cards;
/**
* Creates an empty deck of cards.
*/
public StackDeck2() {
this.cards = new Stack<String>();
}
/**
* Returns the number of cards in the deck.
*/
public int size() {
return this.cards.size();
}
/**
* Returns {@code true} if the deck contains no cards, returns {@code false} otherwise.
*/
public boolean isEmpty() {
return this.cards.isEmpty();
}
/**
* Removes and returns the card currently at the top of the deck.
*
* @throws NoSuchElementException if the deck is empty
* @return the top-most card
*/
public String dealCard() {
this.failIfUnableToRemove(1);
return this.cards.pop();
}
/**
* Returns the requested amount of cards from the top of the deck.
*
* @param amount the amount of cards to remove
*
* @throws IllegalArgumentException
* if {@code amount} is negative
* @throws NoSuchElementException
* if {@code amount} exceeds the size of the deck
*
* @return a new deck containing the dealt cards, with the card at
* the top of this deck located at the bottom of the
* returned one.
*/
public Deck dealCards(int amount) {
this.failIfUnableToRemove(amount);
StackDeck2 output = new StackDeck2();
this.transfer(this.cards, output.cards, amount);
return output;
}
/**
* Adds a card to the top of the deck.
*
* @param card the card to add (cannot be null)
*/
public void addCard(String card) {
this.cards.push(card);
}
/**
* Moves all the cards in the other deck to this one.
*
* <p>Note that the other deck of cards will be emptied
* after this operation is over.
*
* @param other the deck to empty and grab cards from (cannot be null)
*/
public void mergeDeck(Deck other) {
while (!other.isEmpty()) {
this.cards.push(other.dealCard());
}
}
/**
* Randomly shuffles the cards in the deck in place.
*/
public void shuffle() {
// Implements a riffle shuffle -- splits the deck in two,
// and splices the two together.
// Note: this is an _imperfect_ shuffle. It doesn't actually
// randomly shuffle the deck in any way, making this a rigged deck.
int half = this.size() / 2;
Stack<String> temp1 = new Stack<String>();
Stack<String> temp2 = new Stack<String>();
// Split the deck in two
this.transfer(this.cards, temp1, half);
this.transfer(this.cards, temp2); // move everything else
// Take one card at a time from each half and add it back
for (int j = 0; j < half; j++) {
this.cards.push(temp1.pop());
this.cards.push(temp2.pop());
}
// Take care of the last card if we have an odd number of cards
if (!temp2.isEmpty()) {
this.cards.push(temp2.pop());
}
}
/**
* Returns a copy of the contents of the card as a list without modifying
* the deck itself.
*
* <p>The card at the top of the deck will be placed at the end of the list.
*/
public List<String> toList() {
Stack<String> temp = new Stack<String>();
List<String> output = new ArrayList<String>();
// Move cards to temp stack, reversing it. The bottom card is now
// at the top of the stack.
this.transfer(this.cards, temp);
// Moves everything back, and adds to the list in the correct order
while (!temp.isEmpty()) {
String card = this.move(temp, this.cards);
output.add(card);
}
return output;
}
/**
* Returns a string representing this deck.
*
* <p>Example output:
*
* <p>{@code [King of Spades, 9 of Hearts, Ace of Clubs, 4 of Spades, ...]}
*
* @return a String representing this stack, where each card is separated by
* comma, surrounded by brackets. The card at the top of the deck will
* be placed at the end of the string.
*/
public String toString() {
if (this.isEmpty()) {
return "[]";
} else {
Stack<String> temp = new Stack<String>();
String output = this.move(this.cards, temp);
// Note: adds to the back of the string, not the front
// (so I can fencepost)
while (!this.cards.isEmpty()) {
String card = this.move(cards, temp);
output = card + ", " + output;
}
// Restores the stack
this.transfer(temp, this.cards);
return "[" + output + "]";
}
}
/**
* Transfers everything in the 'src' stack to the 'dest' stack.
*
* <p>Neither deck can be null.
*
* @param src the stack to grab elements from
* @param dest the stack to add elements to
*/
private void transfer(Stack<String> src, Stack<String> dest) {
this.transfer(src, dest, src.size());
}
/**
* Transfers the top 'amount' of elements from the 'src' stack to
* the 'dest' stack.
*
* @param src the stack to grab elements from
* @param dest the stack to add elements to
* @param amount the amount of elements to transfer (amount must be less
* then or equal to the number of elements in src and cannot
* be negative)
*/
private void transfer(Stack<String> src, Stack<String> dest, int amount) {
for (int i = 0; i < amount; i++) {
dest.push(src.pop());
}
}
/**
* Moves one element from 'src' to 'dest', but returns that one element.
*
* <p>Neither stack can be null.
*
* @param src the stack to grab elements from (most contain at least
* one element)
* @param dest the stack to add elements to
*
* @return the item at the top of the 'src' stack
*/
private String move(Stack<String> src, Stack<String> dest) {
String card = src.pop();
dest.push(card);
return card;
}
/**
* Throws an NoSuchElementException if it is not possible to remove
* "n" cards from the deck, otherwise does nothing.
*
* @param n the number of elements to try checking
*/
private void failIfUnableToRemove(int n) {
if (this.size() < n) {
throw new NoSuchElementException("Deck doesn't contain enough cards");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment