Results 1 to 9 of 9
  1. #1
    sonny's Avatar
    sonny is offline Senior Member
    Join Date
    Feb 2010
    Location
    North West England
    Posts
    146
    Rep Power
    0

    Cool Stepwise refinement,, any suggestions?

    i'm still just beginning and teaching myself via online courses,
    ive sorta got my head around control statements and i've just done some reading on methods :confused: and stepwise refinement.
    i would be most grateful for any feedback on the following code examples
    (which all work :D and are hopefully self explanatory) particularly on ways of refining or improving them.

    thanks, in advance
    Sonny


    pyramid program
    Java Code:
    /*File pyramid.java
     * this program draws a pyramid
     * Programming exercise 1 cs106a stanford:
     * Assignment #2: Simple Java Programs
     *  Write a GraphicsProgram subclass that draws a pyramid consisting of bricks
    arranged in horizontal rows, so that the number of bricks in each row decreases by
    one as you move up the pyramid
    The pyramid should be centered at the bottom of the window and should use
    constants for the following parameters:
    BRICK_WIDTH The width of each brick (30 pixels)
    BRICK_HEIGHT The height of each brick (12 pixels)
    BRICKS_IN_BASE The number of bricks in the base (14)
    The numbers in parentheses show the values for this diagram, but you must be able
    to change those values in your program.
     */
    
    import acm.program.*;
    import acm.graphics.*;
    
    
    public class pyramid extends GraphicsProgram {
    
    	private static final int BRICK_WIDTH = 30; //The width of each brick (30 pixels)
    	private static final int BRICK_HEIGHT = 12; //The height of each brick (12 pixels)
    	private static final int BRICKS_IN_BASE = 14;  //The number of bricks in the base (14)
    	 
    	
    	public void run(){
    		int w = getWidth();
    		int h = getHeight();
    		int bricksInCourse = BRICKS_IN_BASE;
    		add(new GLabel(""+(w)+"w "+(h)+"h ", 10,20));// just to help me along 
    		for(int j=0;j<BRICKS_IN_BASE;j++){
    			for (int i = 0; i<bricksInCourse;i++){
    				int x = ((w/2)-(bricksInCourse*BRICK_WIDTH/2))+(i*BRICK_WIDTH);
    				int y = (h-BRICK_HEIGHT-1)-(j*BRICK_HEIGHT);
    				GRect brick = new GRect(x, y, BRICK_WIDTH, BRICK_HEIGHT);  
    				add (brick);
    				pause(15);	
    			}
    			bricksInCourse--;
    		}
    	}
    }



    i realised after my first attempt at drawing a target(below)which used a method to calculate the radii
    that relationship of the radii of circles provided a simpler solution if you count down variable i from 3 to 1, hopefully you can see my both my initial and ultimate method of doing it. (what is the plural of radius && how do you spell it ! :))

    Java Code:
    /*File target.java
     * this program draws a target
     * Assignment #2: Simple Java Programs
     * Programming exercise 2 draw a target
     * The outer circle should have a radius of one inch (72 pixels), the white circle
     * has a radius of 0.65 inches, and the inner red circle has a radius of 0.3 inches. The
     *figure should be centered in the window of a GraphicsProgram subclass.
     *  
     */
    
    import java.awt.Color;
    
    import acm.program.*;
    import acm.graphics.*;
    
    public class target extends GraphicsProgram {
    	private static final int PPI = 72; //pixel per inch/outer circle rad pixels
    	private static final int ICR = 30*PPI/100; // centre circle radius pixel ratio
    	private static final int WCR = 65*PPI/100; // white circle radius pixel ratio
    	
    	public void run(){
    		int w = getWidth()/2;
    		int h = getHeight()/2;
    		for(int i=3;i>0;i--){// using i to determine (int r)
    			int r = i*(WCR-ICR)-5;
    			//int r = setRad(i);  // if calling setRad then set for loop to:(int i=0;i<3;i++)
    			GOval target = filledCircle(w,h,r);
    			if(i%2!=0){// (i%2==0) if calling setRad
    				target.setFillColor(Color.RED);
    				target.setColor(Color.RED);
    			}else{
    				target.setFillColor(Color.WHITE);
    				target.setColor(Color.WHITE);
    			}
    			add(target);
    			pause(1000);
    		}
    	}
    	
    		private int setRad(int r) {
    		if (r==0)return PPI;
    		if (r==1)return WCR;
    		if (r==2)return ICR;
    		return r;
    		
    	}
    		private GOval filledCircle (int x, int y, int r){
    		GOval circle = new GOval(x-r,y-r ,r*2,r*2);
    		circle.setFilled(true);
    		return circle;
    		
    		
    		}
    }
    Last edited by sonny; 02-27-2010 at 07:50 AM.

  2. #2
    gcalvin is offline Senior Member
    Join Date
    Mar 2010
    Posts
    953
    Rep Power
    5

    Default

    Hi Sonny,

    I think you're missing the point a bit on these two exercises by putting all of your code directly into the run() method. Try these strategies and see if they don't give you simpler, more readable code:


    Pyramid:

    Write a drawBrick(double x, double y) method. The brick's width and height should come from constants in your Pyramid class. Test your method by putting something like drawBrick(10, 10) in your run() method.

    Next, write a drawRowOfBricks(double x, double y, int n) method that uses a for loop and the drawBrick(x, y) you wrote in the first step. Test it by changing your run() method to call drawRowOfBricks(10, 10, 5).

    Now write drawCenteredRowOfBricks(double y, int n) that figures out where the first x should be and then calls drawRowOfBricks(x, y, n). Test it with something like drawCenteredRowOfBricks(10, 5) in your run() method.

    Once you've implemented those three methods, you can do your run() method with one call to find the bottom of the window, and then one for loop to draw the whole pyramid. (Hint: your for loop won't start with "for (int i = 0; ..." but rather with "for (int i = BRICKS_IN_BASE; ...".) Arguably, it's still better style to put that code in a separate drawPyramid() method, and call that from run().

    Target:

    Using a similar approach to above, write a method that draws a filled circle based on its center point, radius in inches, and color. Do the inches to pixels conversion in a separate method.

    The whole idea is to try to think in terms of each method doing one simple thing. I know it seems silly now -- why put code in a separate method if you're only calling it from one place, right? But trust me and go through the motions of doing it, and then take a look at your finished program and tell me if it isn't cleaner and easier to read. After all, these are exercises. The point isn't to draw a pyramid or a target but to internalize the concepts.

    -Gary-

  3. #3
    sonny's Avatar
    sonny is offline Senior Member
    Join Date
    Feb 2010
    Location
    North West England
    Posts
    146
    Rep Power
    0

    Thumbs up sorry for delayed response but haven't been on for a over a week

    The whole idea is to try to think in terms of each method doing one simple thing. I know it seems silly now -- why put code in a separate method if you're only calling it from one place, right?
    After all, these are exercises. The point isn't to draw a pyramid or a target but to internalize the concepts.

    I see what you mean many thanks Gary a really great help,
    my last programming experience was back in the 1980's when i was kid and i was pretty adept back then at using BASIC. Its difficult getting my head around methods, i keep thinking "subroutine" but its not the same thing.


    I have rewritten pyramid (below) and it did take me much longer to do it this way than the first way however i have been re writing some of the other exercises and I think the penny is starting to drop.

    Would it be fair to say that as a general rule of thumb I should try to avoid using control statements within run() and create a method

    heres my rewrite which IS much easier follow:D

    Java Code:
    import acm.program.*;
    import acm.graphics.*;
    
    
    public class pyramid2 extends GraphicsProgram {
    
    	private static final int BRICK_WIDTH = 30; //The width of each brick (30 pixels)
    	private static final int BRICK_HEIGHT = 12; //The height of each brick (12 pixels)
    	private static final int BRICKS_IN_BASE = 14;  //The number of bricks in the base (14)
    	 
    	
    	public void run(){
    		beginPyramid();
    	}
    	
    	/*determine y coordinates to start each row of bricks calls rowOfBricks*/	
    	private void beginPyramid(){
    		int h = getHeight();
    		int rows=0;
    		for(int i=BRICKS_IN_BASE;i>0;i--){
    			int y = (h-BRICK_HEIGHT-1)-(rows*BRICK_HEIGHT);
    			rowOfBricks(y,i);
    			rows++;
    		}
    	}
    	
    	/* determines x coordinates for all the bricks in the row(n)and calls draw brick n times*/
    	private void rowOfBricks(double y, int n){
    		int x = (getWidth()/2)-(n*BRICK_WIDTH/2);
    		for (int i=0;i<n;i++){
    			drawBrick(x+(i*BRICK_WIDTH),y); 
    		}
    	}
    	
    	/*  draws a brick at coordinates x and y */
    	private GRect drawBrick(double x, double y){
    		GRect brick = new GRect(x,y,BRICK_WIDTH,BRICK_HEIGHT);
    		pause(15);
    		add(brick);
    		return brick;
    	}
    }
    :p I still have my "L" plates on...... directions and explanations are far more help than blaring your Horn! :p Watching:CS106a on YouTube \Reading The Art & Science of Java by Eric S Roberts

  4. #4
    gcalvin is offline Senior Member
    Join Date
    Mar 2010
    Posts
    953
    Rep Power
    5

    Default

    Nice work, Sonny. I came up learning BASIC as well, on very low-memory machines (TI-99/4a -- a whole 16K of RAM!) and while we learned some things that are very valuable, we were also forced to learn some bad habits.

    One of the big advantages of methods is variable scoping. If you keep your methods down to one loop, for example, and call a method for the inner loop, then you can always use 'i' as your index variable, and reduce the complexity you're carrying around in your head. Of course it doesn't always make sense to do it this way, but quite often it does. In BASIC we didn't have that luxury. Even if we used a GOSUB, we were still dealing with the same global variables, and had to keep track of all of them program-wide.

    By the way, your beginPyramid() can still be a little simpler:
    Java Code:
    	/*determine y coordinates to start each row of bricks calls rowOfBricks*/	
    	private void beginPyramid(){
    		int y = getHeight();
    		for(int i=BRICKS_IN_BASE; i > 0; i--){
                            y -= BRICK_HEIGHT;
    			rowOfBricks(y, i);
    		}
    	}
    Cheers!

    -Gary-

  5. #5
    sonny's Avatar
    sonny is offline Senior Member
    Join Date
    Feb 2010
    Location
    North West England
    Posts
    146
    Rep Power
    0

    Default Snap!

    WOW! TI99/4a , SNAP! I had one of those! :D
    probably the best machine of its day, i think it was the first 16bit home computer, All my mates had specy's and vic 20's, which had loads of games. but the TI outstripped em all, you just had to be prepared to type in games from magazines and stuff then save them. oh man! good times indeed!
    i intend trying to do carwars in Java once i progress a bit, i loved that game

    y -= BRICK_HEIGHT;
    Brilliant, much simpler, that hadnt occured to me, but seems so obvious

    many thanks
    Sonny
    :p I still have my "L" plates on...... directions and explanations are far more help than blaring your Horn! :p Watching:CS106a on YouTube \Reading The Art & Science of Java by Eric S Roberts

  6. #6
    Join Date
    May 2011
    Posts
    2
    Rep Power
    0

    Default Question...

    "private void rowOfBricks(double y, int n)"

    This is coming from a serious newbie, so I hope you will bear with me if the answer to this question should be obvious.

    Why set the type for 'y' to double since the value passed on to this method for 'y' is from a variable that was type int? All that does is just tack ".0" to the end of it, right?

    Thanks.

  7. #7
    gcalvin is offline Senior Member
    Join Date
    Mar 2010
    Posts
    953
    Rep Power
    5

    Default

    Quote Originally Posted by hoosiertechguy View Post
    Why set the type for 'y' to double since the value passed on to this method for 'y' is from a variable that was type int? All that does is just tack ".0" to the end of it, right?
    That's an excellent question. Basically, we specify a double because the drawBrick() method we're going to call wants a double. And we specified doubles in drawBrick() because the GRect() constructor provided by the library we're using wants doubles. That may seem strange as well (pixels on the screen are discrete, right? you can't really put a dot at 22.3, 57.8 on the screen, can you?) but it turns out that in lots of situations, using doubles for screen coordinates makes sense. I'll let you discover those situations on your own -- take my word for it for now. You're right that in this program it wouldn't make any difference, but it's generally a good habit to use the same types used by the methods you're calling.

    -Gary-

  8. #8
    Join Date
    May 2011
    Posts
    2
    Rep Power
    0

    Default

    Thank you, Gary. That makes sense now that I actually take a closer look at the drawBrick method. Does it matter when you cast the int as a double? The variable 'y' is cast as a double in the rowOfBricks method, but 'x' is not cast as a double until the drawBrick method, I'm not trying to nitpick, I'm just trying to wrap my mind around the best practices, so I hope no one takes offense. My current profession is as a Small Business Network Engineer, so I'm a little bit Obsessive/Compulsive about these kind of things, I guess.

  9. #9
    gcalvin is offline Senior Member
    Join Date
    Mar 2010
    Posts
    953
    Rep Power
    5

    Default

    You're right that the x in the body of rowOfBricks() should probably be a double too, as should the h and y in beginPyramid(). Again, for this exercise, it didn't make any real difference.

    -Gary-

Similar Threads

  1. Book suggestions
    By Lil_Aziz1 in forum Java Applets
    Replies: 3
    Last Post: 01-04-2010, 03:38 AM
  2. Replies: 8
    Last Post: 10-29-2009, 04:35 PM
  3. Please post your suggestions about this code
    By mathansj in forum Advanced Java
    Replies: 8
    Last Post: 02-15-2009, 04:41 PM
  4. any suggestions?
    By PureAwesomeness in forum New To Java
    Replies: 4
    Last Post: 01-19-2009, 08:34 AM
  5. Suggestions of crufty or otherwise bad APIs
    By Andre in forum Forum Lobby
    Replies: 8
    Last Post: 11-18-2008, 12:06 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •