Lab #2: MidLibs

Overview: Work in pairs, both together and separately

In this lab we'll write a non-trivial sized program in Java, but it will be written following the procedural programming paradigm — not the way one normally programs in Java. However, we'll get familiar with how Java language features, run-time features and conventions enable and even encourage collaboration.

You'll work in pairs on a program to do "Mad Libs". Sometimes you'll be working together at a single computer, sometimes separately on different parts of the same project. At all times, you'll be constantly testing and debugging as you go. At the end, you should be well-positioned to start learning the core or this class: Objected-Oriented Programming.

Step 1: Linked lists (partners together)

Create a lab02 directory.

Working together with a partner (at one computer), create a file in your lab02/ with the following class definition:

public class StringNode {
  String data;
  StringNode next;
}
You will use this class as the basis for some functions manipulating linked lists of strings. Again in your lab02/, create a class ListStuff that defines the following methods/functions:

// addToFront(s,Nold) returns a StringNode reference representing the list obtained by adding s to the front of list Nold
public static StringNode addToFront(String s, StringNode Nold) {
  // you will fill this in
}

// listToArray(N) returns a reference to an array containing the same strings as in the list N (in order)
public static String[] listToArray(StringNode N) {
  // you will fill this in
}

You must define a main method/function in ListStuff.java to test the code with (of course!), and you may add any other methods/functions you find useful.

Note: A "list" is now represented by a StringNode reference. The "empty list" is represented by a null reference. So, for example:

StringNode N = null;      // at this point N *is* an empty list
N = addToFront("rat",N);  // at this point N *is* the list ("rat")
N = addToFront("dog",N);  // at this point N *is* the list ("dog","rat")
N = addToFront("pig",N);  // at this point N *is* the list ("pig","dog","rat")
String[] A = listToArray(N);
for(int i = 0; i < A.length; i++) {
  System.out.println(A[i]);
} 
... should print out this when it's done:

pig
dog
rat

Step 2: Split the Work (partners separate)

Partner 1
You will create a class WordRead that defines a function
public static String[] get(String fname) { ... }

that takes a filename fname and reads all the strings in that file, returning them (in order) in an array. Since you don't know how many strings are in the file, you're going to have to use a linked list (good thing you have one!) to read and store, then copy into an array. Unfortunately, you really need to have things stored in order!

Of course you'll have to thoroughly test this by writing a "main" for your WordRead class. For input file nouns.txt your test program should simply call get("nouns.txt") and print the resulting array, showing the words in nouns.txt one per line.

One thing you'll need to be able to do is create a Scanner that reads from a file. Without understanding what's going on, here's how to do that:

Scanner sc = null;
try {
  sc = new Scanner(new FileReader(fname));
} catch(IOException e) {
  e.printStackTrace(); System.exit(1);
}

You'll need a "import java.io.*;" for that. I also suggest you take a look at the Scanner class's hasNext() (see the Scanner API documentation). The gist is that sc.hasNext() returns true if there's a "next" string to be read, and false otherwise. This will tell you when to stop reading from the input file.

Partner 2
You'll create a class named Formatter and define in it a function
public static void writeInColumns(String[] A, int cols) { .. }

that takes an array A of strings and a positive int "cols" and prints the strings from A out, in order, separated by spaces, but never using more than "cols" characters (including spaces!) in a line. So you have to periodically insert newlines as you go.

Of course you'll have to thoroughly test this by writing a "main" for your Formatter class. Here's a sample of how writeInColumns works for an array containing the strings: These, are, the, times, that, try, men's, souls.

cols = 20
These are the times
that try men's
souls.

cols = 10
These are
the times
that try
men's
souls.
Note: Test this thoroughly!

Step 3: Combining Your Work

Share your functioning code from Step 2 with each other. Then, on one computer, continue development by creating a class MidLibs that defines a program that takes a filename and prints the words in that file within 35 columns. The input filename will come as a command-line argument.

Command-line arguments

Take the following example for running a java program from the command line:

java ClassName foo bar 23

In this example, "foo", "bar", and "23" will be stored in the String[] args that is the parameter to the main() function for the class.
In other words, your main method will now receive as its parameter: String args[] = {"foo","bar","23"}

For MidLibs, if a filename isn't provided as a paramenter in the command line (args has length 0), you should print out a usage message and exit. System.exit(1) will do this for you.

Download the file madin01.txt.

Here's some sample runs for the program:

~/$ java MidLibs
usage: java MidLibs <filename>
~/$ java MidLibs madin01.txt
One of my @nounp came to see me in
my office. He was @adjective with
his @nounp . He asked if there were
any optional assignments he could
do to @verb things. I told him that
I don't believe in @nounp , but
that I was happy to help him @verb
for the final.

Step 4: Finalizing MidLibs

Create a file MidLibs.java which will be your full program.

The last step is to replace each @noun, @verb, @adjective and @nounp (plural noun) with a randomly selected word. You read the candidate words in from the files nouns.txt, verbs.txt, adjectives.txt. For a plural noun you can simply add an "s" to the end of a randomly chosen noun. Now you have a program that really does Mad Libs!

Note: The == sign cannot be used to test for equality between String objects. It tests for equal references, not strings. Instead, if A and B are Strings, you test for equality with

A.equals(B)

... which returns true if the strings are equal, and false otherwise.

For picking random words, remember from the previous lab that you can initialize a Random object. For this lab, let's seed it with the following:

Random rand = new Random(890);

Do that just once, and then generate random numbers like so:

int myrand = rand.nextInt(k);

Submit

Each student shall submit the source code of their team solution using the following:

~/bin/submit -c=IC211 -p=lab02 *.java

Review Submission

Log into the submission site: submit.cs.usna.edu and review the test cases run against your submission.

Do not simply look at the Score!

Click on the timestamp for your submission and click on the MidLibs to confirm that your program runs correctly.