Monday, September 13, 2010

Animated Bouncing Ball- The Bill Version

After I wrote up my Animated Bouncing Ball solution, my friend Bill left a comment. His suggestion had to do with how I tracked the location of my ball so I'd know when it had hit a wall and should reverse directions. My solution had been to declare the variables x and y, set them to the initial x and y coordinates of my ball, and change their value after each move the ball made to make them match the new coordinates. As Bill said, this is quite poor because you're tracking x and y in two places, leaving it inefficient and susceptible to bugs.

The truth is, I had wanted to use a built-in getX() kind of method, but I didn't think such a method existed, since it wasn't listed in the textbook. Then I talked to Andrew, a friend from work, and realized that not only were there hundreds of other methods for GOval than were in the book, but that Java has dozens of ways to conceptualize an oval, only one of which is the GOval class. It's like I've been walking around with blinders on and suddenly the blinders have come off and I realize there's much more than I even knew to look for. As my friend Jane says, half of programming is just knowing what to Google.

So, I looked up to see whether I can use getX() with the GOval class to make my program more efficient, and lo and behold, I can! New and improved code below.


/*
* File: BounceBall.java
* Name: 
* Section Leader:
* -----------------

*/

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

public class BounceBall extends GraphicsProgram {
    public void run() {
        
//Create ball in initial centered position
     int centeredx = (getWidth()-DIAMETER)/2;
     int centeredy = (getHeight()-DIAMETER)/2;
        
     GOval ball = new GOval (centeredx, centeredy, DIAMETER, DIAMETER); 
        ball.setFilled(true);
        add(ball);

        int dx = 1; //Setting the size of the ball's steps
        int dy = 1;
        
        while(true) { //Getting the ball to move
            ball.move(dx, dy);
            pause(PAUSE_TIME);

//  Declare x and y variables to locate the ball
          
            double x = ball.getX(); 
            double y = ball.getY();
            
//"If" statements to test whether the ball is at a wall, and if so, reassign dx or dy to switch direction.
            
            if (x >= getWidth()-DIAMETER) { //If it hits the right-hand wall`
             dx=-dx;     
            }
            if (y >= getHeight()-DIAMETER) { //If it hits the bottom
             dy=-dy;
            }
            if (x == 0) { //If it hits the left-hand wall
             dx=-dx;
            }
            if (y == 0) {//If it hits the top
             dy=-dy;
            }
        }
        }
        
//Private Constants
        
        private static final int DIAMETER = 40;
        private static final int PAUSE_TIME = 20;     
      
    }

Monday, August 9, 2010

Program to Draw an Animated Bouncing Ball

As I learn to code, programmer friends emphasize that I should break a problem down into chunks that I solve sequentially. It helps me think clearly to focus on one goal at a time.

For example, a recent question asked me to create a ball that bounces within the graphics window, like this.

The 3 main parts of this problem, once you draw the ball, are:

1) Get the ball to MOVE.
2) Get the ball to STOP at the edge of the graphics window.
3) Get the ball to BOUNCE to the next wall, over and over.

Here is how I tackled them:

Step 1. Get the ball to MOVE:
When I started the problem, I just wanted to make a ball on the screen and get it to move in the direction I told it to. It would start moving at an x=y diagonal. I wrote a ‘while’ loop that says, “As long as we’re in this loop, move the ball one pixel to the left (dx) and one pixel down (dy).”

At this point, I didn’t know whether I’d have to tell the loop to make the ball stop moving when it got to the edge of the window or whether it would automatically do so. (Silly me). As it turns out, it really goes on forever! I ran the app to see what would happen, and the ball, once it reached the end of the window, kept going, apparently forever. (See for yourself.) That meant I next had to figure out how to detect the edge of the window and make the ball stop.

