Thursday, December 29, 2011

Program to Make the Plural of a Word

Problem:

Write a method regularPluralForm(word) that returns the plural of word formed by following these standard English rules:

a) If the word ends in s, x, z, ch, or sh, add es to the word. 
b) If the word ends in y and the y is preceded by a consonant, change the y to ies. 
c) In all other cases, add just an s.
Write a test program and design a set of test cases to verify that your program works.

(Roberts ch 10, problem 7).

What it looks like:

/*File: MakePlural.java
 * ---------------------
 * This program lets the user enter in any word and it will print out the plural form according to the basic,
 * not totally comprehensive rules outlined in the problem from ch. 10. It makes use of the private methods
 * makePlural (which take in a string and returns another string, the plural form of the word).
 */
import acm.program.ConsoleProgram;
public class MakePlural extends ConsoleProgram {
    public void run() {
       while (true){
           String word = readLine("Enter word and we'll make it plural. Enter '0' to stop: ");
           if (word.equals("0")){
               break;
           }
       print(makePlural(word) + " ");
       }
    }
    
    //Takes the submitted string, inspects the last letter (or last 2 letters in case of "ch" and "sh"),
    //and returns the appropriate plural form.
    private String makePlural (String singularWord){
        String pluralWord = "";
        String strippedWord = singularWord.substring(0, singularWord.length()-1);
        char lastLetter = singularWord.charAt(singularWord.length()-1);
        switch (lastLetter){
            case 's':
            case 'x':
            case 'z':
                pluralWord = singularWord + "es";
                break;
            case 'h': // checking for if the word ends with "ch" or "sh"
                if ((singularWord.charAt(singularWord.length()-2)== 'c') || (singularWord.charAt(singularWord.length()-2)== 's')) {
                    pluralWord = singularWord + "es";
                    break;
                } 
            case 'y':
                if (isEnglishConsonant(singularWord.charAt(singularWord.length()-2))) {
                    pluralWord = strippedWord + "ies";
                    break;
                }
            default: pluralWord = singularWord + "s";
            break;
        }
        return pluralWord;
    }
    private boolean isEnglishConsonant(char ch) {
        switch (Character.toLowerCase(ch)) {
            case 'a': case 'e': case 'i': case 'o': case 'u': 
                return false;
            default: 
                return true;
        }
    }
}





What made it tricky:


The program is structured to work well as a "switch" statement, and I had wanted to create a neat table that took a substring "lastLetter" (last 2 letters in the case of "ch" and "sh") and neatly return the proper plural form.  However you can't switch on a string as I learned-- damn! So had to use the character only and switch on that, which made checking for "ch" and "sh" slightly less convenient.


Come to think of it, why *can't* you switch on a string? You'd think that it's a similar situation to comparing strings via "if (s1 == s2)", namely that it would often give you the wrong answer since they're comparing actual objects, not values. However I got an error when I attempted...anyone know why?


Another bug I ran into came from attempting to inspect the last letter and second-to-last-letter by doing charAt(-1) or charAt(-2) and making a substring of all but the last letter of the original word by doing "singularWord.substring(0, -1)". Those were throwing out-of-bounds errors. Oops-- sure would have been convenient.


The main bug I got stuck on before it worked is that it kept giving me the default case. So "sky" gave me "skys", "box" gave me "boxs" etc. I didn't know why and whether the non-default case was even getting run so I added debugging lines to print out the plural form as soon as it gets run.






It appeared that the special cases were getting run, but the default was getting run every time. Why?


I suppose I needed to add "break" statements to my special cases in the "switch" statement. I looked up confirmation for this in the text and this is what it said:


"Java is defined so that if the break statement is missing, the program starts executing statements from the next clause after it finishes the selected one. While this design can be useful in some cases, it tends to cause more problems than it solves. To reinforce the importance of remembering to include the break statement, every case clause in this text ends with an explicit break statement (or sometimes with a return statement, as discussed in Chapter 5)."


That kind of makes sense... depending on what the syntax means when it checks for "default," it's posible that "default" means every single case *in addition to* the special cases that do apply. So yes, once I did add a "break" statement to each case, the problem worked correctly.


It's weird though because one example in the book does a simple switch statement with a default, but does not have a break statement after the special cases:

private boolean isEnglishVowel(char ch) {
     switch (Character.toLowerCase(ch)) {
         case 'a': case 'e': case 'i': case 'o': case 'u':
            return true;
         default: 
            return false;
    }
}   
I can confirm that this private method works correctly since I used it in my own program. So I'm not quite sure when a break statement is required. I do realize that the author may not have meant to include a confusing example in the final version of the book, so I'll check this PDF against my hard copy when I'm back home. Any ideas on this switch statement conundrum however?

Wednesday, December 28, 2011

Program to Determine the Ordinal Value of a Number

Problem:
Like most other languages, English include two types of numbers: cardinal numbers (such as one, two, three, and four) that are used in counting, and ordinal numbers (such as first, second, third, and fourth) that are used to indicate a position in a sequence. In numeric form, ordinals are usually indicated by writing the digits in the number, followed by the last two letters of the English word that names the corresponding ordinal. Thus, the ordinal numbers first, second, third, and fourth often appear in print as 1st, 2nd, 3rd, and 4th.
The general rule for determining the suffix of an ordinal can be defined as follows:
Numbers ending in the digit 1, 2, and 3, take the suffixes "st", "nd", and "rd", respectively, unless the number ends with the two- digit combination 11, 12, or 13. Those numbers, and any numbers not ending with a 1, 2, or 3, take the suffix "th".
Your task in this problem is to write a function ordinalForm(n) that takes an integer n and returns a string indicating the corresponding ordinal number.  (Roberts ch 10, problem 9).


What it looks like:

