Lab 1 - Java Zone

CSCI 151
Fall, 2018
Due:  11:59 pm, Sunday September 23, 2018

Assignment Description

In this lab you will be writing a number of short programs to get some practice working with Java.  The goals of the lab are to

The assignment consists of four programming problems.  You can get started by creating a folder called lab1 in your cs102 folder.

Getting organized

First, you should create a separate folder for your solutions.

% cd
% mkdir cs151 # skip if you already did lab0
% cd cs151
% mkdir lab1
% cd lab1

Create a Java project in Eclipse

If you are writing your programs in Eclipse, you can now create the project.

  1. Start up Eclipse by typing eclipse & on the command line
  2. Select File > New > Java Project
  3. Call it Lab 1 (or whatever you want)
  4. For the location use the Browse button to select the lab1 folder you created earlier
  5. Now select Finish


Problem 1:  Pyramids

Write a class called Pyramid that draws a simple pyramid out of * characters. The user will specify the height of the pyramid with a single command-line argument, as in

java Pyramid 5

Your program should

  1. Verify that the String array passed to the main method (i.e., args) has a length of 1.  If it does not, you should print a message to the user and then quit the program by calling System.exit(1);

    For reference, here is a program that will print out all of the arguments to the main method:

    public static void main(String[] args) {
    for ( int i = 0; i < args.length ; i++) {
    System.out.println( "Argument " + i + " is " + args[i] );
    }
    }
  2. Integer.parseInt is a static method in the Integer class that allows you to convert a String that represents a number and turn it into an int.  Use Integer.parseInt to convert the first argument args[0] into an int for the height of your pyramid
    int height = Integer.parseInt(args[0]);
  3. Print out the pyramid

Here are some examples of what the program output should look like:

% java Pyramid 5
*
***
*****
*******
*********

% java Pyramid 1
*

% java Pyramid
Usage: java Pyramid <height>


Problem 2:  What number am I thinking of?

Create a class called HiLo that plays a simple numeric guessing game.  The program will pick a number between 1 and 1000 and then the user will try to guess what it is.

To create a random number, you will need to create a Random object that will let you generate random numbers.  You then can use rand.nextInt(1000) to get a random integer between 0 and 999.  Just add 1 to get it into the right range.

    Random rand = new Random();
int target = rand.nextInt(1000) + 1;

Now you'll want to loop until the user guesses your number.  Keep in mind that you can use break and continue to exit or go to the next iteration of a loop.

Use a Scanner object to read from System.in which will capture keyboard input.  I recommend using 2 Scanners.  The first is created to scan System.in.  With this Scanner you can use hasNextLine()  and nextLine() to get an entire line of input from the user.  Create a second Scanner to scan the input line and then use hasNextInt() and nextInt() to see if the user actually typed a number and then retrieve it.   If the line doesn't start with a number (i.e., hasNextInt returns false) you should print a message out to the user and loop back to where you read an entire line.

    int userGuess = -1;

Scanner input = new Scanner(System.in); // I'm reading what the user typed

while ( input.hasNextLine() ) { // keep looping for each guess, use 'break' to exit

String line = input.nextLine(); // Read the next line of input from the user

Scanner s2 = new Scanner(line); // s2 will let me break 'line' apart

if ( s2.hasNextInt() ) { // check to see if s2 would next see an integer number
// Yay! do something with this
userGuess
= s2.nextInt(); // read in that number
} else {
// So sad, print a message and then...
continue; // jump back to the top of the while loop
}

/* probably more here! This is just an example, you know? */

}

Keep track of the number of valid guesses the user makes and let them know how they did at the end.  Here's a sample run:

Let's play a game!
I'm thinking of a number between 1 and 1000
Try to guess what it is!

Enter a guess: 500
Too low!

Enter a guess: 750
Too high!

Enter a guess: 625
Too low!

Enter a guess: -72
Too low!

Enter a guess: kittens
That's not a number, try again.

Enter a guess: 630
Too high!

Enter a guess: 629
You guessed my number! It took you 6 tries.


Problem 3:  Redaction

The subject of redacted documents has been in the news recently.  Let's try our hand at automatically redacting some documents.

Create a java program called Redactor that performs redaction on an input file.  The words to be redacted will be the command-line arguments to the program.  The document to be redacted will be read from System.in, and the redacted version of the document will be written to System.out.

The program should set up a Scanner to read from System.in line by line.  For each line, create another Scanner and take each word and see if matches one in args.  If it does, then print XXXXXX instead of the word.  If it doesn't, just print the word as is.  You should have spaces between the words you print, and the words should be on the same line as they were in the input file, but you can otherwise ignore whitespace.

For this program, you only need to handle exact matches. You'll find that words delimited by punctuation symbols won't be treated as matches, but you don't have to handle those cases (unless you want to).

note:  When comparing Strings, use the equals method rather than the == operator.  For example,

if(s1.equals(s2)) ...

I've pulled a few articles from the Review that you can use to test your redactor:  lab1-news.zip.   You can download this file to your lab1 directory and unzip it.

Run your program from the command line.  Use input redirection (denoted by the '<' symbol, as shown in the example below) to indicate the name of the input file.  For example, here are the first 15 lines of output of a sample run of the program.  The program redacts the words "Oberlin", "Kenyon", and "Yeomen" from the file football.txt.

% java Redactor Oberlin Kenyon Yeomen < football.txt
Football Advances to 2–0
Jane Agler, Staff Writer
September 15, 2017

