This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Programming Assignments

2-week Assignments

4 programming assignments will be assigned during the semester. Note that their due dates are subject to change.

  1. Programming Assignment 1 - Due: 10/22 11:00PM (Extended to 10/25 11:00PM) (I/O and Specialization)
  2. Programming Assignment 2 - Due: 11/5 11:00PM (Interfaces, Abstract Classes, and Polymorphism)
  3. Programming Assignment 3 - Due: 11/19 11:00PM (Extended to 11/26 11:00PM) (Recursion)
  4. Programming Assignment 4 - Due: 12/10 11:00PM (Collections)

1 - PA4: BatchGeo

Programming Assignment 4

BatchGeo

Learning Objectives

This assignment is designed to help you learn several things. First, it will help you learn how to use type-safe collections. Second, it will help you learn about the capabilities of different kinds of collections (and when each is appropriate). Third, it will help you learn more about file I/O. Finally, it well help you understand the importance of testing and debugging.

Overview

Nearby is a (fictitious) company that develops software in three closely related areas: personal navigation systems, en-route and mobile commerce, and location-based services. You have been contracted to develop the classes they will need to complete an application named BatchGeo.

BatchGeo is an application that can be used to geocode street addresses (i.e., convert street addresses to longitude/latitude coordinates).

Background

Before you can start implementing the system, you need to learn a little bit about the terminology and file formats used by Nearby.

Acronyms

TIGER
Topologically Integrated Geographic Encoding and Referencing

Definitions

Address
A street name and a house/lot number.
Equator
The imaginary line on the surface of and encircling the Earth that is equidistant to the North and South Poles.
High End of the Segment
The end of the segment with the largest house/lot number
House/Lot Number
A number (for our purposes, an integer) ascribed to a particular location (often a vacant lot, house, or business) on a segment.
Interpolation Parameter for a House Number
Given a low house number, L, a high house number, H, and a house number of interest, A, in [L,H], the interpolation parameter for A is defined as m=(A-L)/(H-L), where the house numbers are treated like real numbers (not integers).
Latitude
The angular distance (in degrees) north (positive) or south (negative) of the Equator.
Line of Latitude (Parallel)
An imaginary line on the surface of and encircling the Earth drawn parallel to the Equator.
Line of Longitude (Meridian)
An imaginary great circle on the surface of the Earth connecting the North and South Poles and perpendicular to the Equator.
Linear Interpolation of Two Numbers
Given two numbers, a and b, and an interpolation parameter, m ∈ [0,1], the linear interpolation of a and b is denoted by v and defined as v=(1-m) ⋅ a + mb.
Linear Interpolation of Two Points
Given two points, a = < ax, ay > and b = < bx, by >, and an interpolation parameter, m ∈ [0,1], the linear interpolation of a and b is denoted by v and defined as v = < vx, vy > where vx=(1-m) ⋅ ax + mbx and vy=(1-m) ⋅ ay + mby .
Location
A point in which the coordinates are a longitude and latitude.
Longitude
The angular distance (in degrees) east (negative) or west (positive) of the Prime (Greenwich) Meridian.
Low End of the Segment
The end of the segment with the smallest house/lot number.
Point
A (2-dimensional) point is an ordered pair. The point a is typically written as the ordered pair < ax, ay >
Prime (Greenwich) Meridian
The line of longitude designated to be at 0 degrees.
Segment
A portion of a street. For example, Main Street might consist of several segments, one from Oak Street to Elm Street, one from Elm Street to Pine Street, and one from Pine Street to Broad Street. A segment has a low end house/lot number and high end house/lot number.
Segment Base
A “database” (i.e., group or collection) containing all of the segments of interest.
Street
A named roadway that consists of one or more segments (that define the street). For example, Main Street might consist of several segments, one from Oak Street to Elm Street, one from Elm Street to Pine Street, and one from Pine Street to Broad Street. A street has a name (e.g., “Main Street”).
Street Base
A “database” (i.e., group or collection) containing all of the streets of interest.

Data Files

The data files used in BatchGeo are “human readable” text files. Each line in a data file is called a record, and each record may contain one or more fields (which are, conceptually, columns or components of the record). Fields in a record are separated by a delimiter character.

BatchGeo currently uses two kinds of data files, .seg files and .str files, each of which is described below. A geographic region will consist of two files that have the same name and these two extensions. So, for example, the data files for the JMU area are named jmuarea.seg and jmuarea.str.

.seg Files

.seg files contain information about segments, as they are defined by the U.S. Census Bureau’s TIGER system (though using a slightly different format).

The Format of .seg Files
  • Records in .seg files use the tab character (i.e., '\t') as the delimiter

  • .seg files contain a variable number of records

  • .seg files are terminated by an end-of-stream (sometimes called end-of-file) character

  • Each record contains nine fields as follows:

  1. The segment ID (String)
  2. The longitude at the low end of the segment (double)
  3. The latitude at the low end of the segment (double)
  4. The longitude at the high end of the segment (double)
  5. The latitude at the high end of the segment (double)
  6. The length in KM (double)
  7. The TIGER road type code (String)
  8. The house/lot number at the low end of the segment (int)
  9. The house/lot number at the high end of the segment (int)
An Example .seg File Containing Seven Segments
Example .seg File
A Description of One Record in a .seg File
Description of a .seg Record

.str Files

.str files contain information about streets.

The Format of .str Files
  • Records in .str files use the tab character (i.e., '\t') as the delimiter (Note: A tab character is used because street names can contain commas)

  • .str files contain a variable number of records

  • .str files are terminated by an end-of-stream (sometimes called an end-of-file) character

  • .str files contain two kinds of records, name records and component records

  • Each name record contains two fields as follows:

    1. The street name (String)
    2. The number of segments in the street (int)
  • Each component record contains one field, the segment ID (String)

An Example .str File Containing Four Streets
Example .str File
A Description of One Street in a .str File
Description of a .str Street

A Geocoding Example

Using the example data files above, we can geocode the address 1970 Creek Ct (which consists of the int house number 1970 and the street name "Creek Ct").

From the .str file we see that Creek Ct consists of a single segment with ID 75739596. From the .seg file we see that the low end number on this segment is 1900 and the high end number on this segment is 1999. So, treating the house numbers as double values (not int values), the interpolation parameter for house/lot number 1970 is given by: m = (1970 - 1900) / (1999 - 1900) = 70/99 ≈ 0.707070

From the .seg file we see that the low end location is <-78.737162, +38.380782> and the high end location is <-78.736349, +38.381549>. Using m to interpolate between these two points yields:

(1.0 - 0.707070) · -78.73716 + 0.707070 · -78.736349

= 0.292930 · -78.73716 + 0.707070 · -78.736349

= -23.064476 + -55.672110

= -78.736586

and

(1.0 - 0.707070) · 38.380782 + 0.707070 · -38.381549

= 0.292930 · 38.380782 + 0.707070 · 38.381549

= 11.242882 + 27.138442

= 38.381324

So, 1970 Creek Ct is geocoded to <-78.736586, 38.381324>, where, using the Nearby convention, the longitude is listed before the latitude.

Note that, in this example, the interpolation parameter was truncated at 0.707070. So, you may get slightly different answers if you use more digits of accuracy. Your code must use the full accuracy of double values.

The Components to be Written

The components to be written are illustrated in black in the following UML class diagram. (The components in jade green are part of the Java API.)

Class Diagram

Note that attributes and methods that are inherited are not made explicit in this diagram. If a method appears in both a base class and a derived class it means that the method in the derived class overrides the method in the base class. Note also that methods that are in an interface are not made explicit in classes that realize/implement that interface.

In addition to the specifications in the UML class diagram, your classes must conform to the following specifications.

The Location Class

The toString() method must return the longitude and latitude formatted using a format String of "%+9.6f,%+9.6f".

The OnSegmentLocation Class

An OnSegmentLocation is a Location that knows the ID of the Segment it is on.

This class implements the Comparable interface so that the sort() method in the Collections class can be used to sort collections of such objects based on their segment IDs (which are String objects that, themselves, implement the Comparable interface).

The Segment Class

The default constructor must create a Segment object with default values for all of the attributes.

The contains() method must return true if the owning Segment contains the given house number, and must return false otherwise.

The interpolate() method must geocode the given house number using linear interpolation. (Hint: Be careful to use the longitude/latitude for the low end of the segment as a and the longitude/latitude of the high end of the segemnt as b.) It must return null if the Segment does not contain the house/lot number.

the fromTSV() method must set the value of all of the attributes from a tab-separated-value representation (as in .seg files). It may need to throw one or more exceptions (e.g., if the String has the wrong number of fields, if a numeric field is non-numeric, etc.). It must return the ID of the segment.

The Street Class

The constructor is passed the name of the Street and must allocate memory for the segments attribute.

The add() method must add the given Segment object to the segments attribute.

The geocode() method must return a List of OnSegmentLocation objects that contain the house number of interest. This List need not be ordered in any particular way. The returned List may be empty but this method must not return null. (Hint: This method should use the interpolate() method in the Segment class.)

The MapReader Class

The readSegments() method must read a collection of Segment objects from a .seg file. Any records in the .seg file that are incorrectly formatted (e.g., contain the wrong number of fields, or contain non-numeric values for fields that must be numeric) must be ignored. The Map that is returned must use the ID of the Segment as they key. (Hint: The readLine() method in the BufferedReader class will return null when the end-of-stream/end-of-file character has been reached. The Scanner class has hasNext() and hasNextLine() methods that can be used to determine if the end-of-stream/end-of-file character has been reached.)

The readStreets() method must read a collection of Street objects from a .str file, using the collection of Segment objects that it is passed. The Map that is returned must use the name of the Street as the key.

The Geocoder Class

The Constructor

The constructor will be passed the name (with no extension) of the .seg and .str files to use (with no path information, meaning the file can be found in the working directory). So, for example, for the JMU area this method will be passed the String "jmuarea" (not "jmuarea.seg" or "jmuarea.str", and not "/cs159/eclipse/pa4/src/testing/jmuarea").

The constructor must use the MapReader class to read the .seg and .str files (from the working directory) and store the information they contain in the Map attribute named streets. Your implementation must not read either data file more than once per execution. If it does, you will receive a grade of 0. In other words, your implementation must read the file once (essentially at the start of the execution), store all of the information needed in the Map named streets, and then use that Map to geocode the addresses entered by the user. (Hint: There is no reason to keep the segments after the constructor returns. They are only needed to read the streets.)

The fromAddress(String name, int number) Method

The fromAddress() method is passed an address (i.e., a street name and a house/lot number) to geocode. The String parameter will contain the street name. The int parameter will contain the house/lot number on the street.

The fromAddress() method must return a List of OnSegmentLocation objects that contains all of the longitude/latitude pairs that correspond to the given address (and nothing else).

  1. If the address can’t be geocoded, the List must contain no elements (but must be non-null).

  2. If the address can be geocoded, the calculated longitude and latitude must be a linear interpolation of the longitudes and latitudes at the low and high end of the relevant segment. If the address can be geocoded using more than one segment (i.e., there is more than one segment with the given street name that contains the given house/lot number), the List must be sorted in ascending order by segment ID. (Hint: This method should use the geocode() method in the Street class.)

Testing

Nearby has provided information for two areas that you can use for testing, each of which consists of two files. They are available for download from the following URLs:

and

You must put these files in the project directory so that your Gecoder will find them in the working directory when the code is executed. (See the section on “Help with Data Files” below.)

Obviously, for all of your tests, you will need a way to calculate the expected results (so that you can compare them with the actual results). While you can use a calculator for this purpose, it’s probably better to use a spreadsheet. Nearby has provided one that is available for download at:

tiny.xls

It contains one row for each segment in the tiny map. If you enter an address in the appropriate row of the “Address” column, it will calculate the interpolation parameter for that address, as well as the longitude and latitude for that address. For example, entering the address 1970 in cell L5 will yield the same results (in cell N5, O5 and P5) as in the example above.

Unit Testing

You should by now realize that you should test individual components before testing the entire system. Hence, you should write JUnit tests for all of the classes your write as you complete them (or as you complete indiviual methods in them). However, you are not required to do so. In other words, you will not be submitting your tests, you should write them because you know that doing so is part of a good process.

Nearby has provided a few unit tests to help you get started. They are available for download at:

These tests may need to be modified/corrected to be useful, and certainly need to be expanded.

Note that it may not be possible to completely cover all of the statements in the classes your write because it may not be possible to generate all of the exceptions that might be thrown. Nonetheless, you should try to cover as much of the code as possible.

Integration Testing

After you are confident that all of the methods in all of your classes pass your unit tests, you should perform integration testing (in which you ensure that they all work correctly together). You should do this by creating JUnit tests for the Geocoder class (which, directly or indirectly, uses all of the other classes). Note that there is no main class included in this assignment. So, if you do not want to use JUnit for integration testing, you will need to design and write a main class on your own. Regardless, make sure you use an appropriate tolerance when comparing double values.

Submission

You must submit (using Gradescope) a .zip file named pa4.zip that contains:

  1. Your implementation of all of the classes

packaged appropriately. The analytics and geog directories/folders must be at the top of the .zip file. (See the first programming assignment if you have forgotten how to do this.) Do not submit your JUnit tests and do not submit any data files.

Your grade will be reduced by 5 points for each submission after the 10th submission. So, you should try to ensure that your code is correct before you submit it the first time.

Grading

Your code will first be graded by Gradescope and then by the Professor. The grade you receive from Gradescope is the maximum grade that you can receive on the assignment

Gradescope Grading

Your code must compile (in Gradescope, this will be indicated in the section on “Does your code compile?”) and all class names and method signatures must comply with the specifications (in Gradescope, this will be indicated in the section on “Do your class names, method signatures, etc. comply with the specifications?”) for you to receive any points on this assignment. Gradescope will then grade your submission as follows:

CriterionPointsDetails
Conformance to the Style Guide0All or Nothing; Success Required
Correctness100Partial Credit Possible

As discussed above, 5 points will be deducted for every submission after the 10th. Gradescope will provide you with hints, but may not completely identify the defects in your submission.

Manual Grading

After the due date, the Professor may manually review your code. At this time, points may be deducted for duplicate code, inelegant code, inappropriate variable names, bad comments, etc.

At this point in the semester, you should be able to create a good process and use it. You should probably think about which classes use which other classes and work from the bottom up. In other words, start with the classes that stand alone (the bottom), then move up to the classes that use them, and keep moving up until you get to the Geocoder class.

Help

You might find the following discussions helpful.

Help with Data Files

You should download the data files into the downloads directory/folder that you created for this course.

After you have downloaded the data files you must open a file explorer or finder, select all of the files, and drag them into Eclipse. Specifically, you must drag them into the project (not the src directory/folder or anything underneath it). When you do so, make sure you select “Copy files” not “Link to files”. (It is possible to put the data files elsewhere, but then, when you submit your solution, your code will not be able to find them on the Gradescope server. In other words, for your code to work both on your computer and on Gradescope, the data files must be dragged into the Eclipse project.)

Then, in your code that needs to use these files, you must use only the file name and extension (i.e., do not include a path). For example, you might construct a BufferedReader named in as follows:

BufferedReader in;
in = new BufferedReader(new FileReader("tiny.seg"));

All of the data files will be available on Gradescope for you to use in your tests (assuming you follow the instructions above).

Help with Testing

The jmuarea files are about 3Mb in total, which means that it will be very difficult for you to debug your code using them. Hence, you should use the smaller tiny files for initial testing and debugging. These files contain four streets, two with one segment each and two with multiple segments.

Even with the small files, you will need to be systematic in the tests you use. Think carefully about the kinds of faults your implementation might contain and the kinds of trigger conditions that might allow you to detect them. Some important addresses to geocode are addresses at the low and high ends of the segment which need not be interpolated (i.e., will have interpolation parameters of 0 and 1 respectively), and addresses that are in the interior of the segment and must be interpolated (i.e., will have an interpolation parameter between 0 and 1).

For tiny.str and tiny.seg you should certainly start with the following test inputs. Of course, you’ll first need to calculate the expected answer for each of these inputs.

Addresses at Ends of Segments (i.e., No Interpolation Required)

  • 748 Milk Spring Rd
  • 798 Milk Spring Rd
  • 674 Milk Spring Rd
  • 746 Milk Spring Rd
  • 1900 Creek Ct
  • 1999 Creek Ct
  • 1 Creek Loop
  • 246 Creek Loop
  • 387 Hill Dr
  • 150 Hill Dr

Addresses in the Interior of Segments (i.e., Must Be Interpolated)

  • 750 Milk Spring Rd
  • 701 Milk Spring Rd
  • 1935 Creek Ct
  • 200 Creek Loop
  • 155 Hill Dr
  • 380 Hill Dr

No Such Street

  • 747 Buttermilk Spring Rd
  • 1 Creekside Ct
  • 700 Spring Rd
  • -1 Hilliard Dr

No Such Number

  • 800 Milk Spring Rd
  • 1750 Creek Ct
  • -1 Hill Dr

Multiple “Hits” (i.e., Segments Containing the Address) Involving Addresses at the End and in the Interior

  • 165 Hill Dr
  • 303 Hill Dr
  • 305 Hill Dr
  • 359 Hill Dr

Multiple “Hits” Involving Addresses in the Interior

  • 177 Hill Dr
  • 351 Hill Dr

Questions to Think About

You don’t have to submit your answers to these questions, but you should try to answer them before you start writing the code because they will help you understand how to do so.

  1. Why is the streets attribute in the Geocoder class a Map<String,Street> rather than some other kind of collection?
  1. Why is the segments attribute in the Street class a List<Segment> rather than some other kind of collection?
  1. Why does the readSegments() method in the MapReader class return a Map<String,Segment> rather than some other kind of collection?
  1. Can a defect in a test (e.g., an incorrect expected value, an inappropriate tolerance) make you think code is correct when it isnt?

  2. What should you do when your code fails an integration tests after passing your unit tests?

2 - PA3: FoneDrone

Programming Assignment 3

FoneDrone

Learning Objectives

This homework/programming assignment is designed to help you learn about recursion. It is also designed to help you think about what it means for code to be correct, and why programmers shouldn’t be satisfied with code that is “almost correct”.

Overview

Old people, like one of the professors teaching CS159 this semester, have a tendency to lose their cell phones (and to have problems with their beepers, fax machines, and land-line phones). While there are currently tools that help people find lost phones, they seem to be beyond the capabilities of old people. This has led to the development of FoneDrone, an “intelligent” drone that can fly around inside of a building and find cell phones.

The drone itself uses short range transmitters/receivers (e.g., bluetooth or near-field communications) to identify phones. Hence, the drone must be directly over a phone to identify it.

The people that developed the FoneDrone hardware have little or no experience developing software, so they have contracted with you to develop the “intelligence” for FoneDrone.

Background

Rather than have you work with an actual drone, you have been provided with a drone simulator and several simulated rooms. The simulation is in the following .jar file (that contains .class files only, no .java files):

and the simulated rooms (that are used by the simulation) are in the following “human-readable” text files:

You should download all of these files into the downloads directory/folder that you created for this course.

The simulator consists of one enum, Direction, and two classes, Drone and DroneController. You must write the FoneDroneController class. The capabilities of these components and the relationships between them are illustrated in the following UML class diagram.

Class Diagram

Specifications for the FoneDroneController Class

In addition to the specifications in the UML class diagram, your implementation of the FoneDroneController class must conform to the following specifications.

  1. You may add private attributes and methods to the FoneDroneController class as needed.

  2. The explicit value constructor in the FoneDroneController class is passed the phone number to look for.

  3. The drone need not search every location (i.e., it may stop searching when it has found the phone it is looking for), but it may.

  4. The drone starts (i.e., is “powered on”) at a particular location. When it is done searching, it must return to that location.

  5. When the drone first searches a particular location it should check to see if the desired phone is at that location. This can be accomplished by having the FoneDroneController invoke the drone object’s checkForPhone() method (which returns the location as an int[] if the phone is at that location, or null if the phone is not at that location). The FoneDroneController should keep track of the location of the phone in its location attribute (and return it when the getLocationOfPhone() method is invoked).

  6. The getLocationOfPhone() is a simple accessor. It must return the location attribute, it should not do the work of finding the phone. The work of finding the phone should be done in the start() method or a private method that is invoked by the start() method.

Testing

You may use the following main class to test your code:


package app;

import java.lang.reflect.InvocationTargetException;
import javax.swing.SwingUtilities;

import controller.*;
import simulator.*;

/**
 * A driver for running FoneDroneController.
 */
public class FoneDrone {

	/**
	 * The entry-point of the application.
	 * 
	 * @param args The command line arguments (which are ignored)
	 * @throws InterruptedException If something goes wrong with the GUI
	 * @throws InvocationTargetException If something goes wrong with the GUI
	 */
	public static void main(String[] args) throws InterruptedException, 
		InvocationTargetException {
		
		Drone drone;
		FoneDroneController controller;

		controller = new FoneDroneController("540-568-1671");
		drone = new Drone(controller, "halls.txt");
		controller.setDrone(drone);
		SwingUtilities.invokeAndWait(drone);
	}

}

It constructs a Drone (for a particular room) and a FoneDroneController and makes them aware of each other.

When running, the drone simulator looks something like the following (for the file named "halls.txt"):

Example

The black areas indicate walls (or other places where the drone can’t go), the gray areas indicate rooms (or other places where the drone can go), the white areas indicate locations that have already been searched, and the * indicates the drone.

Since you are viewing the simulator from above and the drone does not change its orientation, Direction.FORWARD is always toward the top of the window, Direction.BACKWARD is always toward the bottom of the window, Direction.RIGHT is always toward the right of the window, and Direction.LEFT is always toward the left of the window.

For testing and debugging purposes:

  1. You can control the speed of the drone using the slider at the bottom of the window. You can change the speed before the simulation starts and while it is running. The smaller the delay (in milliseconds) between moves, the faster the drone travels.

  2. You can start the drone by clicking on [Drone] and pulling down to [Start]. This causes the FoneDroneController object’s start() method to be invoked.

  3. After the FoneDroneController object’s start() method returns, its getLocationOfPhone() method is invoked, and the result is displayed in the console. (Note: This is where the Drone thinks it found the phone; the Drone may not be correct.) Also, information about the drone’s final location is displayed in the console.

  4. You should have the Drone search for Prof. Bernstein’s, Prof. Mayfield’s and Prof. Stewart’s phones (they all have been known to leave them behind) in all three rooms. Prof. Duan’s phone number has changed since the simulator was created, so her current phone number shouldn’t be found. (You can find all of their phone numbers in the JMU Directory ). You should also have the Drone search for your phone in all three rooms (which it shouldn’t find).

Submission

You must submit (using Gradescope) a .zip file named pa3.zip that contains:

  1. FoneDroneController.java

packaged appropriately. The controller directory/folder must be at the top of the .zip file. (See the first programming assignment if you have forgotten how to do this.)

Do not submit any other classes (including any unit tests).

Your grade will be reduced by 5 points for each submission after the 10th submission. So, you should try to ensure that your code is correct before you submit it the first time.

Grading

Your code will first be graded by Gradescope and then by the Professor. The grade you receive from Gradescope is the maximum grade that you can receive on the assignment

Gradescope Grading

Your code must compile (in Gradescope, this will be indicated in the section on “Does your code compile?”) and all class names and method signatures must comply with the specifications (in Gradescope, this will be indicated in the section on “Do your class names, method signatures, etc. comply with the specifications?”) for you to receive any points on this assignment. Gradescope will then grade your submission as follows:

CriterionPointsDetails
Conformance to the Style Guide0Success Required
Correctness100 pointsAll or Nothing

In other words, your code is either correct (i.e., the Drone finds all of the lost phones and doesn’t find any phones that aren’t lost) or it isn’t.

As discussed above, your grade will be reduced by 5 points for each submission after the 10th submission.

Manual Grading

After the due date, the Professor may manually review your code. At this time, points may be deducted for inelegant code, inappropriate variable names, bad comments, etc. Points may also be deducted for using randomization to choose directions.

If your solution is not recursive (in a meaningful way), you will receive a grade of 0.

Help

You should carefully consider all of the following topics before starting.

Help with Data Files

As discussed above, you should download the data files into the downloads directory/folder that you created for this course.

After you have downloaded the data files you must open a file explorer or finder, select all of the files, and drag them into the Eclipse graphical user interface. Specifically, you must drag them into the project (not the src directory/folder or anything underneath it). When you do so, make sure you select “Copy files” not “Link to files”. Then, when you construct a Drone, you must use only the file name (i.e., do not include a path) as in the example above.

You do not need to read these files, they are read by the simulation. You just need to tell the Drone which file to use.

Help Using .jar Files

As discussed above, you should download the .jar file into the downloads directory/folder that you created for this course.

Help incoroprating .jar files into an Eclipse project is available on the CS Wiki .

Help Allocating Time

Almost all of your time on this assignment should be spent thinking; very little time should be spent typing/compiling/etc. Indeed, the recursive method in the FoneDroneController class may contain as few as 20 lines of code.

Though it may have worked for you in the past, it is very unlikely that you will discover an algorithm that solves this problem using trial and error (i.e., trying something, compiling, testing, making a change, and repeating). You will need to think carefully about how to solve problems recursively in general, and how recursive thinking can be used to solve this problem in particular.

Help with Class Design

The start() method in your FoneDroneController class should not contain all of the control logic. It should call other methods (that you will need to write), at least one of which must be recursive.

Help Getting Started

The people who developed FoneDrone originally contracted with students at another university in Virginia to develop the “intelligence”. They didn’t understand recursion and so were only able to develop a FoneDroneController that could search forward (in a stright line) from the Drone object’s original position. (We won’t mention which university so as not to embarass them.) The people who developed FoneDrone have provided you with this FoneDroneController in case it will help you get started (and help you understand what not to do). (Remember to edit the comments after you make changes.)

package controller;

import simulator.*;

/**
 * INCORRECT control logic for the PhoneDrone.
 *
 * @author A team of "hoakey" programmers at an un-named university in VA.
 * @version 1.0
 */
public class FoneDroneController extends DroneController {

    private int[] location;

    /**
     * Explicit Value Constructor.
     *
     * @param number The phone number to look for
     */
    public FoneDroneController(String number) {
        super(number);
        this.location = null;
    }

    /**
     * Get the location of the phone (or null if it hasn't been found).
     * 
     * @return The location of the phone (or null)
     */
    public int[] getLocationOfPhone() {
        return location;
    }

    /**
     * Start the FoneDrone.
     */
    @Override
    public void start() {
        search();
    }

    /**
     * Search for the phone.
     *
     * This method should be recursive but we couldn't figure
     * out how to do that. So, we did this instead. It's
     * close to correct because it does find the phone
     * sometimes. As a result, we think we should get at
     * least partial payment. In fact, because of the amount of
     * effort we devoted to it, we really think that we
     * deserve full payment.
     */
    private void search() {
        while (drone.canMove(Direction.FORWARD) && (location == null)) {
            drone.move(Direction.FORWARD);
            location = drone.checkForPhone(number);
        }

        while (drone.canMove(Direction.BACKWARD)) {
            drone.move(Direction.BACKWARD);
        }
    }
}

Help Writing a Recursive Algorithm

Remember that there are two parts of a recursive algorithm:

  1. The part of the algorithm that handles the “easy” case.

  2. The part of the algorithm that refines “difficult” cases.

The first thing to think about is how to define the “easy” case for this problem. To do so, suppose the drone is at a particular location and is told to search. When, in terms of the data (i.e., its location in the room, ignoring the location of the phone), is its job really easy?

After you have identified the “easy” case, think about how you can move the “difficult” cases (in terms of the data) to the “easy” case. In other words, how can you make progress (i.e., make the current situation “easier”) by calling methods in the Drone class like move(), canMove(), and hasBeen().

If you have trouble answering either of these questions after thinking about them for a few hours, ask your Professor for help (but make sure that you have evidence that you have thought seriously about answering these questions before you ask for help).

Thinking About Other Recursive Algorithms

Thinking about other recursive algorithms may help you write this one.

Finding the Factorial of n

The base case is when n is 1 (or 0) since all you have to do in this case is return the value 1. Refinement involves moving from the hard case toward the easy case (adjusting the answer accordingly). So, refinement involves reducing the value by 1.

Finding the Size of a Directory/Folder

A directory/folder can contain files and other directories/folders. The base case is when we you are examining a file since all you have to do in this case is return its size. Refinement involves moving from the hard case toward the easy case (adjusting the answer accordingly). So, refinement involves entering each directory/folder.

Questions to Think About

You don’t have to submit your answers to these questions, but you should try to answer them because they will help you determine whether or not you understand some of the important concepts covered in this assignment.

  1. If your FoneDroneController works correctly and your phone is not found at a particular location, do you need to search at that location again? (You can assume that your phone does not move.)

  2. If your FoneDroneController works “sometimes” and your phone is not found at a particular location, have you learned anything?

  3. If the software in the air traffic control system works correctly and assures a pilot that there are no planes on the runway that they have been directed to, can the pilot land confidently?

  4. If the software in the air traffic control system works “sometimes”, can a pilot ever land confidently?

  5. Would you fly on an airplane if the software in the air traffic control system and the software in the plane’s avionics system work “sometimes”?

  6. Would you complain if Canvas contained defects that led it to read and write grade files incorrectly every time it did so? Suppose it only read and wrote grade files incorrectly “sometimes”?

3 - PA2: Big Box Bargains

Programming Assignment 2

Big Box Bargains

Learning Objectives

This programming assignment is designed to help you learn several things. First, it will help you learn about interfaces and abstract classes, and improve your understanding of specialization. Second it will help you learn about polymorphism and dynamic binding. Third, it will help you learn about static binding. Finally, it will help reinforce your understanding of I/O, packages, and unit testing.

Overview

Big Box Bargains (BBB), a new “big box” store that hopes to compete with stores like Costco and Sam’s Club, has contracted with you to write some of the software they need for their checkout system.

The Components to be Written

You must write the Account and VIPAccount classes that encapsulate membership information that is specific to BBB, as well as some general purpose components for performing input/output operations on comma-separated-value (CSV) files. The relationship between these components is illustrated in the following UML class diagram.

Class Diagram

Note that methods in a class that are “concrete” implementations of abstract methods (that are listed either in an interface or an abstract class) are not explicitly listed in the class (e.g., the toCSV() method in the Account class). Method in a derived class that override a method in a base class are explicitly listed in the derived class (e.g., the toCSV() method in the VIPAccount class).

The CSVRepresentable Interface

The CSVRepresentable interface describes the capabilities of objects that can be represented in simplified CSV format (i.e., all of the fields are delimited by commas, the fields are assumed to not contain commas, and there are no column headers). The toCSV() method says that such an object must be able to create a String representation of its attributes in simplified CSV format. The fromCSV() method, on the other hand, says that such an object must be able to initialize its attributes from a String representation in simplified CSV format.

Obviously, the fromCSV() method must tokenize the String that it is passed (that has a comma as the delimiter between tokens). In principle, this can be done in many ways, but you must choose between two. Specifically, you must use either a Scanner or a StringTokenizer (both of which are in the java.util package) for this purpose. The fromCSV() method returns the object used for tokenizing the String so that it may be used to tokenize any remaining tokens in the String. In other words, the String representation may contain more tokens than the fromCSV() method uses, so it must return the object used for tokenzing in case these tokens need to be used elsewhere.

The FileIdentifier Class

The FileIdentifier class encapsulates the “classic” two-part approach to identifying files. In this “classic” approach, a file identifier consists of a name (the portion to the left of the dot) and an extension or type (the portion to the right of the dot). So, for example, one might identify the file named Student.java using a FileIdentifier that has a name attribute of "Student" and an extension attribute of "java".

This class implements/realizes the CSVRepresentable interface because it is common to include FileIdentifier objects in CSV files.

The toString() method must return the name and extension formatted using the format String "%s.%s".

The FileProcessor Class

The FileProcessor class is an abstract encapsulation of an object that can read from and write to the file system in a line-oriented way. The first line of any file it reads or writes must contain the number of lines in the file.

This class supports encryption and decryption, but those capabilities must be provided by derived classes. In addition to the specifications contained in the UML class diagram, this class must conform to the following specifications.

  1. The readLines() method must first read the number of lines in the file. It must then read the subsequent lines, decrypt them, and return a String[] array that contains the decrypted lines.

  2. The writeLines() method must first write the length of the parameter named lines (on a line of its own). It must then encrypt the elements and write them to the file (one element per line).

The CSVFileProcessor Class

The CSVFileProcessor class is a concrete specialization of the FileProcessor class. In addition to the specifications contained in the UML class diagram, this class must conform to the following specifications.

  1. The decrypt() and encrypt() methods must return the parameters they are passed unchanged. In other words, CSV files must not be encrypted.

  2. The write() method must create a CSV representation of the objects it is passed and write all of them to the appropriate file (that is passed to the constructor), one per line.

  3. The read() method must read all of the records from the appropriate file (that is passed to the constructor) and initialize the attributes of the objects that it is passed. It must assume that it is passed an array of objects that has the same number of elements as there are records (one per line) in the file. (Note: This method does not return the elements it reads. Instead, it sets the attributes of each CSVRepresentable object it is passed, using that CSVReprentable object’s fromCSV() method.)

  4. The write() and read() methods must not duplicate any code in the FileProcessor class or in the class of the CSVRepresentable objects that it is passed.

The Account Class

The Account class is an encapsulation of a membership account at BBB. In addition to the specifications contained in the UML class diagram, this class must conform to the following specifications.

  1. The purchases attribute must be used to keep track of the total purchases made by the member (measured in dollars), and the creditsUsed attribute must be used to keep track of the total credits used by the member (measured in dollars).

  2. The default constructor must initialize both attributes to 0.00.

  3. The availableCredit() method must return the available credit, which is based on a percentage (obtained from getRewardPercentage()) of the purchases attribute minus the credits used to date. So, for example, if purchases is 2000.00, getRewardsPercentage() returns 0.01, and creditsUsed is 5.00, then this method must return 15.00. Note that the value returned must never be less than 0.00. So, for example, if purchases is 2000.00, getRewardsPercentage() returns 0.01, and creditsUsed is 25.00, then this method must return 0.00.

  4. An Account holder can use the express line when the total purchases made by the member is greater than 1000.00.

  5. The getRewardPercentage() method must return 0.01 (i.e., 1 percent) for Account holders.

  6. The increaseCreditsUsed() method must increase the creditsUsed attribute by the given amount. It must never decrease the creditsUsed attribute (i.e., it must do nothing when the parameter is negative).

  7. The increasePurchases() method must increase the purchases attribute by the given amount. It must never decrease the purchases attribute (i.e., it must do nothing when the parameter is negative).

  8. The purchase() method must process a purchase of the given amount (when it is greater than 0.00), using as many credits as are available when the applyCredits parameter is true (in which case it must invoke the increaseCreditsUsed() method, passing it the appropriate value). It must invoke the increasePurchases() method passing it the amount due (i.e., the amount of the purchase less any credits that are used), and must return the amount due. For example, if passed 100.00 and true when the Account holder has 20.00 credits available, it must pass 20.00 to increaseCreditsUsed(), pass 80.00 to increasePurchases() and must return 80.00. The amount due must never be less than 0.00, but can be 0.00 (when enough credits are available). The credits used must never be greater than the purchase.

  9. The toCSV() method must return a String representation of the purchases and credits used, formatted using a format String of "%.2f,%.2f".

  10. The fromCSV() method must set the attributes of the owning object. It may assume that the String it is passed was created by the toCSV() method and must not do any error checking.

  11. The toString() method must use return a String representation of the purchases, credits used, and available credit, formatted using a format String of "Purchases: %.2f\nCredits Used: %.2f\nCredits available: %.2f".

The VIPAccount Class

The VIPAccount class is an encapsulation of an exclusive membership account at BBB. (“VIP” is an acronym for “very important person”.) In addition to the specifications contained in the UML class diagram, this class must conform to the following specifications.

  1. The visits attribute must keep track of the number of visits to BBB in which the member made a purchase.

  2. The default constructor must initialize all attributes to 0.00.

  3. A VIPAccount holder can use the express line whenever an Account holder can. A VIPAccount holder can also use the express line when they have 10 or more visits.

  4. A VIPAccount holder has the same starting reward percentage as an Account holder, however, it can increase. Specifically, for every ten visits, a VIPAccount holder’s reward percentage increases by 0.01 up to a maximum of 0.15 (i.e., it can bever be larger than 15 percent). For example, a VIPAccount holder who has made 26 visits will have a reward percentage of 0.03 (i.e., 0.01 + 0.02) and a VIPAccount holder who has made 371 visits will have a reward percentage of 0.15.

  5. Each time the increasePurchases() method is invoked, it must increase the number of visits by 1. Of course, it must also increase the purchases attribute in the base class.

  6. The toCSV() must return a String representation of the result of invoking the toCSV() method in the base class followed by the number of visits, formatted using a format String of "%s,%d".

  7. The fromCSV() method must set all of the attributes of the owning object. It may assume that the String it is passed was created by the toCSV() method and must not do any error checking.

  8. The toString() must return a String representation of the result of invoking the toString() method in the base class followed by the number of visits, formatted using a format String of "%s\nVisits: %d".

  9. No method in the VIPAccount class may duplicate code in the Account class.

Unit Testing

You must write JUnit tests for all of your classes. Your JUnit test suite must cover all statements and all branches (as measured by EclEmma) in all of the classes you write. Your tests must be in a package named testing and each test class must include the word “Test” in its name.

As in the past, your unit tests of the input/output methods must make use of round-trip testing. So, you must create a JUnit test that first executes the appropriate write method and then executes the appropriate read method. Note that, to ensure that the write happens before the read, the two must be in the same JUnit test. You can (and should) have multiple tests of this kind, but each must be independent of the others.

Submission

You must submit (using Gradescope) a .zip file named pa2.zip that contains:

  1. CSVRepresentable.java, FileIdentifier.java , FileProcessor.java, CSVFileProcessor.java, Account.java, and VIPAccount.java; and

  2. Your JUnit tests

packaged appropriately. The io, membership, and testing directories/folders must be at the top of the .zip file. (See the previous programming assignment if you have forgotten how to do this.) Do not submit any .bbb files.

Your grade will be reduced by 5 points for each submission after the 10th submission. So, you should try to ensure that your code is correct before you submit it the first time. In other words, you should not use Gradescope to check your style, to test your code, or to ensure that your tests cover your code - you should do all of that on your computer before you make any submissions to Gradescope.

Note that your submission will not be graded if it does not comply with the specifications. So, if you do not complete a class your submission should include a stubbed-out version of it. This will allow you to potentially get credit for the methods/classes that you do complete.

Grading

Your code will first be graded by Gradescope and then by the Professor. The grade you receive from Gradescope is the maximum grade that you can receive on the assignment

Gradescope Grading

Your code must compile (in Gradescope, this will be indicated in the section on “Does your code compile?”) and all class names and method signatures must comply with the specifications (in Gradescope, this will be indicated in the section on “Do your class names, method signatures, etc. comply with the specifications?”) for you to receive any points on this assignment. Gradescope will then grade your submission as follows:

CriterionPointsDetails
Conformance to the Style Guide0Success Required
Passing Your Tests10All or Nothing; Success Required
Coverage of Your Tests20Partial Credit Possible
Correctness70Partial Credit Possible

As discussed above, your grade will be reduced by 5 points for each submission after the 10th submission. Gradescope will provide you with hints, but may not completely identify the defects in your submission.

Manual Grading

After the due date, the Professor may manually review your code. At this time, points may be deducted for code that does not conform to the specifications, inelegant code, duplicate code, inappropriate variable names, bad comments, etc.

At this point in the semester, you should be able to create a good process and use it.

Questions to Think About

You don’t have to submit your answers to these questions, but you should try to answer them because they will help you determine whether or not you understand some of the important concepts covered in this assignment. Note that you do not need the source code for the CashRegister class to answer them.

  1. Suppose you have a CashRegister class in which a canUseExpressLine() message is sent to an Object named member, which is declared to be an Account but can actually be either an Account or a VIPAccount. Both classes have such a method. What code is invoked and why?

  2. Suppose you have a CashRegister class in which the availableCredit() message is sent to an Object named member, which is declared to be an Account but can actually be either an Account or a VIPAccount. The only availableCredit() method is in Account.java so, obviously, that code will be invoked. However, the getRewardPercentage() method is then invoked, and this method is implemented in both classes. What code will be invoked and why?

  3. Suppose you have a CashRegister class in which the purchase() message is sent to an Object named member, which is declared to be an Account but can actually be either an Account or a VIPAccount. The only purchase() method is in Account.java so, obviously, that code will be invoked. However, the increasePurchases() method is then invoked, and this method is implemented in both classes. What code will be invoked and why?

  4. Suppose you have a CashRegister class that has an overloaded addToLog() method, one which is passed an Account and of which is passed a VIPAccount. Suppose further that this method is passed an Object named member which is declared to be an Account but can actually be an Account or a VIPAccount, both of which implement the CSVRepresentable interface. Which overloaded version of addToLog() will be invoked and why?

  5. Why is the FileProcessor class declared to be abstract?

  6. Will the following fragment compile? Why or why not?

    FileProcessor fp;
    fp = new CSVFileProcessor("temp.csv");
    
  7. In the previous programming assignment, the io package was a subpackage of the product package. In this assignment, the io package is not inside the membership package. Why not?

4 - PA1: Teethbrushes

Programming Assignment 1

Teethbrushes

Learning Objectives

This programming assignment is designed to help you learn several things. First, it will help you learn about specialization (i.e., derived classes), inheritance, and overriden methods. Second, it will help you learn about reading from and writing to the file system (i.e., file input and output). Finally, it will help you become familiar with packages.

Overview

You may have heard, or you may have observed first-hand, that computer science students sometimes have personal hygiene problems. (Not you of course, but perhaps some of your fellow students?) A recent survey identified part of the problem. Many computer science students only brush one tooth (rather than all of them) because they were told to use a toothbrush and the word tooth is singular. An enterprising company has decided to take advantage of this confusion by selling teethbrushes instead.

At the moment, they are starting to build relationships. For example, they have contracted with “Dr. Teeth and the Electric Mayhem” to write their advertising jingles, and they have contracted with you to implement some of the classes needed for their inventory system.

Background

A physical Teethbrush consists of a head (and associated handle or stem) while a physical ElectricTeethbrush consists of a head and a body. The bristles in the head can be flat or polished (i.e., rounded). The body of an ElectricTeethbrush can be rechargeable or not, and can provide ultrasonic cleaning (via the head) or not.

The cost of a Teethbrush is the sum of the BASE_HEAD_COST ($2.00), the hardness cost, and the POLISHED_UPCHARGE ($0.75) if the bristles are polished. The hardness cost is the product of the hardness (which is in the closed interval [0, 5]) of the bristles and the HARDNESS_UPCHARGE ($0.10). So, the harder the bristles, the higher the cost. For example, a Teethbrush that has polished bristles with a hardness of 5 costs $2.00 + $0.75 + $0.50 = $3.25

The head of an ElectricTeethbrush costs the same as the head of a Teethbrush. However, an ElectricTeethbrush comes with multiple heads, whereas a Teethbrush has only one. Hence, the cost of an ElectricTeethbrush is the product of the NUMBER_OF_HEADS (5) and the cost of a Teethbrush, plus the BASE_BODY_COST ($5.00), plus the RECHARGEABLE_UPCHARGE ($20.00) and the ULTRASONIC_UPCHARGE ($10.00) as appropriate. For example, a basic ElectricTeethbrush that has polished bristles with a hardness of 0 has an initial cost of $13.75 + $5.00 = $18.75, and a rechargeable version would cost $18.75 + $20.00 = $38.75.

The shipping cost of an order is the product of the unit shipping cost and the order size, plus a STOCKING_COST ($25.00) if the size of the order is greater than the current inventory level. The unit shipping cost is either the UNIT_SHIPPING_COST_OVERSEAS ($0.30) or the UNIT_SHIPPING_COST_LOCAL ($0.10), reduced by the LARGE_ORDER_DISCOUNT (30.0%) if the order is greater than LARGE_ORDER (1000). For example, suppose someone wants to ship an order of 2000 Teethbrush overseas when there are 100 in inventory. The unit shipping cost will be $0.21 (the $0.30 minus the large order discount of $0.09), meaning the total shipping cost will be $445.00 (i.e., $0.21 x 2000 = $420.00 plus the $25.00 stocking cost).

The Classes to be Written

You must write the Teethbrush, ElectricTeethbrush, and ProductFileProcessor classes that are summarized in the following UML class diagram.

Class Diagram

Note that attributes and methods that are inherited are not made explicit in this diagram. If a method appears in both a base class and a derived class it means that the method in the derived class overrides the method in the base class.

The Teethbrush Class

As discussed above and as shown in the UML class diagram, a Teethbrush object is characterized by the hardness of the bristles (on a scale of 0-5), and whether the bristles are polished or not (i.e., whether the part of the bristle that comes in contacts with the teeth is flat or rounded). A Teethbrush object also has an associated inventory level.

In addition to the specifications contained in the UML class diagram and the background discussion above, this class must conform to the following specifications.

  1. Any time someone attempts to set the hardness attribute to a value less than 0 it must be set to 0.
  2. Any time someone attempts to set the hardness attribute to a value greater than 5 it must be set to 5.
  3. The changeInventory() method can be used to increase (with a positive parameter) or decrease (with a negative parameter) the inventory attribute. It must not change the inventory attribute (and must return false) if the change would make the inventory attribute negative. Otherwise, it must make the change and return true.

The ElectricTeethbrush Class

As discussed above and as shown in the UML class diagram, in addition to the attributes of a Teethbrush, an ElectricTeethbrush can be rechargeable or not, and can be ultrasonic or not.

In addition to the specifications contained in the UML class diagram and background discussion above, this class must conform to the following specifications.

  1. The cost() method in the ElectricTeethbrush class must not duplicate any code in the method that it overrides.

The ProductFileProcessor Class

The ProductFileProcessor is a utility class that can be used to read/write Teethbrush and ElectricTeethbrush information from/to the file system in (a simplified) comma-separated-valued (CSV) format in which fields are delimited by a comma and there is a newline character at the end of a record. For example, the CSV file for an electric toothbrush might be as follows:

0,3,true,false,true

In addition to the specifications contained in the UML class diagram, this class must conform to the following specifications.

  1. The file name to use when reading and writing must be the model name followed by ".bru". So, for example, the information about model "E1003" must be in a file named "E1003.bru" (in the working directory/folder).
  2. All objects used for reading and writing must be closed when they are no longer needed.
  3. The writeTeethbrush() method must write the inventory, hardness, and polished attributes using "%d,%d,%b\n" as the format String
  4. The writeElectricTeethbrush() method must write the inventory, hardness, polished, rechargeable and ultrasonic attributes using "%d,%d,%b,%b,%b\n" as the format String
  5. The readTeethbrush() method must read a file written by the writeTeethBrush() method, construct and initialize a Teethbrush object, and return it.
  6. The readElectricTeethbrush() method must read a file written by the writeElectricTeethBrush() method, construct and initialize an ElectricTeethbrush object, and return it.

Unit Testing

You must write JUnit tests for the Teethbrush, ElectricTeethbrush, and ProductFileProcessor classes. Your JUnit test suite must cover all statements and all branches (as measured by EclEmma) in all of the classes you write. Your tests must be in a package named testing and each test class must include the word “Test” in its name.

Submission

You must submit (using Gradescope) a .zip file named pa1.zip that contains:

  1. Your implementation of the Teethbrush, ElectricTeethbrush, and ProductFileProcessor classes.

  2. Your JUnit tests.

packaged appropriately.

Do not submit any .bru files. To test the read methods in your ProductFileProcessor class you must create a JUnit test that first executes the appropriate write method and then executes the appropriate read method. (This is sometimes called “round trip” testing of input/output.) Note that, to ensure that the write happens before the read, the two must be in the same JUnit test. You can (and should) have multiple tests of this kind, but each must be independent of the others.

There is no limit on the number of submissions and no penalty for excessive submissions. Note that your submission will not be graded if it does not comply with the specifications. So, if you do not complete a class your submission should include a stubbed-out version of it. This will allow you to potentially get credit for the classes/methods that you do complete.

Grading

Your code will first be graded by Gradescope and then by the Professor. The grade you receive from Gradescope is the maximum grade that you can receive on the assignment

Gradescope Grading

Your code must compile (in Gradescope, this will be indicated in the section on “Does your code compile?”) and all class names and method signatures must comply with the specifications (in Gradescope, this will be indicated in the section on “Do your class names, method signatures, etc. comply with the specifications?”) for you to receive any points on this assignment. Gradescope will then grade your submission as follows:

CriterionPointsDetails
Conformance to the Style Guide0Success Required
Passing Your Tests10All or Nothing; Success Required
Coverage of Your Tests20Partial Credit Possible
Correctness70Partial Credit Possible

Note that some of the criteria are described as “Success Required”. This means that Gradescope will not assess subsequent criteria unless this criterion is satisfied (and you will receive a grade of 0 for the criteria that aren’t assessed). So, for this assignment, if your code does not conform to the style guide then nothing else will be assessed (and you will receive a grade of 0 for the assignment). Similarly, if your code does not pass your tests, nothing else will be assessed and you will receive a grade of at most 10.

Gradescope will provide you with hints, but may not completely identify the defects in your submission.

Manual Grading

After the due date, the Professor may manually review your code. At this time, points may be deducted for inelegant code, inappropriate variable names, bad comments, etc.

Since nobody will be looking over your shoulder, you can use any process that you would like to use. However, it is strongly recommended that you use the process described here.

Get Started

  1. Read and understand the entire assignment.

  2. In Eclipse, create a project for this assignment named pa1. (Remember, do not create a module, and create separate folders for source and class files).

  3. In Eclipse, create three packages (in the project) named product, product.io, and testing. Do not have Eclipse create package-info.java for any of these packages.

  4. Activate Checkstyle for this assignment.

Create Test Cases for Teethbrush and ElectricTeethbrush

  1. By hand (i.e., using pencil and paper), create several black-box tests cases (i.e., inputs and expected outputs) for the cost() method in the Teethbrush class. Some of these tests should involve random inputs and some should involve rules-of-thumb.

  2. By hand, create tests several black-box cases for the shippingCost() method in the Teethbrush class. Some of these tests should involve random inputs and some should involve rules-of-thumb.

  3. By hand, create sevearl black-box tests cases for the cost() method in the ElectricTeethbrush class. Some of these tests should involve random inputs and some should involve rules-of-thumb.

Writing these black-box test cases before you start writing the code is called test driven development (TDD). Using TDD will help you understand the algorithms that you need to write.

Stub-Out the Classes

  1. Stub-out the Teethbrush class.
  2. Stub-out the ElectricTeethbrush class.
  3. Stub-out the ProductFileProcessor class.
  4. Add the “javadoc” comments to the three classes class.
  5. Check the style of the three classes and make any necessary corrections.

Implement and Test the Classes

  1. Implement the constructor, setters, and simple getters in the Teethbrush class.

  2. Test the constructor, setters, and simple getters in the Teethbrush class using the black-box tests (and debug if necessary).

  3. If necessary, add white-box tests to get 100% statement coverage and 100% branch coverage (and debug if necessary).

  4. Implement the constructor and simple getters in the ElectricTeethbrush class.

  5. Test the constructor and simple getters in the ElectricTeethbrush class using the black-box tests (and debug if necessary).

  6. If necessary, add white-box tests to get 100% statement coverage and 100% branch coverage (and debug if necessary).

  7. Implement the shippingCost() method in the Teethbrush class.

  8. Test the shippingCost() method in the Teethbrush class using the black-box tests (and debug if necessary).

  9. If necessary, add white-box tests to get 100% statement coverage and 100% branch coverage (and debug if necessary).

  10. Implement the cost() method in the Teethbrush class.

  11. Test the cost() method in the Teethbrush class using the black-box tests (and debug if necessary).

  12. If necessary, add white-box tests to get 100% statement coverage and 100% branch coverage (and debug if necessary).

  13. Implement the cost() method in the ElectricTeethbrush class.

  14. Test the cost() method in the ElectricTeethbrush class using the black-box tests (and debug if necessary).

  15. If necessary, add white-box tests to get 100% statement coverage and 100% branch coverage (and debug if necessary).

  16. Use the same kind of process to develop, test, and debug the ProductFileProcessor class.

Help

Help is available on the following topics.

Help Creating Packages

Help with creating packages in Eclipse is available on the Department’s Wiki at:

Help Creating Files (Including Files in a Package)

Help with creating files in Eclipse (including files in a package) is available on the Department’s Wiki at:

Help with JUnit

You should be fairly proficient with JUnit at this point (especially since we will be using JUnit for the rest of the semester). However, if you are still having trouble, help is available at:

Help with Coverage

In order to get 100% coverage, you sometimes have to be aware of some quirks of the language you are working in, and the tool set you are using. For more information, see:

Help Creating the .zip File

The directories/folders containing the packages must appear at the top of the .zip file. So, you must not compress the directory/folder containing these directories/folders, you must compress the directories/folders containing the packages. In other words, if you have a directory named src that contains the directories product and testing, you must not compress src, you must compress product and testing. (Note that the io directory/folder will be inside of the product directory/folder.)

Help with creating .zip files is available on the CS Wiki. In particular, see:

Note that your .zip file must only contain .java files, not .class files. This will be much easier to accomplish if, when you create your project, you instruct Eclipse to use separate directories/folders for source and class files.

Help Using a Scanner

There are two delimiters used in CSV files, the comma that separates fields and the newline character that separates records (or lines). To instruct a Scanner to use a particular delimiter or delimiters you must invoke its useDelimiter() method. To instruct it to use just commas as delimiters you must pass it ",", to instruct it to use just newlines as delimiters you must pass it "\n", and to instruct it to use both you must pass it "[,\n]" (which is a regular expression that matches both).

Help Using a BufferedReader

There are two delimiters used in CSV files, the comma that separates fields and the newline character that separates records (or lines). If you choose to use a BufferedReader you will read an entire record (including the newline character) using the readLine() method. You can then tokenize it either using the split() method in the String class (passing it "," as the delimiter) or using a StringTokenizer object (again using "," as the delimiter).

Questions to Think About

You don’t have to submit your answers to these questions, but you should try to answer them because they will help you determine whether or not you understand some of the important concepts covered in this assignment.

  1. Would the design of the Teethbrush class be improved by using a 0-1 indicator for the polished attribute (as discussed in Chapter 6 of Patterns for Beginning Programmers ) rather than using a boolean value? What would change in the constructor, cost() method, and isPolished() method?

  2. What is gained by using specialization in this assignment? In other words, what is gained from having the ElectricTeethbrush class extend the Teethbrush class?

  3. Is there code duplication in the “read” methods of the ProductFileProcessor class? Why is this troubling?

  4. Is there code duplication in the “write” methods of the ProductFileProcessor class? Why is this troubling?

  5. Given the number of classes in this assignment, are the packages that helpful? When is the use of packages likely to be more helpful?