Skip to content

Instantly share code, notes, and snippets.

@Michael0x2a
Created November 3, 2015 23:58
Show Gist options
  • Save Michael0x2a/97e03aab6797bea60878 to your computer and use it in GitHub Desktop.
Save Michael0x2a/97e03aab6797bea60878 to your computer and use it in GitHub Desktop.
// Michael Lee
// Tuesday, April 14, 2015
// Sample program: StackDeck.java
//
// This class represents a deck of cards, which you can shuffle
// and manipulate.
import java.util.*;
public class StackDeck implements Deck {
private Stack<String> cards;
// Creates an empty deck of cards.
public StackDeck() {
this.cards = new Stack<String>();
}
// Returns the number of cards in the deck.
public int size() {
return this.cards.size();
}
// Returns 'true' if the deck contains no cards, returns 'false' otherwise.
public boolean isEmpty() {
return this.cards.isEmpty();
}
// Removes and returns the card currently at the top of the deck.
//
// Preconditions:
// - The deck is not empty (otherwise throws NoSuchElementException)
public String dealCard() {
this.failIfUnableToRemove(1);
return this.cards.pop();
}
// Returns the requested amount of cards from the top of the deck.
//
// Preconditions:
// - "amount" must not be negative (otherwise throws IllegalArgumentException)
// - "amount" must not exceed the size of the deck
// (otherwise throws NoSuchElementException)
//
// Postconditions:
// - Returns a new Deck containing the 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);
StackDeck output = new StackDeck();
this.transfer(this.cards, output.cards, amount);
return output;
}
// Adds a card to the top of the deck.
//
// Preconditions:
// - The card is not null
public void addCard(String card) {
this.cards.push(card);
}
// Moves all the cards in the other deck to this one.
//
// Preconditions:
// - "other" must not be null
//
// Postconditions:
// - The other deck will be emptied of all cards
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.
//
// Postconditions:
// - 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.
//
// Postconditions:
// - Each card will be separated by comma, surrounded by brackets
// - The card at the top of the deck will be placed at the end of the string.
//
// Example of output:
//
// [King of Spades, 9 of Hearts, Ace of Clubs, 4 of Spades, ...]
//
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.
//
// Preconditions:
// - Neither stack should be null
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.
//
// Preconditions:
// - Neither stack should be null
// - The src stack must have at least 'amount' number of elements
// - The amount must not 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.
//
// Preconditions:
// - Neither stack should be null.
// - The 'src' stack must have at least one element.
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.
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