The XXXXXX followed up a strong start to the season with a dominating 31–10
victory in their homecoming game against the XXXXXX College Lords. XXXXXX
now commands their first 2–0 start since 1989 following the defeat of their
rivals. While their previous 24–6 win over the Kalamazoo College Hornets
broke their 13-game losing streak that spanned over two seasons, this win
solidly indicates a transformed XXXXXX team.

“We had a mission at the beginning of the season,” new offensive coordinator
and quarterback coach Robbie Matey wrote in an email to the Review. “Take
everything one week, one day, one rep at a time.”


The user can save the redacted version of the input by using output redirection as follows:

% java Redactor Oberlin Kenyon Yeomen < football.txt > football-redacted.txt


Problem 4:  Benford Analysis

Benford's Law (also known as the "first-digit law") is an observation about the distribution of digits in numbers in data sources. In brief, in many natural datasets the first digit will be a '1' about 30% of the time with each higher digit occurring less frequently than the previous one, ending with a '9' occurring less than 5% of the time.

There is a nice graph of this distribution on the Wikipedia page: http://en.wikipedia.org/wiki/Benford's_law#Mathematical_statement

Counting first digits

For this program, you will again be reading from System.in, but you are only concerned with words that start with a numerical digit.  For each such word, you need to get the value of the starting digit.  You'll need to maintain a count of the number of words you encounter that start with the digits 0 through 9; that is, you need 10 separate counters.  The counters should be kept in an array, with the starting digit used as an index into the array.

There are a number of ways you can get at the first character, determine if it is a digit, and get the value.  Here is one approach:

  1. Get a word from your input (probably using Scanner and hasNext() / next()
  2. Use the word's charAt() method to get the first character and pass it to Character.isDigit() to determine if it is a digit.
  3. If it is, then you can use the word's substring method to extract that first digit as a String
  4. And that new String can be passed into Integer.parseInt to determine its integer value.

Processing the input

As with the previous problem, you'll be reading from System.in (probably redirected from a text file).  In this case, it's okay to read the input word by word using a single Scanner, rather than line by line.  For each word you read in, test its first character.  If it is a digit, increment one of your counters; if not, skip it and continue with the next word.  (Note:  Use the digit as an index into your array of counters.  Don't use nested if statements or a switch statement to find the right counter.)

Printing out the frequency chart

When you have finished reading System.in and made counts of all the leading digits, you should print out a histogram of the various frequencies that you encountered. You should should print out the following information for each row:

  1. The leading digit 0-9
  2. The total count of words beginning with that digit
  3. The relative frequency of that digit occurring at the start of words beginning with digit
  4. A bar of * characters representing the frequency graphically
The most frequently occurring digit should have a bar of length MAXWIDTH, which should be defined as a named constant in your class.
    public static final int MAXWIDTH = 50;

All of the other bars' lengths should be scaled proportionally to this.  So take the digit's count, divide by the max count (using floating-point division), and multiply by MAXWIDTH.  Round this number to the nearest integer using Math.round().

So if all the frequencies are about equal, you'd expect all the bars to be about 50 units wide. If they are more varied, then the longest will be 50 and the others will be of various shorter widths. Note that if the frequency is 0, the bar should have 0 '*' characters.

To print out the table in a formatted fashion, you might want to use System.out.printf. You can pass it a format string that uses %d for decimal numbers and %f for floating point numbers. You can also specify a width for each field by including a number between the % and the letter. Here is what I used in the example shown below:

    System.out.printf("%d %8d %4.1f%% : ", digit, count[digit], freq );

Sample data

I've collected a number of pieces of sample data for you to try out your Benford analysis tool on: lab1-numbers.zip

Because these are large files, and I don't want you to turn them in, they are all in a subfolder called "numbers".

This data comes from the US Census Bureau, CIA World Factbook, and a variety of other sources around the web. Try running your tool on the various files. Note in your comments for your program which ones seem to follow Benford's law and which ones don't. Feel free to speculate as to why the ones that don't are that way.

% java Benford < numbers/census-pop-est.txt
Welcome to the Benford analysis program

0 1116 0.9% : **
1 35294 29.8% : **************************************************
2 20825 17.6% : ******************************
3 14070 11.9% : ********************
4 11405 9.6% : ****************
5 9210 7.8% : *************
6 8019 6.8% : ***********
7 6809 5.7% : **********
8 6472 5.5% : *********
9 5259 4.4% : *******



Submitting your programs

Each of your programs should have a block comment at the beginning of the file containing a description of the program and the name of the author (i.e., your name).  For the Benford's law program, include your observations and analysis of the program's output on the sample files I provided.  If you adhered to the honor code in this assignment, add the following statement at the top of your Benford.java file:

I have adhered to the Honor Code in this assignment.

If there are portions of these programs that you know are not working correctly, you should indicate that in a comment section near the top of the file.

Please delete the numbers files before running handin. They total about 20MB in size and we have our own copy. Thanks!

Now, submit your programs electronically using handin.  You can use the same procedure that you used for lab 0.
    % cd          # changes to your home directory
    % cd cs151    # goes to your cs151 folder
    % handin      # starts the handin program
                            # class is 151
                            # assignment is 1
                            # file/directory is lab1

    % lshand      # should show that you've handed in something

You can also specify the options to handin from the command line

    % cd ~/cs151                 # goes to your cs151 folder
    % handin -c 151 -a 1 lab1


Last Modified: September 2018-John Donaldson, based on material from Bob Geitz, Roberto Hoyle and Ben Kuperman