Your browser does not support the canvas tag.

previous        Show / Hide Source        Download        next
/* ////////////////////////////////////////////////////////
 
 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);
    }
  }
}