CISC 3115
Modern Programming Techniques
Lecture 1
Prep


Overview

In this lecture we're going to present a series of applications that are somewhat different than the ones you've seen in 1115. We'll develop them and discuss various issues as we go along.

Modelling 'Things': A Bank Account (01-BankAccount)

First Implementation (01-BankAccount/01-baseline)

Write an app named BankAccount that contains two methods named deposit and withdraw, both of which accept a balance and an amount and returns the amount added-to/subtracted-from the balance respectively. The mainmethod should illustrate the methods by declaring and initializing an integer variable named balance performing the following operations: first depositing $200, then withdrawing $50, followed by a second withdrawal of $70.

class BankAccount {
	public static void main(String [] args) {
		int balance = 0;
		System.out.println("Initial balance: " + balance);
		balance = deposit(balance, 200);
		System.out.println("Balance after deposit of $200: " + balance);
		balance = withdraw(balance, 50);
		System.out.println("Balance after withdrawal of $50: " + balance);
		balance = withdraw(balance, 70);
		System.out.println("Balance after withdrawal of $70: " + balance);
	}	

	public static int deposit(int balance, int amount) {return balance + amount;}
	public static int withdraw(int balance, int amount) {return balance - amount;}
}

Notes

First Regression: Remove the Methods (01-BankAccount/01-baseline/01-no-methods)

Let's just see where this takes us

class BankAccount {
	public static void main(String [] args) {
		int balance = 0;
		System.out.println("Initial balance: " + balance);
		balance += 200;
		System.out.println("Balance after deposit of $200: " + balance);
		balance -= 50;
		System.out.println("Balance after withdrawal of $50: " + balance);
		balance -= 70;
		System.out.println("Balance after withdrawal of $70: " + balance);
	}	
}

Notes

Second Regression: Remove the Meaningful Identifiers (01-BankAccount/01-baseline/02-no-names)

And here's what happens without meaningful names as well.

class C {
	public static void main(String [] args) {
		int i = 0;
		System.out.println("Initial balance: " + i);
		i += 200;
		System.out.println("Balance after deposit of $200: " + i);
		i -= 50;
		System.out.println("Balance after withdrawal of $50: " + i);
		i -= 70;
		System.out.println("Balance after withdrawal of $70: " + i);
	}	
}

Notes

A Second Implementation — File Input (01-BankAccount/02-from-input)

Hard-coding the transactions is both boring and overly constraining; lets read them in from a file containing an action code followed by a transaction amount

import java.io.File;
import java.util.Scanner;

class BankAccount {
	public static void main(String [] args) throws Exception {
		Scanner scanner = new Scanner(new File("bank_actions.text"));

		int balance = 0;

		while (scanner.hasNext()) {
			String action = scanner.next();
			int amount = scanner.nextInt();

			if (action.equals("D")) {
				balance = deposit(balance, amount);
				System.out.println("Balance after deposit of $" + amount + ": " + balance);
			}
			else if (action.equals("W")) {
				balance = withdraw(balance, amount);
				System.out.println("Balance after withdrawal of $" + amount + ": " + balance);
			}
		}
	}	

	public static int deposit(int balance, int amount) {return balance + amount;}
	public static int withdraw(int balance, int amount) {return balance - amount;}
}

bank_actions.text
D 200
W 50
W 70

A Third Implementation — No Overdraft Withdrawals (01-BankAccount/03-no-overdraft)

Let's add some more semantics … something a bit more realistic … you can't withdraw from an account unless there's sufficient money in the account.

import java.io.File;
import java.util.Scanner;

class BankAccount {
	public static void main(String [] args) throws Exception {
		Scanner scanner = new Scanner(new File("bank_actions.text"));

		int balance = 0;

		while (scanner.hasNext()) {
			String action = scanner.next();
			int amount = scanner.nextInt();

			if (action.equals("D")) {
				balance = deposit(balance, amount);
				System.out.println("Balance after deposit of $" + amount + ": " + balance);
			}
			else if (action.equals("W")) {
				balance = withdraw(balance, amount);
				System.out.println("Balance after withdrawal of $" + amount + ": " + balance);
			}
		}
	}	

	public static int deposit(int balance, int amount) {return balance + amount;}
	public static int withdraw(int balance, int amount) {
		if (balance >= amount) 
			return balance - amount;
		else
			return balance;
	}
}

Notes

Summary

Some Things to Think About

Modelling Things with Several (Logically-Related) Elements: A Container (02-Container)

Write an app that reads values from a file and places them into a container, i.e., a data entity that contains other items of data. The methods to be provided are:

import java.io.File;
import java.util.Scanner;

class Container {
	public static void main(String [] args) throws Exception {
		final int CAPACITY = 100;
		int [] values = new int[CAPACITY];
		int size = 0;

		Scanner scanner = new Scanner(new File("container_actions.text"));

		while (scanner.hasNext()) {
			String action = scanner.next();
			int value;
			int index;

			switch (action) {
				case "A":
					value = scanner.nextInt();
					size = add(values, size, value); 
					System.out.print("After adding " + value + ": ");
					print(values, size);
					System.out.println();
					break;

				case "F":
					value = scanner.nextInt();
					int pos = find(values, size, value);
					if (pos >= 0) 
						System.out.println(value + " is at position " + pos + " of the container");
					else
						System.out.println(value + " is not in the container");
					break;

				case "G":
					index = scanner.nextInt();
					value = get(values, size, index);
					System.out.println("The value at location " + index + " is " + value);
					break;

				default:
					System.out.println("*** Error *** unknown action: " + action);
			}
		}
	}	
	
	public static int add(int [] values, int size, int value) {
		values[size] = value;
		size++;
		return size;
	}

	public static int size(int [] values, int size) {return size;}

	public static boolean isEmpty(int [] values, int size) {return size(values, size) == 0;}

	public static int find(int [] values, int size, int value) {
		for (int i = 0; i < size; i++)
			if (values[i] == value) return i;
		return -1;
	}

	public static int get(int [] values, int size, int index) {
		return values[index];
	}

	public static void print(int [] values, int size) {
		System.out.print("{");
		for (int i = 0; i < size; i++)
			System.out.print(values[i] + (i < size-1 ? ", " : ""));
		System.out.print("}");
	}
}
Notes

Summary

Modelling Related and Hierarchical Things: Points, Lines & Line Pairs (03 Points, Lines, Line Pairs)

Some supporting documentation

Points (Points)

Model a point in 2-dimensional space (i.e., the 2D plane). A point is represented as a pair of values (we'll stick with integers … at least for now) representing the x and y components of the point.

We will support the methods:

import java.io.*;
import java.util.*;

public class Point {
	public static void main(String [] args) throws Exception {
		Scanner scanner = new Scanner(new File("points.data"));

		System.out.println(" --- From the file");
		System.out.println();

		while (scanner.hasNextInt()) {
			int 
				x = scanner.nextInt(),
				y = scanner.nextInt();
			doIt(x, y);
		}

		Random r = new Random(12345);

		System.out.println();
		System.out.println(" --- Some random points between 0 and 9");
		System.out.println();

		for (int i = 1; i <= 20; i++) {
			int 
				x = r.nextInt(19)-9,
				y = r.nextInt(19)-9;
			doIt(x, y);
		}
	}


	public static void doIt(int x, int y) throws Exception{
		System.out.println(x + " " + y);

		System.out.println("Quadrant: " + quadrantStr(x, y) + " (" + quadrant(x, y) + ")");
	}

	public static String quadrantStr(int x, int y) {
		switch (quadrant(x, y)) {
			case 0: return "Origin";
			case 1: return "Quadrant 1"; 
			case 2: return "Quadrant 2";
			case 3: return "Quadrant 3"; 
			case 4: return "Quadrant 4"; 
			case 5: return "Positive x axis"; 
			case 6: return "Positive y axis"; 
			case 7: return "Negative x axis"; 
			case 8: return "Negative y axis"; 
			default: return "???";
		}
	}
			
	public static int quadrant(int x, int y) {
		if (x == 0 && y == 0) return 0;
		if (x > 0 && y > 0) return 1;
		if (x < 0 && y > 0) return 2;
		if (x < 0 && y < 0) return 3;
		if (x > 0 && y < 0) return 4;
		if (x > 0 && y == 0) return 5;
		if (x == 0 && y > 0) return 6;
		if (x < 0 && y == 0) return 7;
		if (x == 0 && y < 0) return 8;
		return -1;
	}
}

Notes

Lines (Lines)

Model a line in 2-dimensional space (i.e., the 2D plane). A line is represented as two pair of values (i.e., points)

We will support the methods:

As usual, main reads in lines and demos the methods; the only difference here is the slope is only printed when the line has a slope; otherwise Vertical line, has no slope is printed.

import java.io.*;
import java.util.*;

public class Line {
	public static void main(String [] args) throws Exception {
		Scanner scanner = new Scanner(new File("lines.data"));

		while (scanner.hasNextInt()) {
			int 
				x1 = scanner.nextInt(),
				y1 = scanner.nextInt(),
				x2 = scanner.nextInt(),
				y2 = scanner.nextInt();
			doIt(x1, y1, x2, y2);
		}
		
		Random r = new Random(12345);

		System.out.println();
		System.out.println(" --- Some random points between 0 and 9");
		System.out.println();

		for (int i = 1; i <= 20; i++) {
			int 
				x1 = r.nextInt(19)-9,
				y1 = r.nextInt(19)-9,
				x2 = r.nextInt(19)-9,
				y2 = r.nextInt(19)-9;
			doIt(x1, y1, x2, y2);
		}
	}

	public static void doIt(int x1, int y1, int x2, int y2) throws Exception {
		System.out.println("(" + x1 + ", " + y1 + ") - (" + x2 + ", " + y2 + ")");

		printQuadrantInfo(x1, y1);
		printQuadrantInfo(x2, y2);

		System.out.println("The length of the line is: " + length(x1, y1, x2, y2));
		if (isVertical(x1, y1, x2, y2))
			System.out.println("Vertical line, no slope");
		else
			System.out.println("The slope of the line is: " + slope(x1, y1, x2, y2));
		System.out.println();
	}

	public static void printQuadrantInfo(int x, int y) {
		System.out.println("(" + x + ", " + y + ") Quadrant: " + quadrantStr(x, y) + " (" + quadrant(x, y) + ")");
	}

	public static String quadrantStr(int x, int y) {
		switch (quadrant(x, y)) {
			case 0: return "Origin";
			case 1: return "Quadrant 1"; 
			case 2: return "Quadrant 2";
			case 3: return "Quadrant 3"; 
			case 4: return "Quadrant 4"; 
			case 5: return "Positive x axis"; 
			case 6: return "Positive y axis"; 
			case 7: return "Negative x axis"; 
			case 8: return "Negative y axis"; 
			default: return "???";
		}
	}
			
	public static int quadrant(int x, int y) {
		if (x == 0 && y == 0) return 0;
		if (x > 0 && y > 0) return 1;
		if (x < 0 && y > 0) return 2;
		if (x < 0 && y < 0) return 3;
		if (x > 0 && y < 0) return 4;
		if (x > 0 && y == 0) return 5;
		if (x == 0 && y > 0) return 6;
		if (x < 0 && y == 0) return 7;
		if (x == 0 && y < 0) return 8;
		return -1;
	}


	public static double length(int x1, int y1, int x2, int y2) {return Math.sqrt((Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)));}
	public static boolean isVertical(int x1, int y1, int x2, int y2) {return x1 == x2;}
	public static double slope(int x1, int y1, int x2, int y2) {return (y2 - y1) / (double)(x2 - x1);}
}

Notes

Line Pairs(Line Pair)

Model a pair of lines in 2-dimensional space (i.e., the 2D plane). A pair of lines line is represented as four pair of values (i.e., two lines of two endpoints)

We will support the methods:

Again, main reads in the values, and illustrates the methods.

import java.io.*;
import java.util.*;

public class LinePair {
	public static void main(String [] args) throws Exception {
		Scanner scanner = new Scanner(new File("line_pairs.data"));

		while (scanner.hasNextInt()) {
			int 
				x11 = scanner.nextInt(),
				y11 = scanner.nextInt(),
				x12 = scanner.nextInt(),
				y12 = scanner.nextInt(),
		
				x21 = scanner.nextInt(),
				y21 = scanner.nextInt(),
				x22 = scanner.nextInt(),
				y22 = scanner.nextInt();
			doIt(x11, y11, x12, y12, x21, y21, x22, y22);
		}
	}
	
	public static void doIt(int x11, int y11, int x12, int y12, int x21, int y21, int x22, int y22) throws Exception {
		System.out.println("(" + x11 + ", " + y11 + ") - (" + x12 + ", " + y12 + ")" + " / " + 
						"(" + x21 + ", " + y21 + ") - (" + x22 + ", " + y22 + ")");

		printQuadrantInfo(x11, y11);
		printQuadrantInfo(x12, y12);
		printQuadrantInfo(x21, y21);
		printQuadrantInfo(x22, y22);

		System.out.println("The length of the first line is: " + length(x11, y11, x12, y12));
		System.out.println("The length of the second line is: " + length(x21, y21, x22, y22));
		double m1 = slope(x11, y11, x12, y12);
		double m2 =  slope(x21, y21, x22, y22);
		System.out.println("The slope of the first line is: " + m1);
		System.out.println("The slope of the second line is: " + m2);
		if (isParallel(x11, y11, x12, y12, x21, y21, x22, y22)) System.out.println("The two lines are parallel");
		else if (isPerpendicular(x11, y11, x12, y12, x21, y21, x22, y22)) System.out.println("The two lines are perpendicular");
		System.out.println();
	}

	public static void printQuadrantInfo(int x, int y) {
		System.out.println("(" + x + ", " + y + ") Quadrant: " + quadrantStr(x, y) + " (" + quadrant(x, y) + ")");
	}

	public static String quadrantStr(int x, int y) {
		switch (quadrant(x, y)) {
			case 0: return "Origin";
			case 1: return "Quadrant 1"; 
			case 2: return "Quadrant 2";
			case 3: return "Quadrant 3"; 
			case 4: return "Quadrant 4"; 
			case 5: return "Positive x axis"; 
			case 6: return "Positive y axis"; 
			case 7: return "Negative x axis"; 
			case 8: return "Negative y axis"; 
			default: return "???";
		}
	}
			
	public static int quadrant(int x, int y) {
		if (x == 0 && y == 0) return 0;
		if (x > 0 && y > 0) return 1;
		if (x < 0 && y > 0) return 2;
		if (x < 0 && y < 0) return 3;
		if (x > 0 && y < 0) return 4;
		if (x > 0 && y == 0) return 5;
		if (x == 0 && y > 0) return 6;
		if (x < 0 && y == 0) return 7;
		if (x == 0 && y < 0) return 8;
		return -1;
	}


	public static double length(int x1, int y1, int x2, int y2) {return Math.sqrt((Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)));}
	public static double slope(int x1, int y1, int x2, int y2) {return (y2 - y1) / (x2 - x1);}
	public static boolean isParallel(int x11, int y11, int x12, int y12, int x21, int y21, int x22, int y22) {return slope(x11, y11, x12, y12) == slope(x21, y21, x22, y22);}
	public static boolean isPerpendicular(int x11, int y11, int x12, int y12, int x21, int y21, int x22, int y22) {return slope(x11, y11, x12, y12) == -1/slope(x21, y21, x22, y22);}
}

Modelling Many Thing with Many Elements: Phonebook (Phonebook)

Given the file, "phonebook.text" containing phone entries in the format last-name phone-number, write an application that allows the user to look up a phone number via the last name. You can assume no two entries have the same last name.

Sample Test Run

For example if the file phonebook.text cntains:

Arnow       123-456-7890
Harrow      234-567-8901
Jones       345-678-9012
Augenstein  456-789-0123
Sokol       567-890-1234
Tenenbaum   678-901-2345
Weiss       789-012-3456
Cox         890-123-4567
Langsam     901-234-5678
Thurm       012-345-6789

here is a sample execution of the program:

name? Weiss
789-012-3456
name? Arnow
123-456-7890
name? Washington
Not found
name? Jones
345-678-9012
name? Thrum
Not found
name? Thurm
012-345-6789
name?

import java.io.*;
import java.util.*;

public class Phonebook {
	public static void main(String [] args) throws Exception {
		final String FILENAME = "phonebook.text";
		final int CAPACITY = 100;

		String [] 
			names = new String[CAPACITY],
			numbers = new String[CAPACITY];

		int size = read(FILENAME, names, numbers, CAPACITY);

		Scanner scanner = new Scanner(System.in);

		System.out.print("name? ");
		while (scanner.hasNext()) {
			String name = scanner.next();
			String number = lookup(names, numbers, size, name);
			if (!number.equals("")) 
				System.out.println(number);
			else
				System.out.println("Not found");
			System.out.print("name? ");
		}
	}

	static int read(String filename, String [] names, String [] numbers, int capacity) throws IOException {
		Scanner scanner = new Scanner(new File(filename));

		int size = 0;
		while (scanner.hasNext()) {
			if (size == capacity) {
				System.out.println("Phonebook capacity exceeded - increase size of underlying array");
				System.exit(1);
			}
			names[size] = scanner.next();
			numbers[size] = scanner.next();
			size++;
		}
		return size;
	}

	static String lookup(String [] names, String [] numbers, int size, String name) {
		for (int i = 0; i < size; i++)
			if (names[i].equals(name)) return numbers[i];
		return "";
	}
}
Notes

An Even More Extreme Case: Student Grading

Program 14.3

Write a program that reads in student data from a data file (whose name should be obtained from the user) consisting of last name, first name, midterm, and final. The program calculates each student's average, and grade, and prints out a roster consisting of all the information, together with whether the student performed above or below the class average.

The program should define the following methods:

import java.io.*;
import java.util.*;

public class Program_14_3 {
   public static void main(String [] args) throws Exception {
      Scanner keyboard = new Scanner(System.in);    
      
      System.out.print("roster file? ");
      String filename = keyboard.next();
      
      final int CAPACITY = 100;
      
      String [] 
         lastNames = new String[CAPACITY],
         firstNames = new String[CAPACITY];
      
      int [] 
         midterms = new int[CAPACITY],
         finals = new int[CAPACITY];
      
      double [] averages = new double[CAPACITY];
      
      char [] grades = new char[CAPACITY];
      
      int size = read(filename, lastNames, firstNames, midterms, finals, CAPACITY);
      
      calculateAverages(midterms, finals, averages, size);
      
      double classAverage = calculateClassAverage(averages, size);
      
      calculateGrades(averages, grades, size);
      
      printRoster(lastNames, firstNames, averages, grades, classAverage, size);
   }
   
   public static int read(String filename, String [] lastNames, String [] firstNames,
                          int [] midterms, int [] finals, int capacity) throws Exception {
      Scanner scanner = new Scanner(new File(filename));
      
      int size = 0;
      
      while (scanner.hasNext()) {
         if (size >= capacity) {
            System.out.print("Reached array capacity and still more data. Make the array bigger");
            System.exit(1);
         }
         lastNames[size] = scanner.next();
         firstNames[size] = scanner.next();
         midterms[size] = scanner.nextInt();
         finals[size] = scanner.nextInt();
         size++;
      }
      return size;
   }
      
   public static void calculateAverages(int [] midterms, int [] finals, double [] averages, int size) {
      for (int i = 0; i < size; i++)
         averages[i] = calculateOneAverage(midterms[i], finals[i]);
   }
      
   public static double calculateOneAverage(int midterm, int finalExam) {return (midterm + finalExam)/2.0;}
   
   public static double calculateClassAverage(double [] averages, int size) {
      double total = 0;
      for (int i = 0; i < size; i++)
         total += averages[i];
      return total / size;
   }

   public static void calculateGrades(double [] averages, char [] grades, int size) {
      for (int i = 0; i < size; i++)
         grades[i] = calculateOneGrade(averages[i]);
   }
   
   public static char calculateOneGrade(double average) {
      return average >= 90 ? 'A' : average >= 80 ? 'B' : average >= 70 ? 'C' : average >= 60 ? 'D' : 'F';
   }
   
   public static void printRoster(String [] lastNames, String [] firstNames, double [] averages, 
                                  char [] grades, double classAverage, int size) {
      for (int i = 0; i < size; i++)
         printOneStudent(lastNames[i], firstNames[i], averages[i], grades[i], classAverage);
   }
   
   public static void printOneStudent(String lastName, String firstName, double average, 
                                      char grade, double classAverage) {
      System.out.println(lastName + " " + firstName + " " + average + " " + grade + " " +
                       (average >= classAverage ? "Above" : "Below"));
  }
}