Archive for December 6th, 2008

Complete Working Refrigerator

// COMPLETE WORKING PROCESSING PROGRAM,
// ILLUSTRATING:
// -- ARRAY OF OBJECTS
// -- MAINTAINING SORTED ORDER OF ARRAY OF OBJECTS
// -- SUBCOLLECTIONS
 
// Global instances of Refrigerator objects:
Refrigerator mainFridge;
Refrigerator miniFridge;
 
 
void setup(){
  size(450, 400);
 
  // Create the instance of the main Refrigerator object.
  // The mini Refrigerator is null for now.
  // Question for you: where does the miniFridge get created?
  mainFridge = new Refrigerator();
  miniFridge = null;
}
 
void draw(){
  background(180);
 
  // Request the main Refrigerator to draw itself.
  // I have modified the render() method to take location & size.
  mainFridge.render(50,50,150,300);
 
  // Since the mini Refrigerator does not exist at the start
  // of the program, only draw it once it has been created.
  if (miniFridge != null){
    miniFridge.render(250,180,150,170);
  }
 
}
 
int miniFridgeType = 0; // just a little hack
 
void keyPressed(){
  switch(key){
  case 'o':
    mainFridge.openDoor();
    break;
  case 'c':
    mainFridge.closeDoor();
    break;
  case '-':
    mainFridge.removeItem();
    break;
  case '+':
    mainFridge.addItem();
    break;
 
  case 'f':
    // When we press the 'f' key,
    // Create the mini-fridge.
    // For this fridge, we ONLY select those foods of a certain "type"
    // (triangle, circle, square).
    miniFridgeType++;
    miniFridgeType%=3;
    miniFridge = mainFridge.makeSubcollectionRefrigerator (miniFridgeType);
    break;
 
  case 'x':
    // When we press the 'x' key,
    // delete whichever item is mouse-selected (in the main fridge),
    // ans shift the remaining items down one position.
    int indexOfSelectedItem = mainFridge.getIndexOfSelectedItem();
    if (indexOfSelectedItem != -1){
      mainFridge.removeSpecificItem(indexOfSelectedItem);
    }
    break;
 
 
  case 'v':
    // when we press the 'v' key,
    // insert a new FoodItem into the main fridge.
    // This FoodItem is generated with a random tallness,
    // and it will have to be inserted in the correct position
    // in the array (maintaining sorted order!).
    // All inserted FoodItems are RED, so you can easily spot them.
    float tallness = 10 + random(35);
    color chroma = color(255,0,0);
    int   type = (int)random(0,3);
    FoodItem F = new FoodItem(tallness, chroma, type);
    mainFridge.insertAndSortNewFoodItem (F);
    break;
  }
}
 
//===============================================
class Refrigerator {
 
  // FIELDS
  int      nFoodItems;
  FoodItem foodItems[];
  boolean  bDoorOpen;
 
  //---------------------------
  // METHODS
 
  Refrigerator(){
    bDoorOpen = false;
    nFoodItems = 0;
 
    int initialFoodItemArraySize = 10;
    foodItems = new FoodItem[initialFoodItemArraySize];
    // ...individual food items will be created (new'd) when they're added.
    // that's one way to do it.
  }
 
  //---------------------------
  void render(int x, int y, int w, int h){
    // IF THE DOOR IS CLOSED, SHOW THE OUTSIDE OF THE FRIDGE.
    if (bDoorOpen == false){
      stroke(0);
      strokeWeight(1);
      fill(255,240,230);
      rect(x,y,w,h);
      fill(180,180,190);
      rect(x+5,y+h/2-40,5,60);
 
      // render silly kid's drawing
      pushMatrix();
      translate(50,50);
      rotate(radians(-15.0));
      translate(x,y);
      fill(255);
      rect(0,0,36,36);
      smooth();
      ellipse(18,18,27,27);
      arc(18,18,20,20, radians(45),radians(135));
      ellipse(12,14,6,6);
      ellipse(24,14,6,6);
      popMatrix();
 
    }
    else {
      // BUT IF THE DOOR IS OPEN, SHOW THE STUFF INSIDE.
      stroke(0);
      strokeWeight(1);
 
      // Draw the fridge enclosure
      fill(200,200,208);
      rect(x,y,w,h);
      fill(240,240,255);
      rect(x+5,y+5,w-10,h-10);
 
      // draw the food items at specified locations.
      // Compute some positions to cleverly position things.
      for (int i=0; i<nFoodItems; i++){
        float foodx = x + 25 + (i%6)*20;
        float foody = y + h - 10 - (60*(i/6));
        foodItems[i].draw(foodx,foody);
      }
    }
  }
 
  //---------------------------
  // ACCESSOR METHODS
  boolean isDoorOpen(){
    return bDoorOpen;
  }
 
  int getNFoodItems(){
    return nFoodItems;
  }
 
  // SIMPLE MUTATOR METHODS
  void closeDoor(){
    bDoorOpen = false;
  }
 