Also, the textbook problem required that the ball start off in the middle of the screen, though in my screencast you’ll notice that I had it starting at the top-left corner. This is because, for the Java graphics library, (0,0) is the top-left corner, so it’s easy to start the ball there, whereas placing it in the center requires a trivial bit of algebra that I knew I’d be able to do later. I just wanted to make the ball quickly and confirm that my ‘while’ loop could get the ball to move.

public class BounceBall extends GraphicsProgram {
    public void run() {
   
//First make the ball...    
   GOval ball = new GOval (0, 0, DIAMETER, DIAMETER);
        ball.setFilled(true);
        add(ball);
        
        double dx = 1;
        double dy = 1;
 
        while(true) {
            ball.move(dx, dy);
            pause(PAUSE_TIME);
            
        }
//Private Constants   
    private static final int DIAMETER = 40;
    private static final int PAUSE_TIME = 20;
    }

2) Get the ball to STOP at the edge of the graphics window.

Now I needed to figure out how to make my program “know” when it’s the end of the window, so it could make the ball stop. I wanted the program to say, “When X coordinate of the ball equals the width of the window, or when Y equals the height of the window, stop!” (To be more precise, the X coordinate should actually be the width of the window MINUS the diameter of the ball, so that the ball doesn’t sink past the edge of the window before it bounces each time). 


At first I was stumped, because I couldn’t think of a way to keep track of the x and y coordinates of the ball. After all, in Java, to move the ball, you just declare variables “dx” and “dy”, which tell you how much to move the ball by; you don’t specify what the new coordinates are. After chatting with my friend Emmett, I realized that you could just declare variables “x” and “y” to equal the x and y coordinates of the ball, which you alter, by adding dx and dy to them, respectively, in every iteration of the loop. Indexing x and y lets you check the coordinates, even if it’s not necessary for the “move” command itself. Seems obvious now, so thanks Emmett :) Also in this stage, I centered the ball’s starting position.






public void run() {

//First you make the ball-- centered now
 int x = (getWidth()-DIAMETER)/2; 
 int y = (getHeight()-DIAMETER)/2;    
   
 GOval ball = new GOval (x, y, DIAMETER, DIAMETER); 
 ball.setFilled(true);
 add(ball); 
 
//Then you make it move
 int dx = 1; 
 int dy = 1; 

 while(true) {  
  ball.move(dx, dy);  
  pause(PAUSE_TIME);  
  x += dx; //changing x and y to check coordinates 
  y += dy; //against graphics window    
  
  if (x >= getWidth()-DIAMETER) {    
   break;
      }  
  if (y >= getHeight()+DIAMETER) { 
   break;
      } 
  if (x == 0) {
   break;
     }  
   if (y == 0) {
   break;
     }
}

3) Getting the ball to BOUNCE

Getting the ball to bounce is just a matter of switching the dx or dy variable to its own negative once we detect that the ball hit a wall. (I drew the ball’s path on a notepad before I attempted coding to think this through.) For example, if the ball is moving down and to the right and hits the bottom edge, it will start going upwards, but its horizontal direction will still be to the right. In that case, dy will switch to -dy, but dx won’t change.

What this looks like in terms of coding is I made “if” statements that say, “If we hit the top or bottom of the wall (aka if the y coordinate of the ball is zero or the height of the window), then change dy to -dy. If we hit the right or left side of the window (aka if the x coordinate is zero or the width of the window) then change dx to -dx. This can go on indefinitely.
while(true) {
 ball.move(dx, dy);
    pause(PAUSE_TIME);            
/*Reset the variables x and y at each iteration
 so can check them against window boundaries*/     
    x += dx;
    y += dy;
            
    if (x >= getWidth()-DIAMETER) {
        dx=-dx;
        dy=dy;
            }
    if (y >= getHeight()-DIAMETER) { 
        dx=dx;
        dy=-dy;
            }
    if (x == 0) { 
        dx=-dx;
        dy=dy;
            }
    if (y == 0) {
        dx=dx;
        dy=-dy;
            }
        }


Something to think about is: What will happen if the ball hits a corner? If it hits the top-left corner, will it bounce to straight right or straight down? Answer: it depends on the order you write your “if” statements in. My particular code checks for hitting the left before it checks for the top, so when the ball hits top-left it will bounce horizontally.

Sunday, February 28, 2010

Find2Largest Problem

Problem: Expand the problem from the preceding exercise "Find Largest" so that it finds both the largest and the second largest values in the list." (Robers ch 4, problem 13).

Basically, you start with two placeholder variables, "top" and "second." You set them initially to 0, but their values will change. As the user enters in new integers, you want a program that looks at each new input and says "If the input value is greater than the top, then replace the current top with the new input. If the input value is less than the current top AND greater than the current second, then reset second to equal the new input."

Renee's Code:
/*
* File: Find2ndLargest.java
* Name: Renee
* Section Leader:
* ------------------
This program uses three variables to find the two-largest values in an indefinite
list of integers entered by the user: "value", which is the variable given to the user
inputs, and "top" and "second," which are storage variables that start off at a value of 0. As the user
enters inputs, we compare the inputs to the current "top" and "second." Whenever the value
the user enters is greater or equal to the current "top," then we reassign the value
of "top" to the new input (but first we have to move the old "top" to "second" place).
This keeps going until the user enters the sentinel, when we end the inner loop and print the
reigning "top" and "second."
*/

import acm.program.*;

public class Find2ndLargest extends ConsoleProgram{
public void run () {
println ("This program finds the 2 largest of a list of integers.");
println("Enter integers, one per line, entering 0 to signify the end of the list.");

int top = 0;
int second = 0;

while (true){
int value = readInt("Enter integer: ");
if (value == SENTINEL) break;

if (value >= top) {
second = top;
top = value;
}else if (value >= second){
second = value;
}

}

println("The highest is " + top + ".");
println("The second highest is " + second + ".");
}
//private constants
private static final int SENTINEL = 0;


}

What it looks like:


Time it took: 35 min

What made it difficult: Not super-difficult this time. I did have a funny blooper. The first time I ran the code, I entered "7, 9, 6, 0" and got "The highest is 9. The second-highest is 6." What! The problem was, I had forgotten to state, "if you get a new 'top,' make the old 'top' equal to the 'second' and then make the new 'value' equal to the new 'top.'" Leaving out that line, then if your second-highest gets entered before your highest, you won't capture the second-highest.

This program also shows you the importance of "greater than" versus "greater than or equal to." At first I thought it was a wash whether I used ">=" or ">" as my operator, but running the program by hand with a couple test inputs clarified the difference.

Let's say the user enters "2, 2, 1, 0" as the inputs. What's the right answer? "The highest is 2. The second-highest is 1", right? However, if the operator is ">", which is wrong, here's how the program runs (going through it by hand):

Initial: top = 0, second = 0
1st loop: value = 2. The program thinks, "Is 2 greater than my current top, 0? Yes. Then top = 2, second = 0."
2nd loop: value = 2. The program thinks, "Is 2 greater than my current top, 2? NO! Well, is it greater than my current second, 0? Yes! Then reassign "second" to equal 2. top = 2, second = 2."
3rd: value = 1. The program thinks "1 is not greater than my current top or my current second, so keep the status as top = 2, second = 2."
4th: value = 0. Zero is the sentinel. Program stops, print "The highest is 2. The second-highest is 2."

This bug is solved by making the operator >=, because if the current top is 2 and the user enters 2, the program will replace the old 2 with the new 2, instead of moving it to the "second" variable.

Wednesday, February 24, 2010

FindLargest Problem

Problem: "Write a ConsoleProgram that reads in a list of integers, one per line, until the users a sentinel value of 0. When the sentinel is read, your program should display the largest value in the list" (Robers ch4, problem 12).

Renee's Code:

/*
* File: FindLargest.java
* Name: Renee
* Section Leader: Me! I did this one before breakfast, =D
* ------------------
We use two variables, "value" and "top", to solve this problem. "Top" is
declared at the beginning of the run method and arbitrarily gets assigned
-1. "Value" comes from the user's imput. Every time the user enters
Value comes the user's input. For every input, we check the input value against
the current "top," and if it's greater, we replace "top" with the "value."
Then once the user enters the sentinel, we print the current "top."
*/

import acm.program.*;

public class FindLargest extends ConsoleProgram{
public void run () {
println ("This program finds the largest of a list of integers.");
println("Enter integers, one per line, entering 0 to signify the end of the list.");

int top = -1;

while (true){
int value = readInt("Enter integer: ");
if (value == SENTINEL) break;

if (value >= top) top = value;

}

println("The highest is " + top + ".");

}
//private constants
private static final int SENTINEL = 0;


}
What it looks like:


How long it took: 25 min

Lingering Questions: I solved this by using two variables ("Top" and "Value") whose value changed, as the comment for the code describes. The question is: What are alternative approaches to solving this?

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?

Wednesday, February 10, 2010

Stuck Stuck Stuck like a Duck



/*
* 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 x = xstart;

double y = ystart;
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++) {


//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
y = y - 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 = 30;

//Width of each brick in pixels
privat
e static final int BRICK_HEIGHT = 12;

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

}

If I built pyramids, all my mummies would have disintegrated long ago.

Sunday, November 15, 2009

Work in Progress: Program To Draw A Pyramid

Problem: 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 in the window and should use named constants for the following parameters:


BRICK_WIDTH: The width of each brick
BRICK_HEIGHT: The height of each brick
BRICKS_IN_BASE: The nuber of bricks in the base

(Roberts Ch 4, exercise 11).


What's making this difficult:

1) Centering the pyramid. I can use getWidth/2 and getHeight/2 methods to find the center of the screen, and add or subtract to place the brick at a location in reference to the center. However, the bricks are sometimes above the center, sometimes below, sometimes to the right of the center, sometimes to the left. Either I'm missing something (quite likely), or it requires a clunky solution (ie, if four sepeate nested loops for each quadrant of the pyramid).

2) Variables inside the nested "for" statement: The outer "i" loop draws all of the rows, and the inner loop "j" draws all of the bricks inside the rows. The first row has 1 brick, the second row has two bricks, and so on, so I make the inner loop condition sound like this: "From j equals 1 to j equals i, draw a brick", making "i" the endpoint since "i" is the nth row that we're on. However, Eclipse seems to get mad when I reference "i" inside the "j" loop; I don't know why, but it has an angry red line under my i's within the inner loop.

(Click to enlarge)

Stanford Editor - Pyramid.java - Eclipse SDK - _Applications_eclipse_Eclipse.app_Contents_MacOS_cs106a_workspace
Uploaded with plasq's Skitch!


I ignored these problems for the time being and tried to see whether I could *just draw* the first brick of the first row. Below is the code for that part; I think it's in the right place. How can I modify it to get to the rest of the pyramid?


/*
* File: Pyramid.java
* Name:
* Section Leader:
* ------------------
*/

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

public class Pyramid extends GraphicsProgram {

public void run() {

//Starting from the bottom, build rows
for (int i = BRICKS_IN_BASE; i > 1; i --); {

//For each row; starting from the left, lay bricks
for (int j = 1; j <= 14; j++); {
double x = getWidth()/2 - BRICK_WIDTH * 14/2;
double y = getHeight()/2 + BRICK_HEIGHT * 14/2;
GRect brick = new GRect(x, y, BRICK_WIDTH, BRICK_HEIGHT);
add(brick);
}
}
}
/** Width of each brick in pixels */
private static final int BRICK_WIDTH = 30;

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

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

}



What it looks like? One sad brick :(