This assignment is due on Thursday, February 7, 2008 at 5:00 PM.

Change Log

Introduction

The purpose of this assignment is to give you some initial experience writing Java code using basic control structures (loops, etc.) and reading data from a file.

Note
You must do this assignment in groups of 2.
Note
Assignments are structured with three levels: C, B, and A. The grading for the assignments will be done so that doing everything correctly for a particular level will result in a grade equivalent to that letter grade. The levels are also cumulative — to receive a B, you must do everything in both the C and B levels (usually, the work in each level will depend on the earlier levels).
Warning
When an assignment description tells you to give something a particular name, you must give it exactly that name. Failure to do so may result in a very low or zero score due to inability to properly run your code.
Warning
Your program must output its results in exactly the format we describe, with no additional text being written. If you insert additional output statements to aid in debugging, make sure they are removed before you submit.

Overview

Your task in this assignment is to write a program which analyzes and summarizes grade information for quizzes in a class.

File format

The data is stored in a text file called students.dat with each student's record on a separate line. Each record consists of a student ID (an integer), followed by four quiz scores (floats/doubles). A sample file looks like this:

12345 90.0 37.2 89.1 99.7
12937 100.0 95.0 100.0 97.0
93701 65.0 75.3 89.2 98.6
73920 78.3 82.1 75.0 77.0

Output

At the C level, your program will print each student's average quiz score, along with their ID, with one student per line.

At the B level, your program will print (in addition to the C-level report) the average score across all students for each quiz.

At the A level, your program will compute the student averages by dropping the lowest quiz score for each student. Additionally, it will compute the overall average (the average of the averages).

Following is a sample of the output at the A level:

12345: 92.933333
12937: 99.000000
93701: 87.700000
73920: 79.133333

STATS (min, max, avg):
Quiz 1: 65.000000, 100.000000, 83.325000
Quiz 2: 37.200000, 95.000000, 72.400000
Quiz 3: 75.000000, 100.000000, 88.325000
Quiz 4: 77.000000, 99.700000, 93.075000
Avg:    79.133333, 99.000000, 89.691667

Getting started

In Eclipse, create a new Java project. Download the following two files, and import them into your project (see the Lab 0 description for how to do this):

Once you have imported the files, create a new class in your src/ folder called GradeProcessor, and give it a public static void main method (click the corresponding checkbox in the New Class dialog).

C level

To receive a C, you must write the code to read in the data file and print out each student's average score.

The GradeReader.java file contains a class we provide, GradeReader, which will help you read the data from the file. Later, you will learn how to do the file I/O directly, but for now it hides some Java details that we haven't covered yet so you can complete this assignment in a straightforward fashion.

You need to do the following in your main method in the GradeProcessor class:

  1. Create a new variable to hold a GradeReader.

  2. Initialize this variable to hold a new GradeReader object which can read from the students.dat file.

  3. Write the code to read each record from the file, compute the average (statistical mean) of their score, and print it. It should print in the following format:

StudentID: Score

Creating new objects

In order to do anything with most classes, you must instantiate them; that is, create a new object from them. In Java, you do this with the new keyword. For example, to create a new object of class Color, you could do the following:

Color c = new Color();

The Color() part is just like a method call; you can put arguments in the parentheses. It calls a “magic” method called a constructor.

The constructor for the GradeReader class requires an argument — a string — which is the file name it will read from.

Using the GradeReader

The GradeReader class class allows you to read from a data file, one line (or record) at a time. It has a notion of a “current record”, and allows you to get data from the current record. When it is first created, it has no current record.

The advance() method of GradeReader advances the current record by 1 record. The first call to advance() makes the first record the current record. It also returns a boolean value — true if it found another record, or false if it reached the end of the file.

The getStudentID() method gets the student ID number, as an integer, from the current record. The getQuizScore(int) method takes an integer quiz number (from 1-4 inclusive) as its sole parameter and returns the student's score for that quiz. Neither of these methods can be called before advance() is called at least once, and neither of them can be called after advance() has returned false.

Note
If you violate the rules regarding calling advance() and getting record information, your program will terminate with a RuntimeException stating that the grade reader is not in a valid state.

Thus, the basic structure of code to process the records in the file looks like this (in pseudocode):

while advance() returns true
    process a record

Outputting data

Java provides an object, System.out, which lets you print data to the standard output stream (which goes to your console in Eclipse, or to the terminal from which you ran the program if you're using a command line). There are a couple methods of interest here:

print

This method prints a string or other data object.

println

This method takes a string (or other data, such as an integer) and prints it, followed by an end-of-line character.

format

This method takes a string followed by several other parameters and prints the string, after inserting the other parameters in place of certain character sequences in the initial string. It is used for nicely formatting output. See Using format for more information.

Look at the PrintStream class in the Java API reference for information on more options for outputting data.

B level

Add code to your Level C solution to compute the average score, across all students, for each quiz. After going through and printing all the student's averages, it should output a blank line followed by a set of lines like the following:

STATS:
Quiz 1: <Q1 Average>
Quiz 2: <Q2 Average>
Quiz 3: <Q3 Average>
Quiz 4: <Q4 Average>

A level

For this level, you need to add the following:

  1. Modify the computation of each student's average grade to drop their lowest grade. That is, the average is the average of the three highest grades.

  2. Compute the average of the averages, along with the average for each quiz.

  3. Compute the minimum and maximum values of each of the quizzes and the student quiz averages.

    To compute a minimum or maximum, create a variable to hold the min or max value. Initialize this variable to some very large (for minimum) or very small (for maximum) value. Since we're working with double values, the values Double.POSITIVE_INFINITY and Double.NEGATIVE_INFINITY are the greatest possible and least possible numbers, respectively. Then, in your loop, check each value against the current best minimum or maximum. If it's less than the minimum, it should be the new minimum, and the maximum case is equivalent.

  4. Modify the output to be minimum, maximum, and average (in that order, separated by “, ”). Modify the output of the “STATS:” line to say “STATS (min, max, avg):”.

Note
The average of averages and min/max of averages are the average, min, and max of the students' quiz averages. The goal is to compute the minimum, maximum, and averages of the final overall quiz scores that the students received.

Submitting your assignment

Before you submit your assignment, you must create a text file called group.txt in your project directory. In this file, put the names and x.500 ID's of the members of your group.

Copy your code and other files (group.txt, students.dat, build.xml) to an ITLabs computer for final testing. On the ITLabs computer, run ant run in your code's directory and make sure the program works. Then run ant package to create the HW package, and submit the resulting hw1.tgz file via Submit.

Extra credit

For a small amount of extra credit, you can modify your program to also compute the median and mode of each of the quiz scores. If you do the extra credit, submit it as the assignment hw1-extra (and still submit your A-level solution as hw1).

Note
You may only attempt to get the extra credit if you also submit an A-level solution.

Using format

The format method of the PrintStream class allows you to format output by having Java substitute various values for string sequences in a template (called a “format string”). The first parameter to `format' is always a string, the format string. The data that is to be substituted in to the format string is passed as the remaining parameters.

The format string contains special codes beginning with the “%” character to indicate substitutions. Some important ones are “%s”, which tells Java to insert a string, “%d” for decimal integers, and “%f” for floating-point (float or double) numbers. If you want to include a literal “%” sign in the output, use “%%”.

Each of the “%” sequences that inserts a value takes a parameter. The parameters are used from left to right. For example, the following call:

System.out.format("The square root of %d is %f\n", 5, 2.236068);

results in the following output:

The square root of 5 is 2.236068

format does not automatically generate a new line at the end of the string; the “\n” sequence indicates the newline character and causes the new line to be printed.