/* ////////////////////////////////////////////////////////
Shuffled Cards by Bruce McCormack
Click on the deck to draw a random card!
Click on the green to place it where ever you want!
Repeat! Up to 51 times!
Click on already placed cards to pick them up again!
If you can see it, you can pick it up! But only ONE at a time!
The reset button sets all the fun back up again!
/////////////////////////////////////////////////////*/
Stack deck = new Stack(width/2, height/2);
Stack displayStack = new Stack(0, 0);
Stack mouseStack = new Stack(mouseX, mouseY);
boolean holding = false;
Button resetBut = new Button();
void setup() {
size(800, 600);
rectMode(CENTER);
deck.Initialize();
}
void draw() {
background(0, 240, 0);
resetBut.drawButton();
deck.drawStack();
displayStack.drawStack();
if (holding) {
mouseStack.updatePile(mouseX, mouseY);
mouseStack.drawStack();
}
}
void mouseClicked() {
if (!holding) {
if (displayStack.mouseCheck()) {
mouseStack.transfer(displayStack.give());
holding = true;
} else if (deck.mouseCheck()) {
if (deck.stackSize() > 1) {
mouseStack.transfer(deck.give());
holding = true;
} else {
deck.display = false;
}
} else if (resetBut.mouseCheck()) {
resetBut.activate();
}
} else {
//set holding to false so new cards can be picked up
holding = false;
//put the held card "down", i.e. append it to the end of the displayStack
displayStack.transfer(mouseStack.give());
//clear out the mouseStack so there aren't doubles
mouseStack.empty();
displayStack.get(displayStack.stackSize()-1).setSelected(false);
println(deck.stackSize());
}
}class Button {
String word = " Reset";
float xPos, xSize, yPos, ySize;
Button() {
xPos = 10;
yPos = 10;
xSize = 37;
ySize = 15;
}
void drawButton() {
rectMode(CORNER);
stroke(0);
fill(255);
rect(xPos, yPos, xSize, ySize);
fill(0);
text(word, xPos, yPos+ySize-3);
}
boolean mouseCheck() {
boolean yes = false;
//determine if the mouse is in the bounds of the button
if (mouseX > xPos && mouseX < xPos+xSize && mouseY > yPos && mouseY < yPos+ySize) {
yes = true;
}
return yes;
}
void activate() {
//reset everything, and re-shuffle the deck
mouseStack.empty();
displayStack.empty();
deck.empty();
deck.Initialize();
}
}class Card {
//0=back, 1=Spade, 2=Diamond, 3=Club, 4=Heart
int suit;
//1=ace, num=num, 11=Jack, 12=Queen, 13=King
int num;
//boolean to determine if the back should be drawn
boolean back;
//boolean to determine if the card is under mouse
boolean selected = false;
//PVector stores the card's location
PVector location = new PVector(width/2, height/2);
Card(int Color, int val, boolean display) {
suit = Color;
num = val;
back = display;
}
//allow outside functions to change selection state
void setSelected(boolean temp) {
selected = temp;
}
//allow outside functions to change face up/down
void upDown (boolean face) {
back = face;
}
//allow outside functions to change location
void updateLocation(float x, float y) {
location.x = x;
location.y = y;
}
//draw the cards
void drawCard() {
stroke(0);
strokeWeight(3);
fill(255);
rectMode(CENTER);
rect(location.x, location.y, 90, 130, 6);
//determine what suit will be drawn
if (suit == 1) {
drawSpade();
} else if (suit == 2) {
drawDiamond();
} else if (suit == 3) {
drawClub();
} else if (suit == 4) {
drawHeart();
}
//if back is true, draw only the back of the card,
//only applies to the draw deck, really
if (back){
drawBack();
//for everything else, draw the card value on top of the suit
} else {
if (num == 1) {
drawAce();
} else if (num == 2) {
drawTwo();
} else if (num == 3) {
drawThree();
} else if (num == 4) {
drawFour();
} else if (num == 5) {
drawFive();
} else if (num == 6) {
drawSix();
} else if (num == 7) {
drawSeven();
} else if (num == 8) {
drawEight();
} else if (num == 9) {
drawNine();
} else if (num ==10) {
drawTen();
} else if (num == 11) {
drawJack();
} else if (num == 12) {
drawQueen();
} else if (num == 13) {
drawKing();
}
}
}
//the info to draw the spade shape
void drawSpade() {
noStroke();
fill(0);
ellipse(location.x-20, location.y+12, 40, 40);
ellipse(location.x+20, location.y+12, 40, 40);
triangle(location.x-39, location.y+5, location.x+39, location.y+5, location.x, location.y-50);
rect(location.x, location.y+20, 10, 50);
}
//the info to draw the diamond shape
void drawDiamond() {
noStroke();
fill(255, 0, 0);
quad(location.x, location.y-50, location.x+40, location.y, location.x, location.y+50, location.x-40, location.y);
}
//the info to draw the club shape
void drawClub() {
noStroke();
fill(0);
ellipse(location.x-18, location.y+10, 46, 46);
ellipse(location.x+18, location.y+10, 46, 46);
ellipse(location.x, location.y-25, 46, 46);
rect(location.x, location.y+20, 10, 50);
}
//the info to draw the heart shape
void drawHeart() {
noStroke();
fill(255, 0, 0);
ellipse(location.x-20, location.y-20, 45, 45);
ellipse(location.x+20, location.y-20, 45, 45);
triangle(location.x-40, location.y-10, location.x+40, location.y-10, location.x, location.y+45);
}
//info to draw an "A"
void drawAce() {
stroke(255);
strokeWeight(3);
line(location.x+15, location.y+20, location.x, location.y-20);
line(location.x-15, location.y+20, location.x, location.y-20);
line(location.x-6, location.y+2, location.x+6, location.y+2);
}
//info to draw a "2"
void drawTwo() {
stroke(255);
strokeWeight(3);
line(location.x-15, location.y-5, location.x-15, location.y-20);
line(location.x-15, location.y-20, location.x+15, location.y-20);
line(location.x+15, location.y-20, location.x+15, location.y);
line(location.x+15, location.y, location.x-15, location.y+20);
line(location.x-15, location.y+20, location.x+15, location.y+20);
}
//info to draw a "3"
void drawThree() {
stroke(255);
strokeWeight(3);
line(location.x-15, location.y-20, location.x+15, location.y-20);
line(location.x+15, location.y-20, location.x+15, location.y+20);
line(location.x+15, location.y+20, location.x-15, location.y+20);
line(location.x+15, location.y, location.x-15, location.y);
}
//info to draw a "4"
void drawFour() {
stroke(255);
strokeWeight(3);
line(location.x+7, location.y-20, location.x+7, location.y+20);
line(location.x-15, location.y-20, location.x-15, location.y);
line(location.x-15, location.y, location.x+15, location.y);
}
//info to draw a "5"
void drawFive() {
stroke(255);
strokeWeight(3);
line(location.x-15, location.y, location.x+15, location.y);
line(location.x-15, location.y-20, location.x+15, location.y-20);
line(location.x-15, location.y+20, location.x+15, location.y+20);
line(location.x-15, location.y, location.x-15, location.y-20);
line(location.x+15, location.y, location.x+15, location.y+20);
}
//info to draw a "6"
void drawSix() {
stroke(255);
strokeWeight(3);
line(location.x-15, location.y-20, location.x+15, location.y-20);
line(location.x-15, location.y-20, location.x-15, location.y+10);
rect(location.x, location.y+10, 30, 20);
}
//info to draw a "7"
void drawSeven() {
stroke(255);
strokeWeight(3);
line(location.x-15, location.y-20, location.x+15, location.y-20);
line(location.x+15, location.y-20, location.x-10, location.y+20);
line(location.x-3, location.y, location.x+7, location.y);
}
//info to draw an "8"
void drawEight() {
stroke(255);
strokeWeight(3);
rect(location.x, location.y, 30, 40);
line(location.x-15, location.y, location.x+15, location.y);
}
//info to draw a "9"
void drawNine() {
stroke(255);
strokeWeight(3);
line(location.x+15, location.y+20, location.x-15, location.y+20);
line(location.x+15, location.y+20, location.x+15, location.y-10);
rect(location.x, location.y-10, 30, 20);
}
//info to draw a "10"
void drawTen() {
stroke(255);
strokeWeight(3);
line(location.x-7, location.y-20, location.x-7, location.y+20);
line(location.x-7, location.y-20, location.x-15, location.y-10);
line(location.x-15, location.y+20, location.x, location.y+20);
ellipse(location.x+7, location.y, 16, 40);
line(location.x+11, location.y-17, location.x+3, location.y+17);
}
//info to draw a "J"
void drawJack() {
stroke(255);
strokeWeight(3);
line(location.x+5, location.y+20, location.x+5, location.y-20);
line(location.x+15, location.y-20, location.x-15, location.y-20);
line(location.x+5, location.y+20, location.x-15, location.y+20);
line(location.x-15, location.y+20, location.x-15, location.y+5);
}
//info to draw a "Q"
void drawQueen() {
stroke(255);
strokeWeight(3);
ellipse(location.x, location.y, 30, 40);
line(location.x+1, location.y+10, location.x+15, location.y+20);
}
//info to draw a "K"
void drawKing() {
stroke(255);
strokeWeight(3);
line(location.x-15, location.y+20, location.x-15, location.y-20);
line(location.x-15, location.y, location.x+15, location.y-20);
line(location.x-4, location.y-5, location.x+13, location.y+20);
}
//info to draw the back of the card, just a solid salmon, really
void drawBack() {
stroke(0);
fill(255, 191, 191);
rect(location.x, location.y, 90, 130, 6);
}
}class Stack {
ArrayList<Card> pile = new ArrayList<Card>();
PVector location = new PVector();
//boolean to determine if the stack should be drawn and clickable
//(for if the deck has a card in it, will be set to false when the null card is the only one left)
boolean display = true;
Stack(float x, float y) {
location.x = x;
location.y = y;
}
void drawStack() {
if (display) {
for (Card c : pile) {
c.drawCard();
}
}
}
//make sure functions outside the class can get at the array size
int stackSize() {
return pile.size();
}
//let functions outside the stack class get at the members of the arrayList, yes, I realize now I should have just made the ArrayLists in the core program
Card get(int i) {
//get the object at the passed index
Card tempCard = pile.get(i);
//return the object at the passed index
return tempCard;
}
//for the main deck's use
void Initialize() {
//add a "null" card so that the deck size never reduces to 0 <- This was Michael's idea
pile.add(new Card(0, 0, true));
//create a temporary "deck" to generate all the cards and the "shuffle"
ArrayList<Card> shuffle = new ArrayList<Card>();
//generate all 52 cards in a deck
//go through all four suits
for (int suit = 1; suit < 5; suit++) {
//go through all 13 card values in each suit
for (int val = 1; val < 14; val++) {
shuffle.add(new Card(suit, val, true));
}
}
//iterate through the temp deck and add random cards to the actual deck
//go backwards to make sure every element gets hit
for (int i = shuffle.size()-1; i >= 0; i--) {
//want a random card
int rngCard = int(random(shuffle.size()-1));
//get the card object
Card c = shuffle.get(rngCard);
//adds the cards to the deck face down
c.upDown(true);
//add the card object to the permenant pile array
pile.add(c);
//remove the card object from the temp deck to avoid repeats
//and reduce the arraylist size so the last element can be potentially selected
shuffle.remove(rngCard);
}
}
//run checks to see if the mouse is over a card
boolean mouseCheck() {
int counter = 0;
//make sure the function can return something regardless of results
boolean yes = false;
//iterate through the stack only if the stack exists
if (pile.size() > 0) {
for (Card c : pile) {
//check to see if the mouse is within the bounds of a given card
if (mouseX < c.location.x +44 && mouseX > c.location.x-44 && mouseY < c.location.y+64 && mouseY >c.location.y-64) {
//if the mouse is over the card, mark it for use in give()
c.setSelected(true);
//check if there aren't any cards on top of it
for (int i = 0; i < counter; i++) {
//only the top most card under the mouse can be selected
//can pull a card out from under if it's poking out and the mouse is over that bit
pile.get(i).setSelected(false);
}
//the counter makes sure the previous for loop can keep up with the full array iteration
counter += 1;
//will fire off a true to progress the function only if the mouse is over ANY card somewhere
yes = true;
}
}
//return false if there is nothing in the stack
} else {
//make sure "yes" is returning false
yes = false;
//do the returning
return yes;
}
//will return false if there is no card under mouse
return yes;
}
//send the card that the mouse is over (or holding) to/from the mouse
Card give() {
//make sure the function can return something
//(even though it's not necessary given how the code will be written, Processing doesn't like it)
Card temp = null;
for (int i = 0; i < pile.size(); i++) {
//only send the card that is "selected" by mouseCheck()
if (pile.get(i).selected) {
temp = pile.get(i);
//remove the selected card from old pile
pile.remove(i);
//make sure the card is face up once manipulated in any way
temp.upDown(false);
//reset the selected state so it won't be "picked up" again
}
}
return temp;
}
//update stack's location, by updating the locations of the cards inside it
void updatePile(float x, float y) {
//iterate through the stack
for (Card c : pile) {
//updating the card's locations, adding to mouse location so they don't snap to center on the mouse
c.updateLocation(x, y);
}
}
//appends a new card to the stack, the mirror of give()
void transfer(Card c) {
pile.add(c);
}
//resets the stack
void empty() {
for (int i = pile.size()-1; i >= 0; i--) {
pile.remove(i);
}
}
}