  void openDoor(){
    bDoorOpen = true;
  }
 
  //---------------------------
  Refrigerator makeSubcollectionRefrigerator (int subselectionFoodType){
    // Here, we ask this Refrigerator to create
    // a "subcollection" Refrigerator (such as a cooler or mini-fridge).
 
    // We know (from its signature) that this method *must*
    // return a Refrigerator. So declare and create this right away!
    // And don't forget to return it at the end of the method.
    Refrigerator outputFridge = new Refrigerator();
 
    // Open its door so we can add food to it (ha!)
    outputFridge.openDoor();
 
    // Search through my foodItems array for items which meet the criterion.
    // Add those items to the outputFridge.
    // (Note that "criterion" in this case means, subselectionFoodType.
    // But the criterion could be measuring a continuous property instead --
    // For example, find me all FoodItems taller than.... etc.)
    for (int i=0; i<nFoodItems; i++){
      if (foodItems[i].getType() == subselectionFoodType){
        outputFridge.addItem(foodItems[i]);
      }
    }
 
    // Return the outputFridge.
    return outputFridge;
  }
 
 
  //---------------------------
  // ADDITEM 1: pass in an actual FoodItem object.
  void addItem (FoodItem F){
    if (bDoorOpen){
      foodItems[nFoodItems] = F;
      nFoodItems++;
      if (nFoodItems >= foodItems.length){
        expandFoodItemArray();
      }
    }
    else {
      System.out.println("Door must be open to add an item.");
    }
  }
 
 
  //---------------------------
  // ADDITEM 2: pass in properties for a new FoodItem to be made from
  void addItem (float tallness, color chroma, int type){
    if (bDoorOpen){
      foodItems[nFoodItems] = new FoodItem(tallness, chroma, type);
      nFoodItems++;
      if (nFoodItems >= foodItems.length){
        expandFoodItemArray();
      }
    }
    else {
      System.out.println("Door must be open to add an item.");
    }
  }
 
  //---------------------------
  void addItem(){
    // ADDITEM 3: pass in nothing (no arguments);
    // Adds a randomly-generated item to the end of the array,
    // expanding the array if necessary (if it gets too full).
 
    if (bDoorOpen){
      // If the door is open,
      // generate the properties of a new FoodItem
 
      // This is code for adding a new fooditem to the end.
      // It makes sure that this new food item is 4 pixels taller than
      // what is currently the last item in the array.
      float tallness = 10;
      if (nFoodItems > 0){
        tallness = foodItems[nFoodItems-1].getTallness() + 4.0;
      }
 
      // generate a color and food type for
      // what will be the newly added FoodItem
      color chroma = color(random(100,255), random(128,255), random(0,100));
      int   type = (int)random(0,3);
 
      // .. create and add that FoodItem to the foodItems array.
      foodItems[nFoodItems] = new FoodItem(tallness, chroma, type);
      nFoodItems++;
 
      // Deal with what happens when the user fills up the array.
      // If the number of food items has exceeded the size of the array,
      // Expand the array!
      if (nFoodItems >= foodItems.length){
        expandFoodItemArray();
      }
    }
    else {
      System.out.println("Door must be open to add an item.");
    }
  }
 
  //---------------------------
  void insertAndSortNewFoodItem (FoodItem inputF){
    // Some FoodItem, inputF, is being "inserted" into the array.
    // We are asked to make sure that we maintain "sorted order",
    // in this case, of the "tallness" of the foodItems.
 
    if (bDoorOpen){
      // Only insert new food if the door is open, right?
      // Now fetch the tallness of the inputF FoodItem.
      // Note the use of the accessor method.
      float tallnessOfInputF = inputF.getTallness();
 
      // Search for the index at which to insert this foodItem,
      // to maintain the sorted order of the foodItem array.
      // This could also be accomplished with a while{} loop.
      int indexAtWhichToInsertInputF = 0;
      for (int i=0; i<nFoodItems; i++){
        if (foodItems[i].getTallness() < tallnessOfInputF){
          indexAtWhichToInsertInputF++;
        }
      }
 
      // It's possible we might need to enlarge the size of the array.
      if (nFoodItems >= foodItems.length){
        expandFoodItemArray();
      }
 
      // Shift all elements taller than inputF,
      // one position further down the array.
      for (int i=nFoodItems; i>indexAtWhichToInsertInputF; i--){
        foodItems[i] = foodItems[i-1];
      }
 
      // Insert the inputF. Note how simple this is.
      // Then, don't forget to increase the nFoodItems!
      foodItems[indexAtWhichToInsertInputF] = inputF;
      nFoodItems++;
 
    }
    else {
      System.out.println("Door must be open to insert an item.");
    }
  }
 
 
  //---------------------------
  void removeItem(){
    if (bDoorOpen){
      if (nFoodItems > 0){
        nFoodItems--;
      }
    }
    else {
      System.out.println("Door must be open to remove an item");
    }
  }
 
