Tuesday, January 4, 2011

2 Programs to Draw a Target Graphic

Problem: "Rewrite the Target program given in Ch2 so that it uses the createFilledCircle method that appears in Figure 5.3. In addition, change the program so that the target is always centered in the window and so that the number and dimensions of the circles are controlled y the following named constants:

private static final int N_CIRCLES = 5;
private static final double OUTER_RADIUS = 75;
private static final double INNER_RADIUS = 10;

(Roberts ch 5, problem 5)

What it looks like:


What the code looks like: New Version:

/*

/*
 * File: TargetWithMethod.java
 * Name: 
 * Section Leader: 
 * -----------------
  * This is the new and improved version of the Target program. As with the old version, we draw 
  * the graphic by laying a bunch of concentric circles on top of each other. However, unlike the 
  *  old version, we draw the program with a "while" loop and a method to create the circles. The
  *  static contants give us number of circles, the outer radius, and the inner radius. Once those are established, 
  *  we derive the x and y coordinates to center our target graphic and the width of each ring. Then we go into a 
  *  "while" loop to keep adding new concentric circles on top of each other until the innermost circle is too small 
  *  (the radius is smaller than the target's rings). At the end of each loop, we change the "radius" 
  *  varible to make the next, smaller circle and we switch the boolean so that the colors can switch from red
  *  to white and back.
 */


package ch6_practice;

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



public class TargetWithMethod extends GraphicsProgram {
    private static final int N_CIRCLES = 5;
    private static final double OUTER_RADIUS = 75;
    private static final double INNER_RADIUS = 10;
 
 
    public void run() {
  
        int center_x = getWidth()/2;
        int center_y = getHeight()/2;
        double band_width = OUTER_RADIUS/N_CIRCLES;
  
        double radius = OUTER_RADIUS;
        boolean is_colored_band = true;
  
        while (radius >= band_width) {
            if(is_colored_band) {
                add(createFilledCircle(center_x, center_y, radius, Color.RED));
            }
            else {
                add(createFilledCircle(center_x, center_y, radius, Color.WHITE));
            }   
            is_colored_band = !is_colored_band;
            radius -= band_width;
       }
 
   }
 
    private GOval createFilledCircle (int x, int y, double r, Color color) {
  
        GOval circle = new GOval (x-r, y-r, 2*r, 2*r); //The method input becomes the center
        circle.setColor(color);
        circle.setFilled(true);
        return circle;
  
    }
}





Old Version:

/*
/*
 * File: Target.java
 * Name: 
 * Section Leader: 
 * -----------------
 * This is the old, static version of the target program. It makes three red concentric circles, named
 * "outer," "white," and "center." It uses the GOval method and the arguments for position and size are
 * explicitly hard-coded in.
 */

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

public class Target extends GraphicsProgram { 
    public void run() {
    GOval outer = new GOval(75, 50, 100, 100);
    outer.setColor(Color.RED);
    outer.setFilled(true);
    outer.setFillColor(Color.RED);
    add (outer);
 
    GOval white = new GOval(95, 70, 60, 60);
    white.setColor(Color.white);
    white.setFilled(true);
    white.setFillColor(Color.white);
    add (white);
 
    GOval center = new GOval(115, 90, 20, 20);
    center.setColor(Color.red);
    center.setFilled(true);
    center.setFillColor(Color.red);
    add (center);
    }
}



How long it took: 40 min

What makes the old version not-so-good: We had to hard-code in the coordinates for each of the rings, which is a pain to figure out. If we miscalculate, or if later on we want each of the rings to be a bit bigger/smaller, we have to redo a bunch of annoying arithmetic over again.

Later on I redid this code making the x and y coordinates variables that used the getHeight() and getWidth() methods, so the position of the board depended on the graphics window we were in. This was a bit better. However, the version that uses the createFilledCircle method is even better because besides always being sure the target is centered, we can be flexible with the number of rings, the overall size of the target, and the width of each ring.

What made it difficult: Nothing too difficult here; I did get stumped at the part where you switch the color from red to white. I knew that I wanted to make it the last step in my loop to switch the boolean, but I didn't know that you can switch booleans with the "!" operator (like this: "is_colored_band = !is_colored_band;" ), thanks Jane/Jason for the tip. I was going to go about it with 1 and -1, but this is much better.

Monday, January 3, 2011

Program to Print the First 10 values 2 to the kth Power

Problem: Write a method raiseIntToPower that takes two integers, "n" and "k" and returns n to the kth power. Use your method to display a table of values 2 to the kth power for all values of k from 0 to 10. (Robers ch 5, problem 3).

What it looks like:



How long it took: 30 min or so

What made it difficult: There are two loops in this problem. One says "From i being 0 to 10, print 2 to the i." The second loop is inside the private method, and it says "From i = 0 to the specified kth power, multiply the base by itself." Both loops use the same variable "i," and I can see a program like this getting confusing. However, it's unavoidable that you'll use the same variable name within a program; that I assume is because methods are built to be re-usable, so you'll never know which program you'll plunk them into.

I felt pretty comfortable with this re-use of "i" because both the book and Mehran's lecture went through tracing a program similar to this throughout multiple method calls and parameter passes. Going through strack frames in excruciating detail like this made me really aware of the "life cycle" of a program. Definitely a good foundation when learning about using private methods.



/*


/*
* File: RaisePowerWithMethod.java
* Name: Chu
* Section Leader: 
* Description: This program asks us to write a program that writes out 2 to the nth power for
* n = 1 to n = 10. We accomplish this using the private method 'raiseIntToPower', which can take in
* any base and any raised power.
*/


package ch6_practice;
import acm.program.*;

public class RaisePowerWithMethod extends ConsoleProgram {
    public void run() {
        for(int i = 0; i < 10; i++) {
            println (raiseIntToPower(2, i));
        }  
  
    }
    
    private int raiseIntToPower(int n, int k) {
     int result = 1;
     for (int i = 0; i < k; i++) {
      result *=n;      
     }
     return result;
    }
}


Saturday, January 1, 2011

Program (and method!) to evaluate Quadratic Equation.

Problem: "In high-school algebra you learned that the standard quadratic equation (ax^2 + bx + c = 0) has two solutions given by the formula: x = (-b +/- sqrt(b^2 -4ac)) / 2a.

The first solution is obtained by using + in place of +/-. The second is obtained by using - in place of +/-.

Write a Java program that accepts values for "a", "b" and "c", and then calculates the two solutions. If the quantity under the square root sign is negative, the equation has no real solutions, and your program should display a message to that effect. You may assume that "a" is nonzero." (Roberts ch 5, problem 1).

What it looks like:



This chapter is all about methods: Understanding how methods work within the context of a bigger program, writing your own, and re-writing old homework problems to use methods. I think I'll cement a lot of what I've learned about what makes code efficient/flexible.

I solved the problem by calling a method that I write. The "run" main method is there to take in the user inputs and print out the two answers. The method "quadratic" actually does the calculation.

How long it took: 1.5 hrs

What made it difficult: As a straight-up program, this wouldn't be hard; it's just a lot of arithmetic and "println" methods.

However, making "quadratic" a method made things a bit more complicated. First, there are two solutions to any quadratic forumla, but a method only can return one result. Arnab suggested fixing this by taking in "sign" as an argument to the method, and so I wrote a program that calls the method twice, once by entering -1 and once by entering 1.

Second, if the chunk under the square root evaluates to negative, there are no real number solutions, so I have to print out a string "There are no real number solutions." However, a method has to have a type (string, integer, etc), and my method type is a double, so I couldn't return a string. Arnab suggested using null-- null is becoming quite my friend these days.

Lingering questions:

1) I don't like that the part which checks for the square root chunk being negative only inspects "plus_sign_answer", even though it works. Is there a more elegant way about this?
2) I don't like that the "int sign" argument MUST take in -1 or 1; if this method was used in a program that put in, say, -100, it would return an inaccurate answer. Is there a way to stop this?



/*

/*
* File: QuadradicEquation.java
* Name: Chu
* Section Leader: Prof. Arnab
* Description: This is a program to evaluate the quadradic equation, giving inputs a, b and c.
* The 'run' method takes in the user inputs, then it calls the private method 'quadradic'.
*/


package ch6_practice;
import acm.program.*;

public class QuadradicEquation extends ConsoleProgram {
    
    public void run (){
        println("Enter the coefficients for the quadradic equation:");
        int a = readInt("a:");
        int b = readInt("b:");
        int c = readInt("c:");
        
        Double plus_sign_answer = quadradic(a, b, c, 1);
        Double minus_sign_answer = quadradic(a, b, c, -1);
        if (plus_sign_answer != null) { //This isn't totally elegant because it only checks the 
         //first answer, even though both the first and second solutions check for null...
        
            println("The first solution is " + plus_sign_answer);
            println("The second solution is " + minus_sign_answer);
        }
        else {
            println("There are no real number solutions.");
        }
    }
        
    
    private Double quadradic(int a, int b, int c, int sign) { //'sign' takes -1 or 1
       
     
        double sqrt_part = Math.sqrt(b*b - 4*a*c);
        int neg_b = b*-1;
        int two_a = 2*a;        
        double solution = (neg_b + (sign * sqrt_part))/two_a;
        
        if (sqrt_part < 0) {
            return null;
            
        }
        
        else {
            return solution;

        }
        
    }

}

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: