Category Archives: Assignment

Chapter 5: Goodies Co. Examples

The Goodies Company Project

vendingmachines

From Wikipedia:
In computer programming, an application programming interface (API) is a set of routines, protocols, and tools for building software applications. An API expresses a software component in terms of its operations, inputs, outputs, and underlying types. An API defines functionalities that are independent of their respective implementations, which allows definitions and implementations to vary without compromising the interface. A good API makes it easier to develop a program by providing all the building blocks. A programmer then puts the blocks together.

Cay Horstmann:
A class should represent a single concept. The public methods
and constants that the public interface exposes should be cohesive.
That is, all interface features should be closely related to the single
concept that the class represents.
If you find that the public interface of a class refers to multiple concepts,
then that is a good sign that it may be time to use separate classes instead.

NO CODE – It is no programming language related!

Examples of public interfaces for the Goodies Company Application:
Example 1:

Class BD_VendingMachine:
public BD_VendingMachine: initializes allocated change and sets profit to 0
void addChange(value) adds allocated change
void addProduct(BD_Product) adds a product to the machine
double getBalance() returns profit
double getChange() returns allocated change remaining
void purchase(BD_Product, double money) buys product inputted and determines change to return, subtracting from allocated change accordingly

Class BD_Product:
public BD_Product(string name, double price)initializes new product and price

Example 2:
Classes:

Class 1 – snack
name, price, stock
can set the name price and amount of the item
can change the price of the item
will decrement the amount when the item is purchased

Class 2 – machine
sales, list of snacks
holds several objects of the class snack
method for purchasing an item which will decrement the snack, increase sales, and output change
method for restocking the amount of a snack
can remove and add snacks
can return the total sales of a machine

Class 3/ Main Class –
runs several of the machines
will buy snacks from various machines
will restock the machines
will check the total sales and amount of snacks in each machine

Example 3:
Vending Machine Project Outline

VendingMachine —> Class
– Array of Products
– Amount initially put in for change
– Total
– Name / Location
addProduct() – allows you to add a product object to the inventory of the machine
addChange() – allows you to add change to the machine
getProfit() – subtracts the added change from the total to display the profit of the machine
buy() – takes in a Product object, and a money value (possibly in coin objets) and allows you to “buy” the product

Product —> Class
– name
– price
getPrice()
getName()
toString()

Coin —> Class
– name
– value
getValue()
getName()
toString()

Example 4:
buyDrink: contains getPrice, giveChange, will give an error message if there are none left
toString: will show everything in the machine and its prices (and quantities?)
addChange: adds to the machine’s change supply w/o buying anything
getQuantity: tells you how many of a drink are in the machine

contains different types of drinks (Drink class?)
takes coins form Coin class

Example 5:
order(x) – The order method is called whenever the user places an order. It decreases the
quantity of the specific item by 1 and adds the price to the overall profit. The item the person
order is given by x, which is an integer that corresponds to the object.
makeChange(x, y) – The makeChange method is always called right after the order method. It
takes in the item as it’s first parameter and the amount the user put into the machine as it’s
second. Then, it returns how much the machine owes the user.
getProfit() – The getProfit method returns the total profit the machine makes.
getQuantity() – The getQuantity method returns the total quantity left of each item in the
machine.

Example 6:
Classes:
endingMachine: This class deals with Product objects and the number of Product objects that exist. This also deals with money taken from the user.
Product: This contains instance variables for different products with their descriptions and prices.
Driver: represents the user’s interaction with the vendingMachine

Methods (VendingMachine):
sellProduct: This method gives a product to the user by lowering the stock of that product and increases profit but checks if the amount of inserted money is enough for the purchase. And if not it refuses it and uses the giveChange method to return the rest.
collectMoney: Collects only the amount of money needed by the machine and allows for sellProduct method.
giveChange: Gives the remaining amount of money that was given but not required to purchase the product.
restockItems: Resets the amount of goods that exist in the vendingmachine.

Product Methods:
getPrice: gives price of product
getProductName: gives the name of the product chosen

Chapter 5: Goodies Co. – The requirements

Design an application Phase 1 – The business model:

vendingmachines

The Goodies Co. maintains a kiosk at a busy location with other competing kiosks. This vending front sells snacks and beverages only. Mrs. Goodies has been operating it manually but she wants to have an automated system that would allow her to manage the kiosk more efficiently.

The client’s requirements at a glance are as follow:
It should have two interfaces: one for the customer and another for the business operation.

Sample of a day’s activity:
Welcome to Goodies Vending Store
1. Business Operation
2. Customer
3. Exit
What is your choice? 1

Business Operations
1. View Inventory
2. Re-stock
3. blah blah …
4. blah blah …
5. Back to the main menu
6. Exit Goodies Vending Store
What is your choice? 5

Welcome to Goodies Vending Store
1. Business Operation
2. Customer
3. Exit
What is your choice? 2

Welcome to Goodies Vending Store
Here are your choices:
1. Drinks
2. Drygoods
3. Frozen delights
4. blah blah
5. Back to the main menu
6. Done with purchases
7. Exit Goodies Vending Store
1 –> drinks menu should come up

Prompt the buyer for more purchases or to go back to the main menu.

What is your choice? 5
Your total is $22.75

Bye! See you soon.
It was a pleasure to serve you!

Customer Interface

  • Available products and price should be displayed numerically as a text menu.
  • The customer should be able to access the product by pressing a key with a number
  • The customer should be prompted for option number.
  • Payment can be assumed to be exact and correct.
  • Handle payment.
  • Update sales record(s).
  • Update kiosk inventory.
  • Back to customer menu.
  • Prompt the user for product number? Exit?
  • If exit, it should go back to the START of operiations.

Business Operations

  • The Business Operations should only be accessed by password (Optional)
  • The system should know the quantity, cost, and selling price for each product.
  • It should keep a current inventory of the products in the kiosk and in stock.
  • It should have re-stocking(s) notification(Optional)
  • It should have an option to re-stock both the store and the stockpile
  • Update stockpile inventory
  • It should access information of the net profits based on the sales on demand.

The START of Operations

  • Welcome message.
  • Load data base of products and prices.
  • Menu: Customer? Business Operations?
  • Chose?/Exit?

The END of Operations

  • Update database with current quantities.
  • Prompt the business manager for stockpile re-stocking
  • Close database files
  • Goodbye message

Assumptions

  • Payment is exact and correct.
  • Products pricess never change

Chapter 5 – Software Life Cycle

Software Development Activities

Four basic development activities:

  • establishing the requirements
  • creating a design
  • implementing the design
  • testing

This sequence would be ideal but it almost never completely linear in reality.
They overlap and interact.

Software requirements specify what a program must accomplish: a document called a functional specification.

The client will often provide an initial set of requirements. However, these initial requirements are often incomplete, ambiguous, and perhaps even contradictory.

The software developer must work with the client to refine the requirements.

A software design indicates how a program will accomplish its requirements.

The design specifies the classes and objects needed in a program and defines how they interact. It also specifies the relationships among the classes.

During software design, alternatives need to be considered and explored. Often, the first attempt at a design is not the best solution.

Implementation is the process of writing the source code that will
 solve the problem.

Too many programmers focus on implementation exclusively when actually it should be the least creative of all development activities. The important decisions should be made when establishing the requirements and creating the design.

Testing is the act of ensuring that a program will solve the intended problem given all of the constraints under which it must perform.

Identifying classes and objects

A fundamental part of object-oriented software design is determining the classes that will contribute to the program. We have to carefully consider how we want to represent the various elements that make up the overall solution. These classes determine the objects that we will manage in the system.

When designing classes, objects are generally nouns.

The nouns in a problem description may indicate some of the classes and objects needed in a program.

A class represents a group of objects with similar behavior. A plural noun is an indication that your design might not be good.

Classes that represent objects should generally be given names that are singular nouns.

A class represents a single item from which we are free to create as many instances as we choose.

Another key decision is whether to represent something as an object or as a primitive attribute of another object.

We want to strike a good balance between classes that are too general and those that are too specific.

There might be additional classes to support the work necessary to get the job done.

Keep in mind that may be an old class that’s similar enough to serve as the basis for our new class.

The existing class may be part of the Java standard class library, part of a solution to a problem we’ve solved previously, or part of a library that can be bought from a third party, “Software Re-usability”.

Assigning responsibilities

Part of the process of identifying the classes needed in a program is the process of assigning responsibilities to each class. Each class represents an object with certain behaviors that are defined by the methods of the class. Any activity that the program must accomplish must be represented somewhere in the behaviors of the classes. That is, each class is responsible for carrying out certain activities, and those responsibilities must be assigned as part of designing a program.

Generally use verbs for the names of behaviors and the methods that accomplish them.

Sometimes it is challenging to determine which is the best class to carry out a particular responsibility. You could benefit from defining another class to shoulder the responsibility.

It’s not necessary in the early stages of a design to identify all the methods that a class will contain. It is often sufficient to assign primary responsibilities and consider how those responsibilities translate to particular methods.

Class and object relationships

The classes in a software system have various types of relationships to each other. Three of the more common relationships are dependency, aggregation, and inheritance.

Dependency relationships: a class “uses” another.
Class A uses class B, then one or more methods of class A invoke one or more methods of class B. If an invoked method is static, then A merely references B by name. If the invoked method is not static, then A must have access to a specific instance of class B in order to invoke the method. That is, A must have a reference to an object of class B.

dependency

UML notation distinguishes between object diagrams and class diagrams. In an object diagram the class names are underlined; in a class diagram the class names are not underlined. In a class diagram, you denote dependency by a dashed line with a shaped open arrow tip that points to the class that is dependent on. Figure 1 shows a class diagram indicating that the CashRegister class depends on the Coin class.

Note that the Coin class does not depend on the CashRegister class. Coins have no idea that they are being collected in cash registers, and they can carry out their work without ever calling any method in the CashRegister class.

coupling

Aggregation: the objects of one class contain objects of another, creating a “has-a” relationship.
When one class instantiates the objects of another, it is the basis of an aggregation relationship. The access can also be accomplished by passing one object to another as a method parameter.
The less dependent our classes are on each other, the less impact changes and errors will have on the system.

Inheritance: creates an “is-a” relationship between classes.

Assignment:

Design an application:

A computer-based system is to be implemented for an airport snack bar business, Goodies Co.
1. Define what the needs are.
2. Based on the previous, create a list of questions for your “client”.
3. Work with your partner to outline the different components to run the company.

vendingmachines

 

Chapter 5: The Goodies Co. – Next step

The Goodies Company Project

vendingmachines

Designing and Implementing – Phase 1:
1. Use your questions and answers as a guide to define the signature of every class’ method.
2. Draw a UML class diagram for your entire application. Make sure you follow the rules for UML.
NOTE: You can use google doc drawing or just a word doc.
.
goodies-Class-Digram-phase-2-2
.
.
UMLBasics-arrows
.
.
Here is the link to a UML builder you used before.
www.umletino.com

Using your Design/UML, implement the Business Operations application for the business owner/manager/bookkeeper/accountant to operate the business.

Day 3: The user interface
Write a program (main) that displays multiple menus.
Example of a simplified session to start your code:

Welcome to Goodies Vending System
1. Business Operation
2. Customer
3. Exit
What is your choice? 1

Business Operations
1. View Inventory
2. Re-stock
3. blah blah …
4. blah blah …
5. Back to the main menu
6. Exit Goodies Vending System
What is your choice? 5

Welcome to Goodies Vending System
1. Business Operation
2. Customer
3. Exit
What is your choice? 2

Welcome to Goodies Vending Machine
Here are your choices:
1. Drinks
2. Drygoods
3. Frozen delights
4. blah blah …
5. Back to the main menu
6. Done with purchases
7. Exit Goodies Vending System
1 –> drinks menu should come up
Prompt the buyer for more purchases or to go back to the main menu.

What is your choice? 5

Your total is $22.75
Bye! See you soon.
It was a pleasure to serve you!

What is next?
A modified Menu:
1. Start the company’s initial state. That includes inventory with the cost associated with the purchases of the products. This feature enables the user to print the table below with the current inventory.
NOTE: display all information in well-aligned columns. Use “printf”.

  1. Updates to the products, quantities, cost and the sale price.
  2. Closing of the business cycle by producing a report with all needed information.
  3. If you need more information from the client, add the questions to your list.
  4. Test your implementation with the client’s data.
  5. Let your client use your implementation.
  6. Make changes to your implementation based on your client’s comments and suggestions.

Check edmodo for the due dates. WARNING: there are no soft due dates for this project. All due dates are hard and penalties will be applied.

Find below some basic raw data to start with but it is not limited to.

This menu will be used by the manager/owner/business operator

Drinks 
         Quantity Available  Cost/case(45) $  Sale Price $
1. Sunkist            45            16         1.25
2. Coca Cola          45            18         1.25
3. Brisk              45            17         1.25
5. Sprite             45            17         1.25
6. Ginger Ale         45            21         1.25
7. Dr. Pepper         45            20         1.25
8. Capri Sun          45            15         1.25
9. Water              45            22         1.00

Snacks 
         Quantity Available  Cost/case(45) $  Sale Price $
1. Chips              45            25         0.75          
2. Pop corn           45            22         0.75         
3. Pop Corners        45            22         0.75     
4. Veggie Sticks      45            21         0.75     
5. Rice Krispies      45            20         0.50     
6. Cookies            45            36         0.75         
7. Granola Bars       45            40         0.50 
8. Fruit Snacks       45            28         0.50 
9. Snack Bars         45            41         0.50

NOTE: Keep all this information as raw data in a text file.
Raw data text file should look like this:
snacks
Chips,45,25,0.75
Popcorn,45,22,0.75
Pop Corners,45,22,0.75
Cheeze it,45,18,0.75
Gold Fish,45,18,0.75
Oreo Cookies,45,30,0.75
Fruit Snack,45,15,0.25
Trail Mix,45,22,0.50
Nutrigrain,45,31,0.50
Peanut Bar,45,16,0.50
drinks
Coke,45,18,1.25
Sprite,45,17,1.25
Sunkist,45,16,1.25
Brisk,45,17,1.25
Ginger Ale,45,21,1.25
Water,45,22,1.00
Capri Sun,45,15,0.75
else
Ice cream,45,20,1.00
Klondike Bars,45,15,1.25
Italian Ice,45,10,1.25
Ice pop,45,16,0.25
end

Warning: NO SPACES should be used to separate the data fields and the commas.

I attached two files with java code to read and write text files. However, there are other options you can use.

Q. What is the public interface of a class?
A. The public interface of a class is a document with the name of each method, the description of the method, and the method’s pre-conditions and post-conditions.

This menu could be typical for a menu for purchasing snacks and drinks

Drinks 
                 Sale Price $
1. Sunkist            1.25
2. Coca Cola          1.25
3. Brisk              1.25
5. Sprite             1.25
6. Ginger Ale         1.25
7. Dr. Pepper         1.25
8. Capri Sun          1.25
9. Water              1.00

Snacks 
                  Sale Price $
1. Chips              0.75          
2. Pop corn           0.75         
3. Pop Corners        0.75     
4. Veggie Sticks      0.75     
5. Rice Krispies      0.50     
6. Cookies            0.75         
7. Granola Bars       0.50 
8. Fruit Snacks       0.50 
9. Snack Bars         0.50