  //---------------------------
  void removeSpecificItem (int indexFromWhichToRemoveFoodItem){
    // To remove a specific item from the foodItems array,
    // copy all higher-numbered FoodItems down one position in the array.
    if ((indexFromWhichToRemoveFoodItem >= 0) &&
        (indexFromWhichToRemoveFoodItem < nFoodItems)){
      for (int i=indexFromWhichToRemoveFoodItem; i<nFoodItems; i++){
        foodItems[i] = foodItems[i+1];
      }
      nFoodItems--;
    }
  }
 
  //---------------------------
  int getIndexOfSelectedItem(){
    // Loop over all of my FoodItems,
    // and return the array-index of whichever one
    // reports that the mouse is hovering over it.
    int output = -1;
    for (int i=0; i<nFoodItems; i++){
      if (foodItems[i].isMouseHovering()){
        output = i;
      }
    }
    return output;
  }
 
  //---------------------------
  void expandFoodItemArray(){
    // Make a new array ("biggerArray") which
    // holds twice as much stuff as foodItems.
    FoodItem biggerArray[] = new FoodItem[ foodItems.length * 2];
 
    // Copy all of our FoodItems into that bigger array.
    for (int i=0; i<foodItems.length; i++){
      biggerArray[i] = foodItems[i];
    }
 
    // Re-assign foodItems to be that bigger array.
    foodItems = biggerArray;
  }
 
} // End of Refrigerator Class.
 
 
 
 
//=====================================================
//=====================================================
class FoodItem {
 
  float posx, posy;
  float tallness;
  color chroma;
  int   type;
 
  //-----------------------------------
  // Constructor for a FoodItem.
  // All necessary variables are passed in.
  FoodItem (float tallness, color chroma, int type){
    this.tallness = tallness;
    this.chroma   = chroma;
    this.type     = type;
  }
 
  //-----------------------------------
  // How a FoodItem should draw itself.
  // Note that a position is passed in.
  void draw (float x, float y){
    posx = x;
    posy = y;
 
    smooth();
    stroke(0);
    if (isMouseHovering()){
      strokeWeight(4);
    }
    else {
      strokeWeight(1);
    }
 
    fill(chroma);
    switch(type){
    case 0: // RECT
      rect(posx-6,posy-tallness, 12,tallness);
      break;
    case 1: // ELLIPSE
      ellipse(posx,posy-tallness/2, 12,tallness);
      break;
    case 2: // TRIANGLE
      triangle(posx-6,posy, posx+6,posy, posx,posy-tallness);
      break;
    }
    noSmooth();
  }
 
  //-----------------------------------
  // ACCESSOR METHODS.
 
  int getType(){
    return type;
  }
 
  float getTallness(){
    return tallness;
  }
 
  boolean isMouseHovering(){
    return (
    (  mouseX > posx-6) &&
      (mouseX < posx+6) &&
      (mouseY < posy) &&
      (mouseY > posy-tallness));
  }
 
} // End of FoodItem Class.

Important End-of-Semester Information

——————————————————-
FINAL EXAM date, time and location:

Monday, December 8
Room DH-2210 (Dougherty Hall)
8:30-11:30AM.

Arrive EARLY, like 8:15am!! Students arriving late will not be given extra time. Please arrive 15 minutes before the exam period begins to get to your assigned seat so you can hear the exam instructions completely.
Missing the exam will result in a failing grade for the exam. If you are ill or have a
family emergency during your exam time, you must have a valid documented excuse and
must speak with your instructor as soon as possible.
Bring 2 pencils, erasers, and your student ID card (or some other government-issued
photo ID) with you. Your ID will be checked at the exam. If you do not bring an ID, you
may be asked to leave the exam room.
You may not use electronic devices of any kind during the exam. This includes, but is
not limited to, cell phones, pagers, calculators, PDAs, computers, music players, etc. It is
better if you do not even bring these items to the exam room in the first place.
Please use the restroom before arriving at your exam room.

——————————————————-
WHAT TOPICS will be on the final exam? See these documents:
http://artscool.cfa.cmu.edu/~levin/courses/dmc/intro08/downloads/15100FinalInfoSheetF08.pdf
http://www.andrew.cmu.edu/course/15-100mooseNsquirrel/Exam3Overview.pdf

——————————————————-
FINAL EXPERIMENT PROJECTS and other HOMEWORK
– Final Experiments are due 3pm on Friday December 12. We will have a fun viewing-session/party in room CFA-303 at that time.
– All unfinished homework assignments should be uploaded by 3pm, Friday 12 December for grading. Missing assignments will not be accepted after that time.

——————————————————-
UNIVERSITY COURSE ASSESSMENTS:

The University Course Assessment (UCA) is open for your feedback, through Wednesday of this coming week. I really care about your feedback, and so does the school. I have received an automatic email informing me that 4 of you have still not filled this out — please take just a minute to fill out the form by going here: Link to the Carnegie Mellon portal at https://my.cmu.edu/site/main/page.academics and click on “University Course Assessment” under “Courses”.