/* File: ordinalForm.java
 * -----------------
 *This console program lets the user enter in any integer and will print out the ordinal form of that number. For example
 *the ordinal form of 1 is "1st," 2 is "2nd" etc. The user enters the sentinel value "-1" to stop running the program.
 *
 *The program and the method of the same name takes an integer as the entered value and returns a string. We use the ACM library's (?)
 *built-in Integer class and its toString method. Because the suffix of an ordinal value depends on the last digit
 *of a number our program has to strip out and inspect the last digit of the supplied integer so we use the method 
 *"getLastDigit" to inspect the last digit. In the case of numbers ending with "11", "12" and "13" we need to see the last
 **two* digits so we also use a similiarly-constructed getSecondToLastDigit.
 */
import acm.program.ConsoleProgram;
public class ordinalForm extends ConsoleProgram {
    public void run() {
       while (true){
       int cardinal = readInt("Enter number and we'll give you the ordinal form: ");
       if (cardinal == -1){
           break;
       }
       print(makeOrdinal(cardinal));
       }
    }
    private String makeOrdinal(int n) {
        String ordinal = "";
        int lastDigit = getLastDigit(n);
        int secondToLastDigit = getSecondToLastDigit(n);
        if ((lastDigit == 1) && secondToLastDigit !=(1)){
            ordinal = Integer.toString(n) + "st"; //Not sure why it's "Integer.toString(n)" instead of "n.toString" or "toString(n)"
        }
        else if (lastDigit ==2 && secondToLastDigit !=(1)) {
            ordinal = Integer.toString(n) + "nd"; 
        }
        else if (lastDigit == 3 && secondToLastDigit !=(1)) {
            ordinal = Integer.toString(n) + "rd";
        }
        else ordinal = Integer.toString(n) + "th";
        return ordinal;
    }
    private int getLastDigit(int n) {
        int remainder = n % 10;
        return remainder;
    }
    
    private int getSecondToLastDigit(int n) {
        int remainder = 0;
        for (int i = 0; i < 2; i++){
            remainder = n % 10;
            n /= 10;
        }
        return remainder;
    }
}
}








What made it tricky:


My first version of this was running just fine....it just kept returning the wrong answer. Have a look at this sample run when the bug existed and guess what the problem was:



Here's a clue: this is what my private methods getSecondToLastDigit(n) and getLastDigit(n) looked like:

    private int getLastDigit(int n) {
        int remainder = 0;
        while (n > 0) {
            remainder = n % 10;
            n /= 10;
        }
        return remainder;
    }

    private int getSecondToLastDigit(int n) {
        int remainder = 0;
        while (n > 10) {
            remainder = n % 10;
            n /= 10;
        }
        return remainder;
    }
So while getLastDigit(n) should have just divided by n *once* and returned the remainder, instead it kept dividing by n until there was nothing left. So it was really stripping off and returning the *first* digit, not the last! getSecondToLastDigit(n) was behaving the same way, except it stopped one iteration sooner so it returned the second digit, not the second-to-last. Ugh, so embarrassing, blame it on the Christmas food abundance.

I didn't see the pattern or understand what was wrong for a while so I made this quick debugging program that printed out the results of just getLastDigit(n):

import acm.program.ConsoleProgram;
public class testLastDigit extends ConsoleProgram {
    public void run() {
       int n = readInt("Enter an int and we'll give you the last digit");
       print (getLastDigit(n));
    }
    private int getLastDigit(int n) {
        int remainder = 0;
        while (n > 0) {
            remainder = n % 10;
            n /= 10;
        }
        return remainder;

    }
}
I ran it a bunch of times and saw that indeed, testLastDigit  was giving me the wrong answer. Once I saw that it was wrong and predictably wrong, the fix was easy.


Saturday, December 17, 2011

Program to Search for a Substring inside a String

Problem: If the designers of the String class had not defined the version of indexOf that takes a string argument, you could implement it using the other methods available in the library. Without calling indexOf directly, implement a method myIndexOf that behaves in exactly the same way.


What it looks like:




/* File: myIndexOfTester.java
 * ---------------
 * This program has a run method that lets the user enter in a (supposed to be) big string and a
 * little string. Then it uses the private method myIndexOf to see whether the little string exists
 * inside the big string and if so, return the index within the big string that the little string
 * exists at.
 * 
 * There is already an indexOf method in Java's standard String class, but the Stanford folks 
 * thought it would be good for us to try implementing it ourselves with other methods in the
 * String class.
 */
import acm.program.*;
public class myIndexOfTester extends ConsoleProgram {
    public void run() {
       String enteredString = readLine("Enter a string: ");
       String searchedForString = readLine("Enter the string you're searching for inside it: ");
       print(myIndexOf(searchedForString, enteredString));
    }
    private int myIndexOf(String littleString, String bigString) {
//"Real" program would check that littleString is longer than bigString & raise and exception of it weren't

//For every letter in bigString MINUS the length of littleString (to guard against out-of-bounds
//errors), check if littleString equals the segment of bigString that starts at that index.
        for (int i = 0; i < bigString.length()-1-littleString.length()-1; i++) {      
            if (littleString.equals(bigString.substring(i, i+littleString.length() ))) {
                return i;
            }           
        }
        return -1; //Signifies that littleString doesn't exist inside bigString         
    }
}




The basic gist of this problem, or at least my approach to it, is you want to take your little string and compare it to substrings inside the big string. In particular, you want to iterate through each letter of the big string and carve out a substring starting at that index and of an equal length to the little string. If they are equivalent, then return the index. If you never get an equivalency, then return -1 (as is the existing convention).


What made it tricky: Two things! 1) Off-by-one errors, and 2) Out-of-bounds errors.


** Off-by-one Errors **


Let's say your big string is "HELLO WORLD". This string has 11 characters, including the space, so the method bigString.length() would return 11. If you iterated from 0 to 11, however, your last iteration would be looking at nothing since there's no character at space "11"! Therefore, you have to make the outer bound of your loop is the length of the big string minus one.




** Out-of-bounds Errors **


Let's say your big string is "HELLO", and the little string you're inspecting "HELLO" for is "HI." You go thru every letter in "HELLO," seeing if the 2-letter substring at that letter is equivalent to "HI".


However, what happens on the last couple of iterations of your loop? If your index is the letter "O" in "HELLO", you're comparing "HI" with "O" and then nothing! To keep this from happening, you need to stop your comparisons so that all the letters in "HI" have something in the string "HELLO" to get compared to.






The last tricky thing is, the problem specified that the method has to behave the *same* way as the existing indexOf. That takes in just one argument (the little string) and you apply it to the big string. My implementation takes in both the big string and the little string as arguments, so I had been worried that I hadn't actually solved the requirement. 


However, how is it possible to write your own implementation as a method by itself without "knowing" the length of the big string? Not sure whether this is do-able.... I checked the textbook to see whether the authors printed this problem. (I have to confess that I've been studying with a PDF of the pre-print copy of the textbook since it's easier to have on hand, and I leave the heavy text at home). I saw that the printed version omitted this problem, so I'm assuming that the editors decided that it wasn't quite a perfectly designed problem because of that mismatch. Thoughts?

Monday, December 12, 2011

Program to Calculate the Scrabble Score of a Word

Problem:
In most word games, each letter in a word is scored according to its point value, which is inversely proportional to its frequency in English words. In ScrabbleTM, the points are allocated as follows:

For example, the Scrabble word "FARM" is worth 9 points: 4 for the F, 1 each for the A and the R, and 3 for the M. Write a ConsoleProgram that reads in words and prints out their score in Scrabble, not counting any of the other bonuses that occur in the game. You should ignore any characters other than uppercase letters in computing the score. In particular, lowercase letters are assumed to represent blank tiles, which can stand for any letter but which have a score of 0. (Robers ch 9, problem 5)

What it looks like:


/* File: ScrabbleCalc
 * -----------------
 * This program takes in an arbitrary word from the end-user and calculates its value according to the points alloted
 * to each letter by the game Scrabble. Characters must be upper-case; lowercase letters are ignored.
 * 
 * The program makes use of the private method 'scabbleScore' that takes in the input string and iterates through
 * each charcter. The method also establishes the integer 'score,' an instance variable that keeps track of the
 * accumulating points for the word. In each loop, it asses character via a switch statement and adds the appropriate 
 * points value for the character to 'score.'
 */
import acm.program.*;
public class ScrabbleCalc extends ConsoleProgram {
    public void run() {
       String word = readLine("Enter Scrabble word (all in uppercase) and we'll calculate your score: ");
       print(scrabbleScore(word));
    }
    private int scrabbleScore(String scrabbleWord) {
        int score = 0;
        for (int i = 0; i < scrabbleWord.length(); i++){
            char calculatedLetter = scrabbleWord.charAt(i);
            switch (calculatedLetter) {
                case 'A':
                case 'E':
                case 'I':
                case 'L':
                case 'N':
                case 'O':
                case 'R':
                case 'S':
                case 'T':
                case 'U': //Jesus this is fugly
                    score +=1; break;
                case 'D':
                case 'G':
                    score +=2; break;
                case 'B':
                case 'C':
                case 'M':
                case 'P':
                    score +=3; break;
                case 'F':
                case 'H':
                case 'V':
                case 'W':
                case 'Y':
                    score +=4; break;
                case 'K':
                    score +=5; break;
                case 'J':
                case 'X':
                    score +=8; break;
                case 'Q':
                case 'Z':
                    score +=10; break;
                default: break;
            }
        }
        return score;
    }
}

What made it tricky:

Whenever I tell other programmers I'm learning programming with Java, they express much exasperation about the language, and I begin to see why. The statement that I had wanted to express was,  "If the letter at increment "i" is A, E, I, L, etc, then add 1 to the instance variable "score." I was looking for the switch statement to support an "or" statement (ie "case 'A' || 'E' || 'I' || 'L' ") but alas, the syntax isn't that neat. I had to list all the separate cases individually, though fortunately I didn't have to do the action block repeatedly for cases with identical points! I don't exactly know how you'd handle this in Python or Ruby but I expect it would be more succinct.
I think if building a Scrabble calculator in the "real world," you'd want to use a hash table  to easily turn the letter:points match into key:value pairs. We haven't gotten to hashes and arrays yet, so the tools for this problem were either a) switch statements or b) cascading "if" statements.

Saturday, November 12, 2011

Program to Create Five Random "Words"

Problem: Write a method randomWord that returns a randomly constructed “word” consisting of randomly chosen letters. The number of letters in the word should also be chosen randomly by picking a number between the values of the named constants MIN_LETTERS and MAX_LETTERS. Write a ConsoleProgram that tests your method by displaying five random words. (Roberts ch 10, problem 2).

What it looks like:



/* File: fiveRandomWords
 * --------------
 * This program generates random "words," just random letters stuck together. The characters of the word are 
 * random, but must be an upcase letter-- these are integers that correspond to the ASCII characters of the 
 * upcase alphabet. The length of the word is also random, but bounded by the constants MIN_LETTERS and
 * MAX_LETTERS.
 * 
 * The run method of the program simply starts of with blank String instance and keeps pulling random letters
 * out of the random generator until the word length is reached. It relies on a private method to generate the 
 * random characters and to set the word length.
 */

import acm.program.*;
import acm.util.RandomGenerator;

public class FiveRandomWords extends ConsoleProgram { 
    public void run() {
        for (int i = 0; i < 5; i++) {
            int wordLength = rgen.nextInt(MIN_LETTERS, MAX_LETTERS);
            String myRandomWord = " ";
            for (int j = 0; j < wordLength; j++) {
                myRandomWord += randomLetter();
            }
            println(myRandomWord);
        }
    }
    
    private char randomLetter() { 
        return (char) rgen.nextInt((int) 'A', (int) 'Z');
    }
    private RandomGenerator rgen = RandomGenerator.getInstance();
    private static final int MIN_LETTERS = 3;
    private static final int MAX_LETTERS = 10;
}
What made it tough:

This simple problem is all about getting comfortable with scalar types: data values that can be represented as numbers. The key snippet in the program is this:

 private char randomLetter() { 
        return (char) rgen.nextInt((int) 'A', (int) 'Z');
    }

How do you return a *character* that's random but bounded by the *integers* A and Z? Because the "char" data type in Java maps directly to Unicode and ASCII. Unicode and ASCII are both systems that match characters (letters, punctuations marks, etc) to integers so that it's easier for the computer to understand. 

Fun facts I learned: 
  • Precursors to ASCII literally mapped 'A' to 1, 'Z' to 26, and everything in-between, but ASCII didn't do so since there are additional characters that precede letters. 
  • The ASCII system came first, Unicode second. ASCII characters don't encode most non-Western characters, so Unicode was created with thousands of new characters to account for these.
  • Unicode contains everything that's in ASCII, and to be completely backwards-compatible, the first 128 digits of Unicode map directly to ASCII


Because characters are mapped this way, you can perform some numeric operations on *letters* as specifying a range like I did above, or taking a letter 'A' and adding 5 to get 'F.'  When specifying the range of characters, you could either provide the character or the number equivalent-- the computer can handle each one and in fact the (int) cast isn't necessary- it's there to make things clearer for humans so they don't think, "Why are you bounding nextInt with characters?" You must specify the (char) cast however to make sure that when you do rgen.nextInt, you get a letter back, not a number.


Program to Create Acronyms

This came from the book as an example, but I wanted to make it better :)

This program, taken from the unit in the book that deals with characters and string manipulation, lets the user input a string (usually a sentence of multiple words) and get an acronym back. The method that builds the acronym works by taking the very first character, and after that, hunting for space characters. It looks at the character right *after* each space and slices that following character to add to the acronym.

There is a bug however-- what happens if the user enters in "hello**world" (say that "*" is a space here)? The acronym SHOULD be "hw", but instead you get "h*w." No good.

I wrote a program, first to test out the buggy method to verify what the acronym for "hello**world" would be, and then to fix that edge case.

What it looks like:



/* File: acronymBuilder
* --------------------
* This program takes a string and returns the acronym, or, a string made up of the first character of each
* word. It works via a private method that takes the first character and saves it to the instance variable
* "result." Then it finds each space, takes the character directly after the space, and takes that following 
* character and appends it to "result" until there are no spaces left.
* 
* This method originally appeared in ch 10 of Roberts' "The Art and Science of Java," but the original method
* didn't account for inputs where there were 2 spaces in a row, so I'm making the modification and writing a
* run method to use it.
 */
import acm.program.*;
 
public class acronymBuilder extends ConsoleProgram {
    public void run(){
        String initialString = readLine("Enter a string you want to generate the acronym for:");
        String result = acronym(initialString);
        println(result);
    }
    
    private String acronym(String str) {
        String result = str.substring(0, 1); 
        int pos = str.indexOf(' '); 
        while (pos != -1) {
            if (str.charAt(pos + 1) != ' ') { 
                result += str.substring(pos + 1, pos + 2); 
            }
            pos = str.indexOf(' ', pos + 1); //Finds the next space sign           
        } 
    return result;
    }
}
What made it tough: There were a couple bugs that stumped me along the way.
First, I wanted to write an "if" statement checking to see if there are two space signs in a row. Specifically, you look at a space sign and see if the character after it is also a space sign. The "if" statement looked like this:

if (str.charAt(pos + 1) != " ");

Eclipse highlighted this statement in red and did not like it. Why?

My first thought was because of that problem that you can't compare strings with each other. The "==" and "!=" operators are mathematical comparisons that you can only use on primitives like ints, whereas for strings that operator will examine the underlying object in memory that stores the string; it won't examine the value.

But wait a minute, that can't be it. First of all, comparing strings is technically a valid argument...it will just usually return an inaccurate result. Like if there were two strings "hello" and "hello" that pointed to two different objects, it will return "False" when the developer probably wanted it to return "True". 

Also, str.charAt(pos + 1)is actually a char, not a string, and chars are primitives, so it should be OK to use the "!=" on it.

The problem was that the second part of my comparison, " ", is a string, so I was comparing a char against a string which isn't ok. All I had to do to fix it was put the space sign in single quotes, since Java denotes chars with single quotes. Easy :)

The second bug came up as I tried to run the program. This is what the code looked like at that point:

import acm.program.*;
 
public class acronymBuilder extends ConsoleProgram {
    public void run(){
        String initialString = readLine("Enter a string you want to generate the acronym for:");
        String result = acronym(initialString);
        println(result);
    }
    
    private String acronym(String str) {
        String result = str.substring(0, 1); 
        int pos = str.indexOf(' '); 
        while (pos != -1) {
            if (str.charAt(pos + 1) != ' ') { 
                result += str.substring(pos + 1, pos + 2); 
                pos = str.indexOf(' ', pos + 1); //Finds the next space sign
            }
        } 
    return result;
    }
}
When I ran the code, it compiled and I input the string "ne**s****w". (There were no "*" signs really, I just used them to demonstrate) where spaces were. When I hit "return", the program didn't print anything! Why?

At first I thought there was an unclosed loop or something, but then I realized: I had inserted an "if" statement checking for if the character following the space sign is NOT another space, but I didn't tell the program what to do if that following character WAS a space! The direction to move on to the next space sign (ie "pos = str.indexOf(' ', pos + 1)" was inside the new "if" statement! Once I adjusted the stuff in my loops I was fine.

Strange though-- on that second bug, my return statement WAS outside the "if" statement, and I had already initiated "result", so why didn't my program atleast print the first character...?

Sunday, October 30, 2011

Program to Test if a Word is a Palindrome.

Problem: "A palindrome is a word that reads identically backward and forward, such as level or noon. Write a predicate method isPalindrome(str) that returns true if the string str is a palindrome. In addition, design and write a test program that calls isPalindrome to demonstrate that it works. In writing the program, concentrate on how to solve the problem simply rather than how to you make your solution more efficient." (Roberts ch 10, problem 6.)

What it looks like:
/* File: PalindromeTester
 * ----------------------------
 * This program lets a user enter in a string, and will respond with confirmation that the word is
 * or is not a palindrome. It uses a private boolean method isPalindrom(). This method goes 
 * halfway down each character of the word and compares to see whether that character and the
 * character at the mirror position on the string equal each other. If they don't, then break and 
 * returnn false, but if they do for all letters in the first half of the string, then return true.
 */

import acm.program.*;
 
public class PalindromeTester extends ConsoleProgram {
    public void run(){
        String str = readLine("Is it a palindrome? Enter string to test here:");
        if (isPalindrome(str)) {
            println("Yes it is!");
        }
        else println("No it isn't.");
    }
  

    private boolean isPalindrome(String str) {
        for (int i = 0; i < str.length()/2; i++) {          
            if (str.charAt(i) != str.charAt(str.length()-i-1)) {          
                return false;
            }                  
        }
        return true;
    }
}

What made it tough:

When I first wrote this, I had a bug. When checking to see if a word is a palindrome, the general approach is, for all charachters "i", to compare the "ith" character with its mirror character and see if they are equal, for all characters "i". So if your word is "kook", you'd compare the first last one to see if the characters are not the same (break if they're not), see if the two middle ones are the same, and so on.

In my buggy version, this is how I did the mirror check:
"if (str.charAt(i) != str.charAt(str.length()-i))"


This is the right version:
"if (str.charAt(i) != str.charAt(str.length()-i-1))"


Why do you have to subtract the extra 1 when you're trying inspect "i"'s mirror? In short because the "str.length" method counts starting at 1 when it returns how many characters a string contains, and meanwhile the charAt(i) method returns the "ith" character in a string, but counting as if the first letter of that string is 0. So because of this, the character at the second half of the word was actually always one after it should have been.

The funny thing is, when I wrote this and ran into the error, it didn't manifest itself via a warning in the Eclipse editor, or as red text showing up in my program's response. Instead the problem killed my program completely. I'd click to run the program, it would let me load up the interface for the user and enter in a word to test, and then instead of returning a result it would abort.

I'm sure there's a reason why my program reacted to the error in that particular way, but I'm not sure what that is. Thoughts?

Sunday, October 16, 2011

Class definition to represent playing cards


Problem:

Implement a new class called Card that includes the following entries:
* Named constants for the four suits (CLUBS, DIAMONDS, HEARTS, SPADES) and the four ranks that are traditionally represented in words (ACE, JACK, QUEEN, KING). The values of the rank constants should be 1, 11, 12, and 13, respectively.
* A constructor that takes a rank and a suit and returns a Card with those values. • Accessor methods getRank and getSuit to retrieve the rank and suit components
of a card.
* An implementation of the toString method that returns the complete name of the card as in exercise 1. Remember that you can use the + operator to connect the different parts of the string together, as shown in the toString implementation for the Rational class in Figure 6-9.

Roberts ch 6, problem 7.

/* File: Card class
 * ----------------------------
 * Class to represent a playing card. There are named constants for suit and face card values to translate integers into respective values,
 * so a client of this class can represent this information with either the integer or the constant.
 * 
 * How you'd use this class:
 * a) Create a new playing card: "myCard = new Card (12, 2)" or "myCard = new Card (Card.QUEEN, Card.HEARTS)"
 * b) Get the rank or suit of cards: "myCardSuit = myCard.getSuit()" or "myCardRank = myCard.getRank()"
 */

public class Card {
    
    public Card (int rank, int suit){ //Constructor
        cardRank = rank; // A real program would check whether "rank" is between 1 and 13, and if not, raise an illegal arguments exception
        cardSuit = suit; // A real program would check whether "rank" is between 1 and 4, and if not, raise an illegal arguments exception
    }
 
    public String getRank() {
        switch (cardRank) {
            case ACE: return "Ace";
            case JACK: return "Jack";
            case QUEEN: return "Queen";
            case KING: return "King";
            default: return Integer.toString(cardRank); 
        }
    }
   
    public String getSuit() {
        switch (cardSuit) {
            case SPADES: return "Spades";
            case HEARTS: return "Hearts";
            case CLUBS: return "Clubs";
            case DIAMONDS: return "Diamonds";
            default: return "no suit."; // Won't actually happen but Java needs it or it thinks the switch statement is incomplete
        }
    }
    
    public String toString() {
        return ("The" + getRank() + " of " + getSuit() + ".");
    }
    
    // Instance variables keep track of the suit and rank values for the lifetime of the card object
    private int cardSuit; // Keeps track of the Card object's suit
    private int cardRank; // Keeps track of the object's rank
    
    // Named Constants to establish int values for each of the suits -- Static variables are class variables
    public static final int SPADES = 1; //does this need to be "void"...?
    public static final int HEARTS = 2;
    public static final int CLUBS = 3;
    public static final int DIAMONDS = 4;
  
    // Named constants to establish int values for each of the suits 
    public static final int ACE = 1; //How does this named constant interact w/ the rest of the program? This part is a little messed up
    public static final int JACK = 11;
    public static final int QUEEN = 12;
    public static final int KING = 13;
}
This problem came before the "Employee" class problem in the book, but I definitely think it's more confusing than writing the Employee class and only really understood it after doing problem 8. At heart, the main point of both classes is to store information about an employee instance or playing card instance and let clients of the class access the information via public methods.

This one had an extra wrench thrown in because we needed to associate integers with suit or facecard values. I completed the class definition and I get now that the benefit of having the named constants is that, even though the constructor method is expecting integers for the suit and number values, you can pass the constants instead so it's a bit more human-readable.

For example, suit information for any particular card is represented in four different places:
1) In the constructor method, the client passes the suit value through as a parameter that instantly gets stored to the instance variable.
2) The instance variable that keeps track of the suit for the lifetime of the object
3) The named constants series translates suit integers into strings. ** Question: Why do we have this level of translation instead of having the constructor look for a string instead of an integer for the "suit" argument? ** From my understanding it's because it's easier to check whether ints are between 1 and 4 than to check all the different casings and spellings people might use to input a string, so it's more bug-tolerant.
4) The getSuit() method returns the current value of the cardSuit instance variable, so a client of the class can store that information in a variable of their own.

Class to represent employees

Problem:

"Write the definition for a new class named Employee that stores the following data for a single employee:
 * The name of the employee (a String)
 * The name of the employee’s supervisor (also a String)
 * The employee’s annual salary (a double)

As with the other classes defined in this book, you should make sure that the instance variables containing these values are private and instead provide get and set methods to retrieve or change any of the values." (Roberts ch 6, problem 8)

/* File: Employee
 * ----------------------------
 * Class to store information about employees, retrieve that information, and reset the information.
 * How you'd use this class:
 * a) Enter in a new employee, ie " emp = new Employee('Bob Cratchit', 'Ebenezer Scrooge', 25.00) "
 * b) get information, ie " name = emp.getName() "
 * c) set information, ie " emp.setSupervisor('Mickey Mouse') "
 */

public class Employee {
    public Employee (String name, String supervisor, double salary) { 
        //LOCAL variables. Exist just for the run of this constructor method. The client passes name/suvervisor/salary information
        // in initially and it immediately gets used to set the instnace variable value.
        employeeName = name;
        supervisorName = supervisor;
        employeeSalary = salary;
    }
    
    //Getter methods:
    
    public String getName() { 
        return employeeName;
    }
    public String getSupervisor() {
        return supervisorName;
    }
    public double getSalary() {
        return employeeSalary;
    }
    
    //Setter methods: These have no return type, they just reset the instance variables
    
    public void setName(String newName) { 
        employeeName = newName;
    }
    
    public void setSupervisor(String newSupervisor) { 
        supervisorName = newSupervisor; 
    }
    
    public void setSalary(double newSalary) { 
        employeeSalary = newSalary;
    }
    
    // INSTANCE variables: Stuff that we're keeping track of for the lifetime of the object. 
    // It gets set using the temp (aka local) variables in the constructor
    
    private String employeeName;
    private String supervisorName;
    private double employeeSalary;

}

This chapter in the book gets students started with writing their own classes. The problem was very simple, but it's good refresher on how objects work see the difference between instance variables and local variables in action.

 It took me a while to get used to the fact that each piece of information is represented 3 times:
* In the constructor method, the client of this class creates a new instance of the "Employee" class and sets the initial name, supervisor and salary values. These are passed through as local variables that exist just for the life of the constructor method and instantly get stored to the instance variable.
* Instance variables that store the name, supervisor and salary values for the lifetime of the object.
* The getter method returns the name/supervisor/salary information from the current value of the instance variable, so clients of the class can store the information in a variable of their own. The setter methods update the instance variable based on new values that the client of the class passes (using a local value that exists just for the life of the setter method).

 Once I got a firm hold on why name/supervisor/salary information is distinct when represented in the local variables versus the instance variables, I got a better understanding of how classes work and how you'd write a class that other programs can use.

Friday, September 23, 2011

Arithmatic Tutor, updated with variable congrats messages

Problem: "To add variety to the interaction, modify your solution to exercise 5 so that it randomly chooses among four or five different messages when the student gets the right answer."

What it looks like:


The code was all the same except that instead of printing the hard-coded string "Right" if the user got the answer right, it printed answerAffirmation. This was a method that generated one of 4 random integers and mapped each integer to a different congrats message.

 if (userAnswer == programSolution) {
     println(answerAffirmation());
 }
 else {
     println("No, the correct answer is " + programSolution); 
 }

I used a switch statement. At first the method was buggy because the program thought I wasn't returning a result:

The problem was, even though having the strings map to one of four integers that I knew would be exhaustive, the program didn't realize that answers could only come from that random integer, so I must include a default string to get returned:

In reality the message "Grrrrreat!" won't get returned unless there's a bug with my method loops or with the rgen factory resource.


Sunday, September 18, 2011

Arithmetic Tutor Program (or, structuring and debugging loops)

Problem:

Write a program that poses a series of simple arithmetic problems for a student to answer.

Your program should meet these requirements:
• It should ask a series of five questions. As with any such limit, the number of questions should be coded as a named constant so that it can easily be changed.
• Each question should consist of a single addition or subtraction problem involving just two numbers, such as “What is 2 + 3?” or “What is 11 – 7?”. The type of problem—addition or subtraction—should be chosen randomly for each question.
• To make sure the problems are appropriate for students in the first or second grade, none of the numbers involved, including the answer, should be less than 0 or greater than 20. This restriction means that your program should never ask questions like “What is 11 + 13?” or “What is 4 – 7?” because the answers are outside the legal range. Within these constraints, your program should choose the numbers randomly.
• The program should give the student three chances to answer each question. If the student gives the correct answer, your program should indicate that fact in some properly congratulatory way and go on to the next question. If the student does not get the answer in three tries, the program should give the answer and go on to another problem.

(Roberts Ch 6, problem 7)

This was a fun problem to write, though debugging took a long time. Here was how I split up the problem, given the requirements. There are three major parts of this program:
1) Generate the arithmatic program.
2) Present it to the student and evaluate his answer
3) Stop the program after 5 presented problems.

These were my smaller steps:
* Generate two numbers (0-20) and an operator (comes from boolean true/false). Use random generator instance.
* Put them together and assess them so the program "knows" the correct answer
* If the result (“problemAnswer”) is not between 0-20, don't print anything and start again
* If it's between 0-20, then present the problem to the user. Declare "int userAnswer = readln(print the equation here)".
* To keep track of user attempts, start a local variable "countUserAttempts" and make it start at 1
* If problemAnswer == userAnswer, break from the loop (print that it's right) and start again
* If problemAnswer != userAnswer, then print it's wrong. Add +1 to the “countUserAttempts” variable and send them back thru the inner loop to try again.
* Let user submit a second answer. If it's right then print that it's correct and start again. If it's wrong then add +1 to the countUserAttempts variable (so now it’s three) and send them back thru.
* If it’s wrong again, then it will make countUserAttempts equal 4 so it will break from the inner “while” loop and roll down to the next argument and print the correct answer.

What it looks like:


/* File: ArithmaticTutor
 * This program shows a series of arithmetic problems to the user and evaluates his or her input.
 * In accordance with the problem specs, we only present components between 0 and 20, and make
 * sure that the answer (sum or difference) is between 0 and 20 as well before giving it to the user.
 * We make up a problem on the fly using 2 methods that each use a random generator instance;
 * one to generate the numbers to in our problem, and a second to decide whether the operator is plus 
 * or minus. There's also a method to collect the user's input. There are two count-keeping variables:
 * one, "countPresentedProblems," makes sure that we give the user only 5 problems (or 
 * however many are allowed by the "maxProblems" constant. The other, "countUserAttempts,"
 * which is inside the inner "while" loop, keeps track of user attempts to make sure 
 * he or she does only 3 attempts. If the user gets the answer right in 3 or fewer attempts, we print 
 * in 3 or fewer attempts, we print "Right!" and move on to the next problem. If not,
 * we just tell the right answer and move on.
 * 
 */
    import acm.program.*;
    import acm.util.RandomGenerator;

    public class ArithmaticTutor extends ConsoleProgram {
        public void run() {
            println("Welcome to Math Tutor! Prepare to be challenged.");
            int countPresentedProblems = 0; 
            while (countPresentedProblems < maxProblems) {
                // First we put together all the stuff needed for our problem and assess the first problem ourselves 
                int firstNumber = generateNumber(0,20); 
                int secondNumber = generateNumber(0,20); 
                boolean isPlusNotMinus = plusNotMinus();
                int programSolution = evaluateProblem(firstNumber, secondNumber, isPlusNotMinus);
                // Then we present it to the student (if the answer is between 0 and 20)
                if (programSolution > 0 && programSolution < 20){
                    countPresentedProblems +=1;
                    int userAnswer = getUserAnswer(firstNumber, secondNumber, isPlusNotMinus);
                    int countUserAttempts = 1;
                    while (countUserAttempts < 3 && userAnswer != programSolution) {
                        userAnswer = readInt ("Wrong. Try another answer:");
                        countUserAttempts += 1;
                    }
                    if (userAnswer == programSolution) {
                        println( "Right!");
                    }
                    else {
                        println("No, the correct answer is " + programSolution); 
                    }
                }
            }
         }
        private final static int maxProblems = 5;
  
        private RandomGenerator rgen = RandomGenerator.getInstance();
  
        private int generateNumber(int min, int max) {
            int number = rgen.nextInt(min, max);
            return number;
        }
        private boolean plusNotMinus() {
            return rgen.nextBoolean();
        }
        private int evaluateProblem (int firstNumber, int secondNumber, boolean plusNotMinus){
            if (plusNotMinus) {
                return firstNumber + secondNumber;
            }
            else {
                return firstNumber - secondNumber;
            }
        }
        private int getUserAnswer (int firstNumber, int secondNumber, boolean plusNotMinus){
            if (plusNotMinus) {
                return readInt("What is " + firstNumber + "+" + secondNumber + "?");
            }
            else {
                return readInt("What is " + firstNumber + "-" + secondNumber + "?");
            }
        } 
}
What made it hard: Keeping track of your loops. Poorly structured loops kept on causing bugs! For example there was a bug where if you entered 2 wrong answers in a row, it fell back to the “Wrong, the correct answer is [programAnswer]” part, even though it should wait till 3 wrong entries. The problem was that the part of the code that says “Wrong, the correct answer is [programAnswer]” was *inside* the "while" loop, so once we evaluated that it was wrong it would print the correct answer then still re-prompt for another attempt! Then I moved that “No, the correct answer is [correct answer]” part to outside the nearest loop, but then it started getting run for every submitted answer, even if they got it right! Here are my other bloopers, along with a brief explanations of what was wrong with the code when they appeared.

Sunday, August 7, 2011

Program to Flip a Coin (until you get 3 "heads" in a row):

"Write a program that simpulates flipping a coin repeatedly and continues until three consecutive heads are tossed. At that point your program should display the total number of times the coin was flipped." (Roberts ch 6, problem 2).

What it looks like:



/*
/* File: FlipThreeHeads.java
 * ----------------------------
 * This program simulates flipping coin repeatedly until you get 3 heads in a row, at which point you
 * print how many flips it took to get those 3. It uses an instance of the RandomGenerator class and keeps count using a local variable 'count.'
 */

import acm.program.*;
import acm.util.*;
public class FlipThreeHeads extends ConsoleProgram{
 
    public void run() {
     
        // Placeholders X, Y and Z to store the most recent flip and the past 2 flips (when they happen):
        String flipX = flipCoin(); 
        println(flipX);
        String flipY = null;
        String flipZ = null;
        
        // Local variable to keep track of how many flips we've done so far:
        int count = 1;
  
       //"As long as X, Y and Z aren't equal to each other and aren't 'heads'..."
        while ((flipX != flipY) || (flipX != flipZ) || (flipZ != "heads")){
            count += 1;
            String nextCoin = flipCoin();
            println(nextCoin);
            //Shove down the values of the placeholders to make flipX the most recent result  
            flipZ = flipY;
            flipY = flipX;
            flipX = nextCoin;
        }
        println("It took " + count + " tries to get 3 consecutive heads.");  
    }
 
    private RandomGenerator rgen = RandomGenerator.getInstance();

    private String flipCoin() {
        boolean booleanResult = rgen.nextBoolean();
  
        String flipResult;
        if (booleanResult == true) {
            flipResult =  "heads";
        } else {
            flipResult = "tails";
        }
        return flipResult;
    }
}

What made this hard/interesting:

Naming things is hard! Because this program requires that you keep track of the 3 most recent flips so that you can compare them and see if there were 3 heads in a row, you have to create a lot of variables. However, I kept being tempted to use variable names like "flipCoin" and "nextFlip" since they all do similar things related to the actual coin flip. If there's a way to make this program more spartan and not use as many variables that would be great.

Here's how a run of the program works and each step needs its own variable or set of variables:

1) You establish 3 local variables "flipX," "flipY" and "flipZ." As we keep flipping our programmatic coin these will keep track of the 3 latest flips. We will build a shove-over mechanism so that with each new coin flip, we'll turn flipX into the latest result, turn flipY into the old value for flipX, and turn flipZ into the old value for flipY.

Also, you create flipX with an initial value by calling the flipCoin() method.

2) The flipCoin() method is a private method that we call that just simulates flipping a coin. It works by pulling a random boolean out of our RandomGenerator instance and translating the returned "true" or "false" into "heads" or "tails."

3) booleanResult is a local variable inside the flipCoin() method that stores the "true" or "false" that gets returned from calling nextBoolean(). flipResult is a local variable that takes the boolean and stores the "head" or "tail" translation.

4) nextCoin is part of our main method and always stores the most recent flip. We keep resetting it as we keep on flipping coins (and resetting flipX to equal it and going on with the shove-down mechanism described in step (1).

The "flipCoin" method was particularly hard to make up names for inside because there are 3 variables that mean essentially the same thing (those that turned out to be called "flipResult," "booleanResult" and "flipCoin." I kept on being tempted to name them "flipResult", but all the distinct variables are necessary in order to return the desired result.

Sunday, July 31, 2011

Program to Draw a Random Card

Problem: Write a program that displays the name of a card randomly chosen from a complete deck of 52 cards. You program should display the complete name of the card. (Roberts ch 6, problem 1).

What it looks like (2 sample runs):

How the code looks:
/*
/*File: DrawCard.java
 * This program simulates drawing a card from a standard deck. It uses an instance of acm.util's 
 * RandomGenerator class to create two new random integers: one helping to supply the value (2-10, Ace, Jack, Queen, 
 * King), and the other integer helps determine the suit (Spades, Clubs, Hearts, Diamonds). Each integer value maps
 * to a card value or suit.
 *  * */
import acm.program.*;
import acm.util.*;

public class DrawCard extends ConsoleProgram{

    public void run() {
   
    int d1 = rgen.nextInt(1,4);
    int d2 = rgen.nextInt(1,12);
   
        String suit = null; //Declare a variable of null value. 
        //Then use switch statement to set a value
        switch (d1) {
            case 1: suit = "Spades"; break;
            case 2: suit = "Clubs"; break;
            case 3: suit = "Hearts"; break;
            case 4: suit = "Diamonds"; break;  
        }
   
        String value = null;
        switch (d2) { 
            case 1: value = "Ace"; break;
            case 11: value = "Jack"; break;
            case 12: value = "Queen"; break;
            case 13: value = "King"; break;
            default: value = Integer.toString(d2); break; // Returns a numeric value in string form
                // if a non-face card gets drawn
        }
        
    println("The " + value + " of " + suit);
   
    }
    //Instance variable for our random generator macheeeeen
    private RandomGenerator rgen = RandomGenerator.getInstance();
}

What made this interesting:

Two interesting concepts you exercise here:

1) Compartmentalizing your program. Instead of just storing 52 potential card values and randomly picking one of them, you can build something neater. There are 4 suits of equal distribution and 13 numeric values, so we can generate two random numbers for the face and numeric numbers and map them to card values. This is better than simply storing 52 potential card values because...

2) The concept of using an instance of a class to do stuff. In this case is a class of objects available to me called RandomGenerator. An instance of the RandomGenerator class is not one random number itself. It is an object that you can create in your program and then call upon to return random numbers. (It will recognize the method getInt() method). So the individual random numbers are a layer of abstraction away from the class that we get from the ACM library.

Why is this important?

This was actually familiar to me based on my work at Twilio. Twiio's REST API lets you make calls, send SMS messages, and pull information about your Twilio account. You can make a request to the API by a raw HTTP request to Twiio. Or, you can be clever and use a wrapper library that creates a "REST client". This is actually a class of objects that know how to make HTTP requests to Twilio, so instead of piecing together a big URL every time you need to communicate to Twilio, you can send commands to your instance of the REST client and communicate via methods instead of a raw URL.

Examples:

A1) Making a phone call directly via a direct HTTP POST to Twilio's API:

POST https://api.twilio.com/2010-04-01/Accounts/account123/Calls/
Auth Headers: username account123, password token456


POST parameters:
* To: 503-111-2222
* From: 503-222-3333
* Url: http://mycoolapp.renee.com


A2) Sending an SMS:


POST https://api.twilio.com/2010-04-01/Accounts/account123/SMS/Messages
Auth Headers: username account123, password token456


POST parameters:
* To: 503-111-2222
* From: 503-222-3333
* Body: Hello World

VERSUS

B) Making a phone call, then sending an SMS message using an instance of the TwilioClient class (from Sean Sullivan's Java wrapper library):

/*import twilio.client.*;
TwilioClient c = new TwilioClient("account123", "token456");

c.call("503-111-2222", "503-222-3333");
c.sendSMSMessage("503-111-2222", "503-222-3333", "Hello world");

See, isn't that better? The advantage is don't have to put together the URL every time or worry about validating each request. You just create your object, which has the account SID and auth token baked in and can recognize the methods "call" and "sendSMSMessage." Instead of needing to be familiar with the Twilio API (which is actually very simple), you can just be familiar with methods in your language of choice that let you make calls or send SMS.