Sunday, January 23, 2011

Predicate Method for Yes/No: The David Version

After I posted my predicate method for categorizing yes/no questions as true or false, David challenged me to rewrite the solution with a single call to readLine(prompt) and a single test for reply.equals("yes").

Here's my shot at it (tested and it works, oorah):

/*

    private boolean askYesOrNoQ(String prompt){   
        while (true) {
            String reply = readLine(prompt);
         
            if (reply.equals("yes")) {
                return true;
            }
            if (reply.equals("no")) {
                return false;
            }
            else
            println("Please enter a yes or no answer.");
        }
        
    }


The old approach said, "As long as the user enters a non-yes/no answer, keep prompting him to enter yes or no; once he does, return true or false, respectively." This version says, "Keep looping. If he enters yes, break from the loop and return true. If he enters no, break from the loop and return false. Else, keep re-prompting and looping."

I don't know if this was the strategy David was thinking of, but I'm glad I figured out how to solve a problem two ways. Comparing this method with the old version, I'm trying to figure out which one is better and why.

For reference, here is the old version:

/*

private boolean askYesOrNoQ(String prompt){ 
        String reply = readLine(prompt);
      
        while ((!reply.equals("yes"))&&(!reply.equals("no"))) {
            println("Please enter a yes or no answer.");
            reply = readLine(prompt);
        }
        return (reply.equals("yes"));
    }
}



Merits of the new version:

1) Clearer to read; you don't really need to know the syntax of Java or how booleans work to know what's going on.

2) Doesn't repeat the line "reply = readLine(prompt)". In general it's a good practice to avoid repeating code so you don't introduce bugs if you decide to change the name of the variable "reply", etc.

Merits of the old version:

1) Fewer lines of code.

2) I like the clean and elegant "return" statement. Instead of breaking down the true or false possibilities into two "if" statements, we say return(boolean); it lets the program figure out true vs false for itself. I guess you could write, "If reply equals yes or no, return(boolean)", though that would violate the challenge of only inspecting reply.equals("yes") only once.

What do you guys think? Also are there other ways of solving this problem?

Predicate Method to Categorize a Yes or No Question (with Monkey Brains program)

Problem: "Write a predicate method "askYesNoQuestion(prompt)" that prints a string "prompt" as a question for the the user and then waits for a response. If the user enters a string "yes" the askYesNoQuestion method should return true. If the user enters a string "no" the askYesNoQuestion method should return false. If the user enters anything else, the method should remind the user that it is seeking a yes-or-no answer and then repeat the question." (Roberts ch 5, problem 7).

This problem was a good illustration of how boolean methods work as part of a larger program. Let's say you want a program to say, "If True, do X, if False, do y," but the mechanics of evaluating a situation to "True" or "False" take multiple steps. If that's the case, then the "if" part would best be handled by a method call.

What it looks like:


/*

* File: YesNoPredicate.java
* Name: Renee
* Section Leader: 
* -----------------
* 
*/

import acm.program.*;

public class YesNoPredicate extends ConsoleProgram {
    public void run() {
        if (askYesOrNoQ ("Do you have monkey brains?")) {
            println ("Have a bananna");
        }
        else println ("Get outta here");
        }
    
    /*This boolean pushes the user to enter a yes or no answer to an arbitrary string (hopefully
    a question) called "prompt." If the user enters anything but yes or no, the method
    will keep looping until the user enters yes or no. If the user enters "yes", the boolean
will return "true." If the user enters "no", the boolean will return "false."*/

    private boolean askYesOrNoQ(String prompt){ 
        String reply = readLine(prompt);
      
        while ((!reply.equals("yes"))&&(!reply.equals("no"))) {
            println("Please enter a yes or no answer.");
            reply = readLine(prompt);
        }
        return (reply.equals("yes"));
    }
}




What made it tough: At first I thought this problem was super-simple, but it stumped me for 30 min before everything clicked. I knew that I wanted the boolean to say, "If the user enters 'yes,' return 'true.' If he enters anything else, return 'false.' Moreover, if the false answer is not 'no', keep re-prompting for a yes-or-no answer." But I wasn't sure how to build that re-prompt into the predicate method and at first built the re-prompt into the run() method, which isn't the proper place because the predicate part is supposed to take care of that.

I was getting close when it looked like this:

/*
    private boolean askYesOrNoQ(String prompt){ 
        String reply = readLine(prompt);
        return (reply.equals("yes"));
        if (!reply.equals("no")) {
            println("Please enter a yes or no answer.");        
        }
but I kept getting an error "Unreachable code." I had the "return true if yes" part come before the "push the user for a yes-or-no answer" part, though it appears you must have the "return" method be the last part of your private method? That makes sense, because if the user entered "gibberish" and we returned "false", the run() method would act upon the "false" without ever getting a yes-or-no answer from the predicate method.

This was also another good illustration of different ways to pass an object to a method. It's interesting that the argument you pass to the method which inspects the user's input isn't the answer itself, but the prompt. You could easily have designed this program so that you print out the prompt as part of the run() method and pass the user input to the private boolean to evaluate it to true or false; I'm trying to think what the merits of each approach are...

Saturday, January 22, 2011

Program to Display the Number of Digits in an integer

Problem: Write a method countDigits(n) that returns the number of digits in the integer 'n', which you may assume is positive. Design a main program to test your method. For hints about how to write this program, you might want to look back at the DigitSum program in Fig 4.6.

What I did: This program interacts with the user, taking in the digit input and sending that input to the countDigits method. I also made the program let the user keep entering in digits to his or her hearts' content, using the value "0" as the sentinel.





/*
/*
* File: DigitCountWithMethod.java
* Name: Chu
* Section Leader: 
* Description: This exercise prints the number of digits in an integer that
* the user enters in. The main/run method uses the digitCount method to 
* accomplish this.
* 
* The countDigits method is pretty clever and reuses the technique from the DigitSum program
* in the textbook from section 4.6. In order to count the number of digits in an 
* integer, you keep dividing the integer by 10 and adding 1 to a variable "dcount" that gets initiated
* at 0. You keep doing this iteration until the integer is zero.
*/


package ch6_practice;
import acm.program.*;

public class DigitCountWithMethod extends ConsoleProgram {
 
    public void run() {
        println("This program counts the digits in an integer.");
        //Hm, get "illegal numeric format" if it's a long integer...Java limitation? Eew.
  
        while (true) {
            int n = readInt ("Enter any integer, entering '0' if you want to exit the program:");
            if (n == 0) {
                println("Goodbye");
                break; //Oh, once you break, you can't continue in the loop; otherwise it's "unreachable code"       
            }
            else {
            println("There are " + countDigits(n) + " integers in " + n + ".");
            }
        }
    }
 
    private int countDigits(int n){
        int dcount = 0;
        while (n > 0) {
            dcount += 1;
            n /= 10;
        }
        return dcount;
    }
 
 
 
}


What made it tough: Nothing much; a lot of the countDigits strategy came from another program, DigitSum. I do see 2 curious things however. First; if the user enters in more than 10 digits, we get an error message "Illegal numeric format." Why??

Also, I wanted to let my program loop so that the user could enter in multiple digits; the only way I could think of how to do this was with establishing a sentinel with the value "0." However, this is not elegant at all; for one thing, what if I want to know how many digits zero has? However, I can't make the sentinel a string, since my prompt will only accept integers. Ideas on a better way for the user to terminate the program?

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;

        }
        
    }

}