Stanford CS106A Assignment 2 Program Hierarchy Solution

31 Oct

The Program Hierarchy problem looks pretty intimidating at first glance, but it was actually fun once I got started. Here is the problem:

Here is my solution, which you can also find on gist:


The Programming Hierarchy Problem actually requires a little bit of basic math. I found it super helpful to draw out rectangles on a piece of white paper to figure out what I was doing. The part I had the most problem with was centering the words in each box. I got help from a friend, who suggested I think of a rectangle drawn around the words, so it’s just another rectangle I’m trying to center.

<pre>/*
 * File: ProgramHierarchy.java
 * Name: 
 * Section Leader: 
 * ---------------------------
 * This file is the starter file for the ProgramHierarchy problem.
 */

import acm.graphics.*;
import acm.program.*;
import java.awt.*;

public class ProgramHierarchy extends GraphicsProgram {	

	//width of each box in the picture
	private static final int Width = 150;

	// height of each box in the picture
	private static final int Height = 60;

	public void run() {
		drawProgramBox();
		drawConsoleLine();
		drawConsoleBox();
		drawGraphicsLine();
		drawGraphicsBox();
		drawDialogLine();
		drawDialogBox();
	}
	private void drawProgramBox() {
		int x = getWidth()/2 - Width/2; //finds center width and moves to starting point
		int y = getHeight()/2 - Height; //finds center height and moves to starting point
		GRect drawBox = new GRect (x, y, Width, Height);  
		add(drawBox); //adds the Program box
		GLabel program = new GLabel("Program", x, y);
		add(program); //adds the "Program" words, but in the wrong location
		double boxCenterX = Width/2;
		double boxCenterY = Height/2;
		double halfProgramWidth = program.getWidth()/2; //finds the center of the width for "program"
		double halfProgramHeight = program.getAscent()/2; //finds the center of the height for "program"
		program.move( (boxCenterX - halfProgramWidth) , (boxCenterY + halfProgramHeight) ); 
	}
	private void drawConsoleLine() {
		int x1 = getWidth()/2; //finds center width 
		int y1 = getHeight()/2; //finds center height 
		int x2 = getWidth()/2;  //width value remains the same
		int y2 = getHeight()/2 + Height; //finds end point for height
		GLine drawLine = new GLine (x1, y1, x2, y2);
		add(drawLine);
	}
	private void drawConsoleBox() {
		int x = getWidth()/2 - Width/2; //Width remains same as Program Box Width
		int y = getHeight()/2 + Height; //Height changes 
		GRect drawBox = new GRect (x, y, Width, Height); 		
		add(drawBox); //adds the Console box
		GLabel console = new GLabel ("ConsoleProgram", x, y); 
		add(console); //adds the "Console" words, but in the wrong location		
		double boxCenterX = Width / 2;
		double boxCenterY = Height / 2;
		double halfConsoleWidth = console.getWidth()/2; 
		double halfConsoleHeight = console.getAscent()/2; 
		console.move( (boxCenterX - halfConsoleWidth) , (boxCenterY + halfConsoleHeight) );
	}
	private void drawGraphicsLine() {
		int x1 = getWidth()/2;
		int y1 = getHeight()/2;
		int x2 = getWidth()/2 - 3 * (Width/2);
		int y2 = getHeight()/2 + Height;
		GLine drawLine = new GLine (x1, y1, x2, y2);
		add(drawLine);
	}
	private void drawGraphicsBox() {
		int x = getWidth()/2 - 2*Width;
		int y = getHeight()/2 + Height;
		GRect drawBox = new GRect (x, y, Width, Height); 
		add(drawBox); 
		GLabel graphics = new GLabel ("GraphicsProgram", x, y); 
		add(graphics); 
		double boxCenterX = Width / 2;
		double boxCenterY = Height / 2;
		double halfGraphicsWidth = graphics.getWidth()/2; 
		double halfGraphicsHeight = graphics.getAscent()/2; 
		graphics.move( (boxCenterX - halfGraphicsWidth) , (boxCenterY + halfGraphicsHeight) );
	}
	private void drawDialogLine() {
		int x1 = getWidth()/2;
		int y1 = getHeight()/2;
		int x2 = getWidth()/2 + 3 * (Width/2);
		int y2 = getHeight()/2 + Height;
		GLine drawLine = new GLine (x1, y1, x2, y2);
		add(drawLine);
	}
	private void drawDialogBox() {
		int x = getWidth()/2 + Width;
		int y = getHeight()/2 + Height;
		GRect drawBox = new GRect (x, y, Width, Height); 
		add(drawBox); 
		GLabel dialog = new GLabel ("DialogProgram", x, y); 
		add(dialog); 
		double boxCenterX = Width / 2;
		double boxCenterY = Height / 2;
		double halfDialogWidth = dialog.getWidth()/2; 
		double halfDialogHeight = dialog.getAscent()/2; 
		dialog.move( (boxCenterX - halfDialogWidth) , (boxCenterY + halfDialogHeight) );
	}
}</pre>
Advertisements

20 Responses to “Stanford CS106A Assignment 2 Program Hierarchy Solution”

  1. robg128 November 17, 2011 at 1:35 pm #

    Hi – I am just getting started with this class – and in looking for help I found your solutions. I am afraid to look at your solution, because I actually want to write the code myself so that I learn something. However, at first glance it looks a little challenging. The part that concerns me most, is how to center everything on the canvas. In other words, “the entire figure should be centered”. Any hints without spoiling it for me?

    Thanks

    • natasha the robot November 17, 2011 at 2:47 pm #

      Sure, you can start by centering the Program box on the following x and y coordinates:

      int x = getWidth()/2 – Width/2; //finds center width and moves to starting point

      int y = getHeight()/2 – Height; //finds center height and moves to starting point

      getWidth() and getHeight() gets the width and height of the whole application window

      Width and Height get the width of the rectangle itself.

  2. KarelTheRobot November 24, 2011 at 2:04 am #

    Hi Natasha,

    I have the same concern as robg128 and that is the assignment’s requirement to center the whole diagram. What you have done was to center only the program box.

    Anyways good software programming 🙂

    • natasha the robot November 24, 2011 at 10:12 am #

      I am starting a later assignment using this solution (Section Assignment 7), and realized that you’re right. You need to make diagram into a GCompound (like his GFace program) and then center the GCompound as a whole.

  3. KarelTheRobot November 25, 2011 at 6:17 am #

    You could do that ?? center the whole diagram as a whole? How?

  4. praven moorthy December 9, 2011 at 5:57 am #

    /*
    * File:ProgramHierarchy.java
    * ————————–
    * In this program it draws the program hierarchy of ACM library
    * the whole graphics is centered on the screen
    */
    import acm.graphics.*;
    import acm.program.*;

    public class ProgramHierarchy extends GraphicsProgram{

    //width of the rectangle
    private static final int RECT_WIDTH = 120;

    //height of the rectangle
    private static final int RECT_HEIGHT = 40;

    public void run(){
    //draws the graphics
    drawProgramBox();
    drawConsoleLine();
    drawConsoleBox();
    drawGraphicsLine();
    drawGraphicsBox();
    drawDialogLine();
    drawDialogBox();

    }

    //draws the program box with the label
    private void drawProgramBox(){

    double x = getWidth()/2 – RECT_WIDTH/2;
    double y = getHeight()/2 – RECT_HEIGHT;
    GLabel programLabel = new GLabel(“Program”);
    GRect programBox = new GRect(x,y,RECT_WIDTH,RECT_HEIGHT);
    programLabel.setLocation((getWidth()/2 – programLabel.getWidth()/2),
    (getHeight()/2-programLabel.getAscent()));
    add(programLabel);
    add(programBox);
    }

    //draws the line for console box
    private void drawConsoleLine(){

    double x1 = getWidth()/2;
    double x2 = getHeight()/2;
    double x3 = x1;
    double x4 = getHeight()/2 + RECT_HEIGHT;
    GLine consoleLine = new GLine(x1,x2,x3,x4);
    add(consoleLine);
    }

    //draws console program box with label
    private void drawConsoleBox(){

    double x = getWidth()/2 – RECT_WIDTH/2;
    double y = (getHeight()/2 – RECT_HEIGHT) + (2*RECT_HEIGHT);
    GLabel consoleLabel = new GLabel(“Console Progam”);
    GRect consoleBox = new GRect(x,y,RECT_WIDTH,RECT_HEIGHT);
    consoleLabel.setLocation((getWidth()/2 – consoleLabel.getWidth()/2),
    (getHeight()/2 – consoleLabel.getAscent())+2*RECT_HEIGHT);
    add(consoleLabel);
    add(consoleBox);
    }

    //draws the line for graphics box
    private void drawGraphicsLine(){

    double x1 = getWidth()/2;
    double x2 = getHeight()/2;
    double x3 = getWidth()/2 – 1.5*RECT_WIDTH;
    double x4 = getHeight()/2 + RECT_HEIGHT;
    GLine graphicsLine = new GLine(x1,x2,x3,x4);
    add(graphicsLine);
    }

    //draws console graphics box with label
    private void drawGraphicsBox(){

    double x = getWidth()/2 -2*RECT_WIDTH;
    double y = (getHeight()/2- RECT_HEIGHT) + (2*RECT_HEIGHT) ;
    GLabel graphicsLabel = new GLabel(“Graphics Progam”);
    GRect graphicsBox = new GRect(x,y,RECT_WIDTH,RECT_HEIGHT);
    graphicsLabel.setLocation((getWidth()/2 – graphicsLabel.getWidth()/2)-(4.5*RECT_HEIGHT),
    (getHeight()/2 – graphicsLabel.getAscent())+2*RECT_HEIGHT);
    add(graphicsLabel);
    add(graphicsBox);
    }

    //draws the line for dialog box
    private void drawDialogLine(){

    double x1 = getWidth()/2;
    double x2 = getHeight()/2;
    double x3 = getWidth()/2 + 1.5*RECT_WIDTH;
    double x4 = getHeight()/2 + RECT_HEIGHT;
    GLine dialogLine = new GLine(x1,x2,x3,x4);
    add(dialogLine);
    }

    //draws console dialog box with label
    private void drawDialogBox(){

    double x = getWidth()/2 + RECT_WIDTH;
    double y = (getHeight()/2- RECT_HEIGHT) + (2*RECT_HEIGHT) ;
    GLabel dialogLabel = new GLabel(“Graphics Progam”);
    GRect dialogBox = new GRect(x,y,RECT_WIDTH,RECT_HEIGHT);
    dialogLabel.setLocation((getWidth()/2 – dialogLabel.getWidth()/2)+(4.5*RECT_HEIGHT),
    (getHeight()/2 – dialogLabel.getAscent())+2*RECT_HEIGHT);
    add(dialogLabel);
    add(dialogBox);
    }

    }

  5. Daniel December 11, 2011 at 12:51 pm #

    I would write a method to draw a labelled box in order to avoid duplicate code.

    For example:

    private void drawBox(double x, double y, String text) {
    		// draw box
    		GRect box = new GRect(x, y, BOX_WIDTH, BOX_HEIGHT);
    		add(box);
    		
    		//print label
    		GLabel label = new GLabel(text);
    		double textWidth = label.getWidth();
    		double textAscent = label.getAscent();
    		label.setLocation(x + (BOX_WIDTH / 2) - (textWidth / 2), y + (BOX_HEIGHT / 2) + (textAscent / 2));
    		add(label);
    }
    
    • Valentin March 27, 2012 at 1:27 pm #

      I tried doing this, but i find that unless i declare the X GRect x and y inside each box, i can’t get the whole thing to center correctly. It does not get the getWidth() and getHeight() correctly… am i doing something wrong?

      • Daniel April 1, 2012 at 6:03 am #

        I don’t see the problem. My method calls look like this:

        public void run() {
        		// find center
        		int x = getWidth() / 2;
        		int y = getHeight() / 2;
        		
        		// draw boxes with labels and lines
        		
        		// draw box program
        		drawBox(x - (BOX_WIDTH / 2), y - ((2 * BOX_HEIGHT + VERTICAL_SPACE) / 2), "Program");
        		
        		// draw box GraphicsProgram
        		drawBox(x - (1.5 * BOX_WIDTH + VERTICAL_SPACE), y + (VERTICAL_SPACE / 2), "GraphicsProgram");
        		// draw connecting line for box GraphicsProgram 
        		connectBox(x - (1.5 * BOX_WIDTH + HORIZONTAL_SPACE), y + (VERTICAL_SPACE / 2));
        	
        		//draw box ConsoleProgram
        		drawBox(x - (BOX_WIDTH / 2), y + (VERTICAL_SPACE / 2), "ConsoleProgram");
        }
        
      • Daniel April 1, 2012 at 6:09 am #

        The whole program looks like this:

        import acm.graphics.*;
        import acm.program.*;
        import java.awt.*;
        
        public class ProgramHierarchy extends GraphicsProgram {	
        	
        	private static final int BOX_WIDTH = 160;
        	private static final int BOX_HEIGHT = 80;
        	private static final int HORIZONTAL_SPACE = 20;
        	private static final int VERTICAL_SPACE = 80;
        	
        	public void run() {
        		// find center
        		int x = getWidth() / 2;
        		int y = getHeight() / 2;
        		
        		// draw boxes with labels and lines
        		
        		// draw box program
        		drawBox(x - (BOX_WIDTH / 2), y - ((2 * BOX_HEIGHT + VERTICAL_SPACE) / 2), "Program");
        		
        		// draw box GraphicsProgram
        		drawBox(x - (1.5 * BOX_WIDTH + VERTICAL_SPACE), y + (VERTICAL_SPACE / 2), "GraphicsProgram");
        		// draw connecting line for box GraphicsProgram 
        		connectBox(x - (1.5 * BOX_WIDTH + HORIZONTAL_SPACE), y + (VERTICAL_SPACE / 2));
        	
        		//draw box ConsoleProgram
        		drawBox(x - (BOX_WIDTH / 2), y + (VERTICAL_SPACE / 2), "ConsoleProgram");
        	}
        	
        	private void drawBox(double x, double y, String text) {
        		// draw box
        		GRect box = new GRect(x, y, BOX_WIDTH, BOX_HEIGHT);
        		add(box);
        		
        		//print label
        		GLabel label = new GLabel(text);
        		double textWidth = label.getWidth();
        		double textAscent = label.getAscent();
        		label.setLocation(x + (BOX_WIDTH / 2) - (textWidth / 2), y + (BOX_HEIGHT / 2) + (textAscent / 2));
        		add(label);
        	}
        	
        	private void connectBox(double box2X, double box2Y) {
        		int box1X = getWidth() / 2;
        		int box1Y = getHeight() / 2 - VERTICAL_SPACE / 2;
        		add(new GLine(box1X, box1Y, box2X, box2Y));
        		
        	}
        }
        
      • Daniel April 1, 2012 at 6:13 am #

        …well, I did not really finish it, but it shows the solution.

  6. Sayyid Sofwan (@ssofwan93) June 14, 2012 at 2:54 am #

    Hi!! I used quite a different technique by writing methods for doing the line, rectangle, and labels..
    Here is my code.. What do you think..?

    
    public class GraphicsHierarchy extends GraphicsProgram {
    	
    	private static final int REC_WIDTH = 100;
    	private static final int REC_HEIGHT = 35;
    	private static final int DIFF = (REC_HEIGHT / 2) + 10;
    	
    	public void run() {
    		GRect rect1 = drawRect(0,-DIFF);
    		GRect rect2 = drawRect(0, DIFF);
    		GRect rect3 = drawRect(REC_WIDTH + (DIFF-10), DIFF); //Draws several rectangle with parameters 
    		GRect rect4 = drawRect(-REC_WIDTH - (DIFF-10), DIFF);  // is its difference from mid-point
    		addLabelLineRect(rect1,rect2,rect3, rect4); //redirects program to a method which adds all objects
    	}
    	
    	/*This method generates a rectangle according to constant height and width specified above
    	 * and finds the actual coordinates from parameters (difference from mid-point)*/
    	private GRect drawRect(int xMid, int yMid){
    		int x = ((getWidth()/2) + xMid) - (REC_WIDTH/2);
    		int y = ((getHeight()/2) + yMid) - (REC_HEIGHT/2);
    		GRect rect = new GRect(x, y, REC_WIDTH, REC_HEIGHT);
    		return rect;
    		
    	}
    	
    	/*This method just adds all objects in the program*/
    	private void addLabelLineRect(GObject obj1, GObject obj2, GObject obj3, GObject obj4){
    		add(putLabel(obj1, "Program"));
    		add(putLabel(obj2, "ConsoleProgram"));
    		add(putLabel(obj3, "DialogProgram"));
    		add(putLabel(obj4, "GraphicsProgram"));
    		add(lineObj(obj1, obj2));
    		add(lineObj(obj1, obj3));
    		add(lineObj(obj1, obj4));
    		add(obj1); add(obj2); add(obj3); add(obj4);
    	}
    	
    	/*This method connects the center of two rectangle (origin and end) with a line
    	 * The parameters are 2 GObects which we want to connect with a line*/
    	private GLine lineObj(GObject origin, GObject end){
    		int xOrg = (int) (origin.getX() + (origin.getWidth()/2));
    		int yOrg = (int) (origin.getY() + origin.getHeight());
    		int xEnd = (int) (end.getX() + end.getWidth()/2);
    		int yEnd = (int) end.getY();
    		GLine line = new GLine(xOrg, yOrg, xEnd, yEnd);
    		return line;
    		
    	}
    	
    	/*This method centers and puts a label on a rectangle. 
    	 * The parameters are the object(which we want to put a label) and the text*/
    	private GLabel putLabel(GObject object, String text){
    		GLabel label = new GLabel(text);
    		int x = (int) ((object.getX() + object.getWidth()/2) - label.getWidth()/2);
    		int y = (int) ((object.getY() + object.getHeight()/2) + label.getAscent()/2);
    		label.setLocation(x, y);
    		return label;
    	}
    
    }
    
  7. zwip778 August 19, 2012 at 5:39 am #

    The problem with your answer Natasha (of course, I am a beginner so it’s just my opinion) is that you centered the first box but the whole figure (the three boxes).

    If I am wrong, I would appreciate some help. Great blog, keeps me motivated, thank you

    • Natasha Murashev August 19, 2012 at 7:59 am #

      I was just a beginner like you when I posted these solutions, so there is definitely a big chance that this solution is not correct. There are definitely better ways to do this problem.

  8. Paul S McLaughlin August 23, 2012 at 3:16 pm #

    Hi:

    I’m doing this class via the free online version and your example helped me understand this question a lot better but also made me realize that my solution was probably overkill 😉

    Unfortunately, I was too far along to go back so I finished using a more algorithmic solution for calculating the x and y coordinates. Interestingly it works no matter how many boxes are in the second row.

    I’d paste the code here but the formatting seems to get screwed up when I do that. Any ideas?

    • Natasha Murashev August 23, 2012 at 8:58 pm #

      Hi Paul,

      I’d love to see your code! Here is how you can format it in wordpress: http://natashatherobot.com/2012/02/03/how-to-embed-code-into-your-wordpress-com-blog/. If that doesn’t work, just paste in your code, and I’ll format it for you in the admin secion (which is what I’ve been doing for everyone else).

      Great job for finishing this!
      Natasha

    • Paul S McLaughlin August 24, 2012 at 9:58 am #

      It doesn’t seem to work. Perhaps it’s because you can edit html as the admin and these reply boxes don’t seem to let you do that.

      Anyway, my version is below. Hope that someone finds it useful.

      /* 
       * File: GraphicsHierarchy.java
       * ----------------------------
       * This program is a solution for GraphicsHierarchy problem for Stanford's online version of CS106A.
       */
      
      import acm.program.*;
      import acm.graphics.*;
      
      
      
      public class GraphicsHierarchy extends GraphicsProgram {
      	
      	private static final double BOX_WIDTH = 100; // needs to be at least 100 to fit all labels.  if NUM_BOXES &gt; 7 all boxes will not fit width of diplay for BOX_WIDTH &gt; 100
      	private static final double BOX_HEIGHT = 40;
      	private static final double BOX_SPACER = 20;  //spacer between boxes
      	private static final double NUM_BOXES = 4;  //Total number of boxes.   One in first row plus others in second row. this will actually work for any NUM_BOXES but can exceed the screen width as numbers get larger
      	
      	
      	public void run() { 
      
      		for (int i=0; i0) {
      						double lineTermX = getWidth()/2; // find center to top box for line terminus
      						double lineTermY = getHeight()/2 - BOX_HEIGHT;  //Adjusts up to bottom of top row
      						double lineStartX = xCoord + BOX_WIDTH/2; 
      						GLine boxline = new GLine(lineStartX,yCoord,lineTermX,lineTermY);						
      						add(boxline);
      				}
      			}
      			
      			/*
      			 * method writeLabel adds a label to each box after finding the center of the box and hte appropriate place to start.
      			 * Label is centered in middle of the box both horizontally and vertically.  To figure the centers you need to both figure out the middle of the box and the middle of the label.
      			 * So for the x direction you start at the left side of the label move right half the width of the box +BOX_WIDTH/2 the move back left half the width of the label -boxlabel.getWidth()/2
      			 * You do basically the same in the y direction except adjusting for half the height of the box +BOX_HEIGHT/2 and half the height of the text +boxlabel.getAscent()/2
      			 * REMEMBER that Y increases as you go down, not up!
      			 */
      			
      			private void writeLabel(int i, double xCoord, double yCoord) {
      				String class1 = ("");
      				
      				if (i==0) class1 = ("Program");
      				else if (i==1) class1 = ("GraphicsProgram");
      				else if (i==2) class1 = ("ConsoleProgram");
      				else if (i==3) class1 = ("DialogProgram");
      				else if (i==4) class1 = ("Label 4");  //extra labels if you want more boxes
      				else if (i==5) class1 = ("Label 5");
      				else if (i==6) class1 = ("Label 6");
      				else if (i==7) class1 = ("Label 7");
      			
      				GLabel boxlabel = new GLabel(class1);
      				double labelXCoord = xCoord + (BOX_WIDTH/2 - boxlabel.getWidth()/2); // adjusts for center of box and the adjusts for width of label
      				double labelYCoord = yCoord + BOX_HEIGHT/2 + boxlabel.getAscent()/2; // adjusts for center of box and the adjusts for height of label
      				add(boxlabel,labelXCoord,labelYCoord);
      			}
      				
      }
      
      • Natasha Murashev August 24, 2012 at 1:51 pm #

        Thanks! Just added the formatting 🙂

Trackbacks/Pingbacks

  1. » CS106a Assignment 2 – Program Class Hierarchy …zero to hero - March 7, 2012

    […] Natasha The Robot’s Solution […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s