WriteToTxtFile

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
// http://www.homeandlearn.co.uk/java/write_to_textfile.html
/**
 * Write a description of class WriteToTxtFile here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class WriteToTxtFile
{
    public static void main(String [] args)
    {
        String myFile = "RawData.txt";
        try{
            FileWriter write = new FileWriter( myFile);
            PrintWriter print_line = new PrintWriter(write);
            print_line.printf("%s" + "%n", "Testing write to a file");
           
        print_line.close();
        }
        catch (IOException e) { System.out.println("It doesn't work");
        
        
        }
    }
}

[collapse]
ScannerReadFile

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
 
public class ScannerReadFile {
 
    public static void main(String[] args) {
 
        // Location of file to read
        File file = new File("data.txt");
 
        try {
 
            Scanner scanner = new Scanner(file);
 
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                System.out.println(line);
            }
            scanner.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
 
    }
}


[collapse]

Standard Libraries
printf short version
printf resource

Chapter 4: Building Design

Programming Assignment 4.9
Design and implement a class called Building that represents a drawing of a building.
The parameters to the constructor should be the building’s width and height.
Each building should be colored black and have a few random windows colored yellow.
Create an application with StdDraw that draws a random skyline of buildings.
skyline

StdDraw library from PU

Chapter 4: Objects Revisited

Chapter 4 – Writing Classes

Concepts to discuss:
keyconcept2

  • attributes, states and instance fields
  • behavior and methods

attributesAndMethods1

methodofaclass4

rollingdiceUML5

keyconcept4

  • object variable and object reference
  • classes as blueprints
  • members of a class

memberofaclass3

 

  • constructors

keyconcept11

 

  • methods

flowofcontrol9

methoddeclaration8

keyconcept8

returnmethod10

keyconcept9

passingpara11

  • access specifiers or visibility modifiers

effectofpublicprivatevisibility7

  • What does a predicate method do? It evaluates the predicate on the value passed to this function as the argument and then returns a boolean value.

keyconcept6

 

  • variable scope

keyconcept3

keyconcept10

 

  • ENCAPSULATION

keyconcept5

 

aclientinteraction6

keyconcept7

Answer the following questions:
Lesson Questions

  1. What is an attribute?
  2. What is an operation?
  3. List some attributes and operations that might be defined for a class called Book that represents a book in a library.
  4. True or False? Explain.
    a. We should use only classes from the Java standard class library when writing our programs—there is no need to define or use other classes.
    b. An operation on an object can change the state of an object.
    c. The current state of an object can affect the result of an operation on that object.
    d. In Java, the state of an object is represented by its methods.
  5. What is the difference between an object and a class?
  6. What is the scope of a variable?
  7. What are UML diagrams designed to do?
  8. Objects should be self-governing. Explain.
  9. What is a modifier?
  10. Describe each of the following:
    ◗ public method
    ◗ private method
    ◗ public variable
    ◗ private variable
  11. What does the return statement do?
  12. Explain the difference between an actual parameter and a formal parameter.
  13. What are constructors used for? How are they defined?
  14. How are overloaded methods distinguished from each other?
  15. What is method decomposition?
  16. Explain how a class can have an association with itself.
  17. What is an aggregate object?

Submit your answers as we discuss them. This assignment will take more than one lesson but submit what you have every time we have the lesson.
 

Chapter 4: Be Rational

Chapter 4 Programming Assignment 7
Write an application, RationalOperations_YI.java that lets the user add, subtract, multiply, or divide two fractions. Use the Rational class in your implementation. Implement the driver class to test all operations. Have a loop prompting the user for operators and operands.

Screen Shot 2014-10-01 at 12.48.04 PM

//********************************************************************
//  RationalNumbers.java       Author: Lewis/Loftus/Cocking
//  BeRational Assignment: change this driver so the user can input Rational
//  numbers and selects the operations
//  Prompt the user for the rational RationalNumbers
//  Prompt the user for the operations
//  Driver to exercise the use of multiple Rational objects.
//********************************************************************

public class RationalNumbers
{
   //-----------------------------------------------------------------
   //  Creates some rational number objects and performs various
   //  operations on them.
   //-----------------------------------------------------------------
   public static void main (String[] args)
   {     
      Rational r1 = new Rational (6, 8);
      Rational r2 = new Rational (1, 3);
      Rational r3, r4, r5, r6, r7;

      System.out.println ("First rational number: " + r1);
      System.out.println ("Second rational number: " + r2);

      if (r1.equals(r2))
         System.out.println ("r1 and r2 are equal.");
      else
         System.out.println ("r1 and r2 are NOT equal.");

      r3 = r1.reciprocal();
      System.out.println ("The reciprocal of r1 is: " + r3);

      r4 = r1.add(r2);
      r5 = r1.subtract(r2);
      r6 = r1.multiply(r2);
      r7 = r1.divide(r2);

      System.out.println ("r1 + r2: " + r4);
      System.out.println ("r1 - r2: " + r5);
      System.out.println ("r1 * r2: " + r6);
      System.out.println ("r1 / r2: " + r7);
   }
}

Chapter 4 Programming Assignment 8
Modify the Student class (Listing 4.13) with the following changes:

a. Each student object also contains the scores for three tests.

b. Provide a constructor that sets all instance values based on parameter values. Overload the constructor so that each test score starts out at zero.

c. Provide a method called setTestScore that accepts two parameters: the test number (1 through 3) and the score.

d. Provide a method called getTestScore that accepts the test number and returns the score.

e. Provide a method called average that computes and returns the average test score for this student.

f. Modify the toString method so that the test scores and average are included in the description of the student.

g. Modify the driver class main method to exercise the new Student methods.

Chapter 4: Method Overloading

Method Overloading

  • Method overloading is useful when you need to perform similar operations on different types of data.
  • The same method name with different parameter list allows for method overloading.
  • The compiler must still be able to match up each invocation with a specific method declaration. If the method name for two or more methods is the same, then additional information is used to tell which version is being invoked.
  • In Java, a method name can be used for several methods as long as the number of parameters, the types of those parameters, and/or the order of the types of parameters is different.
  • A method’s name along with the number, type, and order of its parameters is called the method’s signature.
  • The compiler uses the complete method signature to bind a method invocation to its definition.

Class work:

1. Select a class of your choice and overload the constructor and a method. Submit also a test class to demonstrate the use of both constructors.

2. What error do you get if your overloaded constructor or method has the same signature as the original constructor or method? Based on the error given, can you deduce if overloading takes place at compilation or run time?

3. Write a method called evenlyDivisible that accepts two int parameters and returns true if the first parameter can be evenly divided by the second, or vice versa, and false if it can’t be. Return false if either parameter is zero. Overload evenlyDivisible to accept Integer parameters and have the same functionality. Include any comment you feel is appropriate.

4. Write a method called average that accepts two integer parameters and returns their average as a floating-point value. Overload the average method so that the method returns the average of three integers. Overload the average method to take four integer parameters and return their average.

Chapter 4: Huge Integer

Project includes: HugeInteger_YI.java and HugeIntegerDriver_YI.java

Huge Integer Class: Create a class HugeInteger which uses a 40-element array of digits to store integers as large as 40 digit long. Provide methods parse, toString, add and subtract to manipulate objects of HugeInteger. Method parse should receive a String, extract each digit using method charAt or substring and place the integer equivalent of each digit into the integer array and return a HugeInteger object. For comparing HugeInteger objects, provide the following methods:

isEqualTo, isGreaterThan, isLessThan, isGreaterThanOrEqualTo and isLessThanOrEqualTo

Each of these is a predicate method that returns true if the relationship holds between the two HugeInteger objects and returns false if the relationship does not hold. Provide a predicate method isZero.
The driver should look like this:


// 40-digit input
HugeInteger hi1 = new HugeInteger(?); // where the ? means any implementation you choose
HugeInteger hi2 = new HugeInteger(?); // where the ? means any implementation you choose

Addition implementations could be as follows:

HugeInteger hi3 = hi2.subtract(hi1);

or

hi2.subtract(hi1)

Things to know:
* Your driver should accept input BUT for testing purposes ONLY, you should hard code the test data.
* Do not use more than 10 digits as test data.
* Assume the string contains only integers.

Make sure you test your code properly:
– add numbers that require carryover
– subtract numbers that require borrowing
– a HugeInteger can be negative
– print the numbers before and after the operations

**** NOTE: This assignment is about object-oriented design. Therefore, the operands are objects of HugeInteger.

Before you start on this assignment, read it carefully and turn your paper for approval:
1. Simple example in paper and pencil: choose two smaller than 40-digit numbers and using your design add and subtract them. Use a diagram representing how the digits are placed in the array.
2. Address the details you need to implement to handle any issues like a “carry-over” and “borrowing” that might arise: re-design.
3. Re-do the example after you make the changes to your design.
NOTE: If you have any questions, I will not answer them unless you have your example on paper.
hugeInt-how2
.
hugeInt-how2
.
hugeInt-how2
.
BE AWARE that
25% of the grade is based on documentation. Indicate with a comment the code that handles each operation and how it does it.
25% of the grade is based on thorough testing.
25% of the grade is based on well-organized and readable code
25% of the grade is based on the working code.

Extra credit: provide methods multiply, divide and remainder. Limit these last 3 operations by a data type int.

Chapter 4: Rational ADT

//********************************************************************
//  Rational.java       Author: Lewis/Loftus/Cocking
//
//  Represents one rational number with a numerator and denominator.
//********************************************************************

public class Rational
{
   private int numerator, denominator;

   //-----------------------------------------------------------------
   //  Sets up the rational number by ensuring a nonzero denominator
   //  and making only the numerator signed.
   //-----------------------------------------------------------------
   public Rational (int numer, int denom)
   {
      if (denom == 0)
         denom = 1;

      // Make the numerator "store" the sign
      if (denom < 0)
      {
         numer = numer * -1;
         denom = denom * -1;
      }

      numerator = numer;
      denominator = denom;

      reduce();
   }

   //-----------------------------------------------------------------
   //  Returns the numerator of this rational number.
   //-----------------------------------------------------------------
   public int getNumerator ()
   {
      return numerator;
   }

   //-----------------------------------------------------------------
   //  Returns the denominator of this rational number.
   //-----------------------------------------------------------------
   public int getDenominator ()
   {
      return denominator;
   }

   //-----------------------------------------------------------------
   //  Returns the reciprocal of this rational number.
   //-----------------------------------------------------------------
   public Rational reciprocal ()
   {
      return new Rational (denominator, numerator);
   }

   //-----------------------------------------------------------------
   //  Adds this rational number to the one passed as a parameter.
   //  A common denominator is found by multiplying the individual
   //  denominators.
   //-----------------------------------------------------------------
   public Rational add (Rational op2)
   {
      int commonDenominator = denominator * op2.getDenominator();
      int numerator1 = numerator * op2.getDenominator();
      int numerator2 = op2.getNumerator() * denominator;
      int sum = numerator1 + numerator2;

      return new Rational (sum, commonDenominator);
   }

   //-----------------------------------------------------------------
   //  Subtracts the rational number passed as a parameter from this
   //  rational number.
   //-----------------------------------------------------------------
   public Rational subtract (Rational op2)
   {
      int commonDenominator = denominator * op2.getDenominator();
      int numerator1 = numerator * op2.getDenominator();
      int numerator2 = op2.getNumerator() * denominator;
      int difference = numerator1 - numerator2;

      return new Rational (difference, commonDenominator);
   }

   //-----------------------------------------------------------------
   //  Multiplies this rational number by the one passed as a
   //  parameter.
   //-----------------------------------------------------------------
   public Rational multiply (Rational op2)
   {
      int numer = numerator * op2.getNumerator();
      int denom = denominator * op2.getDenominator();

      return new Rational (numer, denom);
   }

   //-----------------------------------------------------------------
   //  Divides this rational number by the one passed as a parameter
   //  by multiplying by the reciprocal of the second rational.
   //-----------------------------------------------------------------
   public Rational divide (Rational op2)
   {
      return multiply (op2.reciprocal());
   }

   //-----------------------------------------------------------------
   //  Determines if this rational number is equal to the one passed
   //  as a parameter.  Assumes they are both reduced.
   //-----------------------------------------------------------------
   public boolean equals (Rational op2)
   {
      return ( numerator == op2.getNumerator() &&
               denominator == op2.getDenominator() );
   }

   //-----------------------------------------------------------------
   //  Returns this rational number as a string.
   //-----------------------------------------------------------------
   public String toString ()
   {
      String result;

      if (numerator == 0)
         result = "0";
      else
         if (denominator == 1)
            result = numerator + "";
         else
            result = numerator + "/" + denominator;

      return result;
   }

   //-----------------------------------------------------------------
   //  Reduces this rational number by dividing both the numerator
   //  and the denominator by their greatest common divisor.
   //-----------------------------------------------------------------
   private void reduce ()
   {
      if (numerator != 0)
      {
         int common = gcd (Math.abs(numerator), denominator);

         numerator = numerator / common;
         denominator = denominator / common;
      }
   }

   //-----------------------------------------------------------------
   //  Computes and returns the greatest common divisor of the two
   //  positive parameters. Uses Euclid's algorithm.
   //-----------------------------------------------------------------
   private int gcd (int num1, int num2)
   {
      while (num1 != num2)
         if (num1 > num2)
            num1 = num1 - num2;
         else
            num2 = num2 - num1;

      return num1;
   }
}