Friday, February 12, 2010

The Pyramid Saga Continues

Finally I draw my pyramid. Before I post the actual code, a second addition to the blooper reel. Have a look at the blooper code and tell me why we're getting a rhombus. And what the correction in the code should be:

Rhombus pyramid:



public class Pyramid extends GraphicsProgram {

public void run() {

//X and Y coordinates for the starting (bottom-left) brick:
double xstart = getWidth()/2 -(1/2)*(BRICK_WIDTH)*(BRICKS_IN_BASE);
double ystart = getHeight()/2 + (1/2)*(BRICK_HEIGHT)*(BRICKS_IN_BASE);

//Outer loop to make a new row. The pyramid has as many rows as bricks in base.
for(int i = 0; i < BRICKS_IN_BASE; i++) {

double BricksInRow = BRICKS_IN_BASE;

double x = xstart;
double y = ystart;

//Inner loop to place bricks in a row
for(int j = 0; j < BricksInRow; j++) {

GRect brick = new GRect (x, y, BRICK_WIDTH, BRICK_HEIGHT);
add(brick);

x += BRICK_WIDTH; //place next brick forward

}

BricksInRow -= 1; //Make the next row 1 brick shorter
ystart = ystart - BRICK_HEIGHT; //and one brick higher
xstart += BRICK_WIDTH / 2; //and start 1/2 a brick to the right


}
}

//Width of each brick in pixels
private static final int BRICK_WIDTH = 15;

//Width of each brick in pixels
private static final int BRICK_HEIGHT = 6;

//Number of bricks in the base of the pyramid
private static final int BRICKS_IN_BASE = 14;



(I once asked my friend Ryan, who took CS in college, what CS exams look like, since clearly it's difficult to write many entire programs during an exam. He said that there is lots of tracing and troubleshooting of code, so I imagine this must be what taking a little test in CS class is like :] )


Here is the actual pyramid:



Here is the code:


/*
* File: Pyramid.java
* Name:
* Section Leader:
* ------------------
* First, you have an outer loop that says, "Start the next row". It does this by,
* once you've made a row, removing one of the bricks from Bricks_In_Base so that
* the second row is one brick shorter, and by moving the starting brick up by
* 1 brick-height up and 1/2 brick-width to the right.
*
* Second, you have an inner loop that says "Make a row." It does this by
* placing down a brick in the starting location, then adding Brick_Width to
* the x coordinate and laying another brick at the new x-coordinate, repeated
* until you get to the end of the number of bricks in your row
* (or, until the index j gets to Bricks_In_Base.)
*
*/

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

public class Pyramid extends GraphicsProgram {

public void run() {

//X and Y coordinates for the starting (bottom-left) brick:

double xstart = getWidth()/2 - (1/2)*(BRICK_WIDTH)*(BRICKS_IN_BASE);
double ystart = getHeight()/2 + (1/2)*(BRICK_HEIGHT)*(BRICKS_IN_BASE);

double BricksInRow = BRICKS_IN_BASE;

//Outer loop to make a new row. The pyramid has as many rows as bricks in base.
for(int i = 0; i < BRICKS_IN_BASE; i++) {

double x = xstart;
double y = ystart;

//Inner loop to place bricks in a row
for(int j = 0; j < BricksInRow; j++) {

GRect brick = new GRect (x, y, BRICK_WIDTH, BRICK_HEIGHT);
add(brick);

x += BRICK_WIDTH; //place next brick forward

}

BricksInRow -= 1; //Make the next row 1 brick shorter
ystart = ystart - BRICK_HEIGHT; //and one brick higher
xstart += BRICK_WIDTH / 2; //and start 1/2 a brick to the right


}
}

//Width of each brick in pixels
private static final int BRICK_WIDTH = 15;

//Width of each brick in pixels
private static final int BRICK_HEIGHT = 6;

//Number of bricks in the base of the pyramid
private static final int BRICKS_IN_BASE = 14;

}




What made it difficult: Algebra. The triangle has to be centered, and it should be flexible so that you can change the size of the bricks and the number of bricks in the pyramid. That means that the coorddinates of the starting brick have to vary depending on what the size constants are. If you have a look at the original coordinates for xstart and ystart (the x and y coordinates for the first brick of the bottom row), you'll see how much it depended on the constants.

The other thing that was tough for me is that I didn't figure out until much later that I should have two pairs of variables for the X and Y coordinates of the bricks. Arram tackled this problem in another language and did it with two pairs, and once I saw this I felt stupid for not having thought of that! You have xstart and ystart, which are the coordinates for the first brick of each row, and then x and y, the coordinates for every brick. (When you're making the first brick of the row in your inner loop, you set x =xstart, and then when you're ready to go up a row, you change xstart.) The whole time, I was in a tizzy trying to figure out how to go back to the left side of the pyyramid from the right once I've finished a row. So obvious now!

Lingering questions:

Well, the pyramid is supposed to be centered.

To make it centered, this is how I found the coordinates for the starting X: I found the center (using the getWidth method divided by 2) and then subtracted half the length of the pyramid. Same goes for the starting X, except for that I used the getHeight/d and added half the height of the pyramid.

However, if the pyramid is very big and needs the viewer to maximize the window, the pyramid is not centered and goes off the screen on one side. For example, this is what the screen looks like if I set the pyramid to be 200 bricks wide and tall:

Big pyramid:

I think that the bottom-left brick is actually in the CENTER of the view window! I thought I had written xstart and ystart so that the bottom brick would be appropriately off-center...What's going on?

1 comment:

  1. You do have the right idea, but you're forgetting oooone leeeettle thing about the way numbers work in Java.. Here's a hint: what's 1 divided by 2? (It's not the same as 0.5...)

    ReplyDelete