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