Tuesday, December 28, 2010

Even-cleaner Checkerboard code

After I finished the checkerboard code, it really pained me to reuse the code for the inner loop that checked whether a square is an "every other" square (ie if ((i+j) % 2 != 0) ). We have to use this both for when determining if a square should be filled, and if a checker belongs in the spot.

I got a couple of suggestions to avoid repeating code. Bill simply suggested storing the boolean in a local variable, which makes a lot of sense; I'm still getting the hang of how booleans work in structure, so it was good to know that I could store the logic that way.

Usman suggested initiating the "checker" variable outside the loop that used the boolean and set the value of "checker" to null at first. Then within the loop, I could change the value of "checker" to be a new object and set it to a proper position and color. At the end of the loop, if the value of "checker" has been changed form "null" to a new object, plop that sucker down. This lets me avoid the problem of plopping the square down after the checker (and covering the checker up.)

I rewrote the code according to Usman's suggestion, and it worked! Yippee! I hadn't known what null was, but it seems to be handy. It sounds like "null" is just a placeholder that is totally neutral, so Java won't object if we set a GOval variable object equal to null at first, and we can check whether the variable is or isn't "null" after the loop.

However, Usman mentioned that it's not good to use "null" a whole lot. I wonder why....

/*


/*
* File: CheckerboardWithoutRepeatedCode.java
* Name: Chu
* Section Leader: Usman. He rules
* Description: This program draws a checkerboard graphic and checkers on it in the original starting position.
* To draw the board, we use the GRect class, with the "x" and "y" coordinates set by the index of the loop
* as well as the square size (determined by private constants).  The checkers use the GOval class, and since they 
* are right on top of the squares, they can use the same "x" and "y" coordinates. To determine if the squares
* should be filled in, we use the boolean ((i+j) % 2 != 0), which resolves to true every other square by
* row and column. We reuse that test for determining whether a checker should be set down.
* 
* I used Usman's suggestion of initiating a checker outside the inner loop with the boolean and setting it 
* equal to null at first, and if the inner loop determines that there should be a checker, we'll change the
* "checker" variable from "null" to a new GOval object. We can check at the end of the loop whether "checker"
* is null or not, and if not, then plot it on the board in the right place.
* ------------------
*/
 
package Ch4Practice;

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

public class CheckerboardWithoutRepeatedCode extends GraphicsProgram {
 
    //private constants
    private static final int N_ROWS = 8;
    private static final int N_COLUMNS = 8; 

    public void run() {
        double sqSize = (double) getHeight() / N_ROWS; 
        double boardWidth = N_COLUMNS * sqSize; 

        for (int i = 0; i < N_ROWS; i++) { //for the outer rows
            for (int j = 0; j < N_COLUMNS; j++) { //for the inner rows
                double x = (j * sqSize) + (getWidth()/2 - boardWidth/2);
                double y = i* sqSize;
   
                //Starting off the checkerboard:
                GRect sq = new GRect(x, y, sqSize, sqSize); //Make up a new square with the proper coordinates
   
                //Initiate the variable checker at null.
                GOval checker = null;    
    
                if ((i+j) % 2 != 0) { //If it's every other square, both by row and column
                    sq.setFilled(true); //Make it filled
          
                    //Now for the checkers:
                    checker = new GOval (x, y, sqSize, sqSize); //Making the checker NOT null, if it appropriate
                    checker.setFilled(true);
     
                    if ((i < 3)) {//If it's every other AND the first three rows, make red checkers 
                        checker.setFillColor(Color.RED);
      
                    }
                    else if (N_ROWS-4 < i) { //If it's every other AND the last 3 rows, make white checkers
                        checker.setFillColor(Color.WHITE); 
      
                    } 
  
                }
    
                add(sq); //Plop that square down
                if (checker != null) {
                    add(checker); //Plop that checker down-- BAM!
                }
            }
 
        }
    }
 
}

Monday, December 27, 2010

Program to find Divisble by 6 or 7's

Problem: Write a program that displays the integers between 1 and 100 that are divisible by 6 or 7 but not both. (Roberts ch 4, exercise 4).

This was one of the first problems in the set, and a relatively easy one that makes a good refresher on how booleans work. The sentence "boolean 'isDivisible' which resolves to true if the number is divisible by 6 and not 7 OR divisible by 7 and not 6" translates in code to "boolean isDivisable = ((integer % 6 == 0) && (integer % 7 != 0)) || ((integer % 7 == 0) && (integer % 6 != 0));"

How long it took: 20 min

What made it tough: Nada, not by now :)

Lingering questions: Is there a better way to do this? For example, what if you first found through all the numbers divisible by 6, then all the numbers divisible by 7, then de-duped them. Would that be any more efficient or flexible?

Also, my friend from work John Britton says that automated tests are a good practice. For a problem like this, you can imagine that if the range of numbers were much bigger (say 1-500,000), it would be harder to confirm that the code is accurate. How would you go about building in tests?

/*
* File: DivisibleBy6or7.java
* Name: Chu
* Section Leader: 
* Description: This program finds the integers from 1 to 100 that are divisible by 6 or 7 (but not both) by running a boolean 'isDivisible' which resolves to true if the number is divisible by 6 and not 7 OR divisible by 7 and not 6. If the 'isDivisible' resolves to true, the we display the integer.
* ------------------
*/
 

package Ch4Practice;

import acm.program.*;
public class DivisibleBy6or7 extends ConsoleProgram {
     public void run() {
     println("These are the integers from 1 to 100 that are divisible by 6 or 7, but not both:");
        for (int i = 1; i < 101; i++) {
            int integer = i;
            boolean isDivisable = ((integer % 6 == 0) && (integer % 7 != 0)) || ((integer % 7 == 0) && (integer % 6 != 0));
            if(isDivisable) {
             println(integer);
            }
        }

    }
}

Saturday, December 25, 2010

Cleaner Implementation of CheckerboardWithCheckers

There was an old problem in the textbook that drew a black-and-white checkerboard. For this problem, we had to modify it to also add checkers.

I gave it a shot at first by simply breaking up the checkerboard into three sections. For the first three rows, make a square, add a red checker. For next three rows, just make the squares. For the last three rows, make a square, add a white checker (later change to black). Needless to say, this is a functional but un-elegant bit of code that re-creates all my loops three times, and if I ever needed to edit the conditions for laying down squares or checkers, I’d easily introduce bugs.

This new version is cleaned up a bit.

First, we put down the checkerboard. For each integration of the loop, we make a square in the proper spot. If it’s an “every other” square, both horizontally and vertically, make it filled. Then add the square to the board.

Next we do the checkers. Make a new GOval for every iteration of the loop; we won’t necessarily plop it down on the board, only if that spot is a proper place for a checker. (Programming experts, is this a bad practice?) If we’re on an iteration of the loop that’s for an “every other” square (we can reuse the code for “sq.setFilled” here) AND if it’s in one of the first three rows, make it red and add it to the board. (Repeat for the last three rows, except make the checker black instead of red.)

Here’s what the code looks like:

/*
* File: CheckerboardWithCheckers.java
* Name: Chu
* Section Leader: Geoff clearly, because without him there would be no acm.jar 
* in this Eclipse workspace, and then where would we be?
* ------------------
*/

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

public class CheckerboardWithCheckers extends GraphicsProgram {

    //private constants
    private static final int N_ROWS = 8;
    private static final int N_COLUMNS = 8; 

    public void run() {
        double sqSize = (double) getHeight() / N_ROWS; 
        double boardWidth = N_COLUMNS * sqSize; 

        for (int i = 0; i < N_ROWS; i++) { //for the outer rows
            for (int j = 0; j < N_COLUMNS; j++) { //For columns within each row
    
                //First make the checkerboard:
                double x = (j * sqSize) + (getWidth()/2 - boardWidth/2);
                double y = i* sqSize;
                GRect sq = new GRect(x, y, sqSize, sqSize); //Make up a new square with the proper coordinates 
                if ((i+j) % 2 != 0) { //If it's every other square, both by row and column
                    sq.setColor(Color.BLACK);
                    sq.setFilled(true); //Make it filled
                    sq.setFillColor(Color.GRAY);   
                }
                add(sq); 
    
                //Now for the checkers:
                GOval checker = new GOval (x, y, sqSize, sqSize);
                checker.setFilled(true);
                if ((i+j) % 2 != 0) {//If it's every other square... (This is bad kids! Don't repeat code.)
                    if ((i < 3)) {//AND the first three rows, make red checkers 
                        checker.setFillColor(Color.RED);
                        add(checker);
                    }
                    else if ((N_ROWS-4 < i) && (i < N_ROWS)) { //If it's every other AND the last 3 rows, make white checkers
                        checker.setFillColor(Color.BLACK); 
                        add(checker);
                    } 
  
                }
    
             }
 
         }
    }
  
} 
 
Here’s what you get when you run it:
The above code is perfectly functional, except we reuse the code that checks for “every other” square, specifically “if ((i+j) % 2 != 0).” I’d wanted to use the same “if” statement for both “sq.setFilled” and “add(checker)”. However, I don’t think I can; the “add(sq)” method applies whether it’s a filled square or not, so I have to put it outside the “if every-other” loop. The add(checker) method does happen only on the “every-other” squares, so it’s inside the loop. This means adding a square comes AFTER adding a checker, so the squares go on top of the checker and we can’t see the checkers. Example code for CheckerboardWithoutRepeatingCode:
import acm.graphics.*;
import acm.program.*;
import java.awt.*;

public class CheckerboardWithoutRepeatedCode extends GraphicsProgram {

    public void run() {
        double sqSize = (double) getHeight() / N_ROWS; 
        double boardWidth = N_COLUMNS * sqSize; 

        for (int i = 0; i < N_ROWS; i++) { //for the outer rows
            for (int j = 0; j < N_COLUMNS; j++) { //for the inner rows
                double x = (j * sqSize) + (getWidth()/2 - boardWidth/2);
                double y = i* sqSize;
                GRect sq = new GRect(x, y, sqSize, sqSize); //Make up a new square with the proper coordinates
   
                if ((i+j) % 2 != 0) { //If it's every other square, both by row and column
                    sq.setFilled(true); //Make it filled
          
                    //Now for the checkers:
                    GOval checker = new GOval (x, y, sqSize, sqSize);
                    checker.setFilled(true);
     
                    if ((i < 3)) {//If it's every other AND the first three rows, make red checkers 
                        checker.setFillColor(Color.RED);
                        add(checker);
                        }
                    else if ((N_ROWS-4 < i) && (i < N_ROWS)) { //If it's every other AND the last 3 rows, make white checkers
                        checker.setFillColor(Color.WHITE); 
                        add(checker);
                    } 
  
                    }
    
                add(sq); //Plop that square down-- DAMN! So perfect except the squares go on top of the checkers...
                         //We have to make the add(sq) come before the add(checker)  
                }
 
        }
    }
 
    //private constants
    private static final int N_ROWS = 8;
    private static final int N_COLUMNS = 8; 
}
What it looks like:

Does anyone have ideas on how to condense this code and possibly not repeat the check for “if every-other” square?

Checkerboard with Checkers

Problem: Enhance the Checkerboard problem so that it centers the checkerboard horizontally and draws the set of red and black checkers corresponding to the initial state of the game. (Roberts ch 4, Exercise 14)

2 instances of repeated code here. We want red checkers apply to the first three rows, no checkers to apply to the middle rows, and white checkers apply to the last three rows. We can take care of this by changing the outer while loop; instead of i going from 0 to N_ROWS, we break it up into a) 0 to 3, b) 3 to N_ROWS-3, and c) N_ROWS-3 to N_ROWS. I need to think about how to break up my iterations this way without repeating code too much.

In the rows where checkers do apply, we want to add checkers only to the squares that are filled in. We have a boolean that says "If the sum of the column number and the row number is odd, then it should be filled in." This is how we make sure the "Every Other" applies both horizontally and vertically. We want to same boolean to apply to whether we put checkers down or not; however, if we make the line "add(sq)" come after the "add(redChecker)", we won't see the checker. But we can't make it come after while being in the same loop because we want to add the square whether or not it's a filled-in square.

I'm going to sleep now...this will be easier to clean up in the morning.

import acm.graphics.*;

/*
* File: CheckerboardWithCheckers.java
* Name: Chu
* Section Leader: Geoff clearly, because without him there would be no acm.jar in this Eclipse workspace, and then where would we be?
* ------------------
*
*/
import acm.graphics.*;
import acm.program.*;
import java.awt.*;

public class CheckerboardWithCheckers extends GraphicsProgram {

 public void run() {
  double sqSize = (double) getHeight() / N_ROWS;
  double boardWidth = N_COLUMNS * sqSize;
  for (int i = 0; i < 3; i++) {
   for (int j = 0; j < N_COLUMNS; j++) {
    double x = (j * sqSize) + (getWidth()/2 - boardWidth/2);
    double y = i* sqSize;
    GRect sq = new GRect(x, y, sqSize, sqSize);
    if ((i+j) % 2 != 0) {
     sq.setFilled(true);

     
    }
    add(sq);
    
    if ((i+j) % 2 != 0) {//This is bad, kids! Don't repeat code
     GOval redChecker = new GOval (x, y, sqSize, sqSize);
     redChecker.setFilled(true);
     redChecker.setFillColor(Color.RED); 
     add(redChecker);
    }
   } 
  }
  
  for (int i = 3; i < N_ROWS-3; i++) { //This is bad, kids! Don't repeat code
   for (int j = 0; j < N_COLUMNS; j++) {
    double x = (j * sqSize) + (getWidth()/2 - boardWidth/2);
    double y = i* sqSize;
    GRect sq = new GRect(x, y, sqSize, sqSize);
    if ((i+j) % 2 != 0) {
     sq.setFilled(true);
     
    }
    add(sq);
   
   } 
  }
  
  for (int i = N_ROWS-3; i < N_ROWS; i++) {
   for (int j = 0; j < N_COLUMNS; j++) {
    double x = (j * sqSize) + (getWidth()/2 - boardWidth/2);
    double y = i* sqSize;
    GRect sq = new GRect(x, y, sqSize, sqSize);
    if ((i+j) % 2 != 0) {
     sq.setFilled(true);
     
    }
    add(sq);
    
    if ((i+j) % 2 != 0) {//This is bad, kids! Don't repeat code
     GOval whiteChecker = new GOval (x, y, sqSize, sqSize);
     whiteChecker.setFilled(true);
     whiteChecker.setFillColor(Color.WHITE); 
     add(whiteChecker);
    }
   } 
  }
 }
 


//private constants
 private static final int N_ROWS = 8;
 private static final int N_COLUMNS = 8;

What it looks like:

Sunday, December 19, 2010

Test: Does this syntax highlighter work?

#Old, not-so-useful version:

print "Hello. Please enter a Celsius value: "
celsius = gets
fahrenheit = (celsius.to_i * 9.0 / 5) + 32
print "The farenheit equivalent is "
print fahrenheit
puts "."






#New and improved version that accomplishes temperature conversion as a method

class Numeric
  def c2f  # this is a method 
    self* 9.0 / 5 + 32
  end  
end  

#Example use cases of this method
current_farenheit = 12.c2f 
puts current_farenheit

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.