# Introduction to Computer Science

## Summary of 11/13 Lecture

Review of 11-8 Lab Results; more on drawing; introduction to arrays or lists; subscripts or indexes; the NumberList class; (7.1, 7.2)

### Review of 11-8 Lab Results

We had three lab exercises on 11-8:

11-8 Lab Exercise 1.  Rewrite Circles2.java so that the circles change color randomly each time the "new Circle" button is pushed.

11-8 Lab Exercise 2.  Change the animations in Surprise2.java so that the circle grows larger and then grows smaller and disappears.  Spend some time on this one.

11-8 Lab Exercise 3.  Change the animations in Surprise3.java so that as the circle grows larger and then grows smaller and disappears, a label is applied which says "Small", "Medium", "Large", "XL", "XXL", as appropriate.  Hint: it can help to use an array. Spend some time on this one.

The key to doing exercise 1 is to combine the random number generator with a call to Color with random arguments in the range of 0-255, or to use a random selection from an array of colors. Let us look at the second option.

The standard colors we can use in java are:

black, blue, cyan, darkGray, gray, green, lightGray, magenta, orange, pink, red, white and yellow for 13 colors in all. However, with a white background, a white circle would vanish, so we only use 12. //File: Circles3.java
//The following packages are necessary for any applet
import java.applet.*;
import java.awt.*;

//The following package is necessary if we are to have
//an interactive applet, one that responds to events
import java.awt.event.*;

public class Circles3 extends Applet implements ActionListener
{
Button circleButton = new Button("New Circle");

public void init()
{
setBackground (Color.white);
}

//The paint() method is called by the browser
// whenever the applet must be redrawn
public void paint (Graphics g)
{
// Add an array for random colors
Color [] myColors =
{ Color.black, Color.blue, Color.cyan,
Color.darkGray, Color.gray, Color.green,
Color.lightGray, Color.magenta, Color.orange,
Color.pink, Color.red, Color.yellow };

Dimension d=getSize();
int w=d.width;
int h=d.height;

x = (int) (w * Math.random());
y = (int) (h * Math.random());

// Set the color to one of the random colors
g.setColor (myColors[((int)(12*Math.random()))%12]);
}

//The actionPerformed() method from the ActionListener interface must be implemented
public void actionPerformed (ActionEvent event)
{
//Here is where the ActionListener components respond to events
repaint(); //calls update()
}
public void update (Graphics g)
{
//Our update doesn't clear the window first
paint(g);
}
}

The answers to the other two exercises build on each other. We will only examine the combined answer:

//File: Surprise4.java import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class Surprise4 extends Applet
{
//Exploding and imploding balloons
//With Small, Medium, Large, .. added

public void init()
{
setBackground (Color.white);
}

public void paint (Graphics g)
{
String [] size_labels = {
" Small ", "Medium", "Large", "XL", "XXL" };
// Note the extra blanks on Small
Dimension size = getSize();
int size_bin; // Added index for size_labels

int diameter = 0,
w = size.width,
h = size.height,
cmin = (int)Math.min(w, h);

// g.setColor(Color.yellow); // was here
while (diameter < cmin)
{
int ws, hf; // needed to position labels
Font current; // note the different style
FontMetrics metrics; // when we do this later

g.setColor(Color.yellow); //now here
g.fillOval((w-diameter)/2, (h-diameter)/2,
diameter, diameter);
// Note it is important to do this
size_bin = (5*diameter)/cmin;
// Before this
diameter++;

// Added code for the size labels
current = getFont();
metrics = getFontMetrics (current);
ws = metrics.stringWidth(size_labels[size_bin]);
hf = metrics.getHeight();

g.setColor(Color.blue);
g.drawString(size_labels[size_bin],
(w-ws)/2, (h+hf)/2);

try
{
Thread.sleep(10); // sleep for 10 msec
}
catch (InterruptedException t)
{
}
}

g.setColor(Color.yellow); //need to draw oval again
//to overwrite old labels
g.fillOval((w-diameter)/2, (h-diameter)/2,
diameter, diameter);
Font current = getFont();
FontMetrics metrics = getFontMetrics (current);
int ws = metrics.stringWidth("Surprise!");
int hf = metrics.getHeight();

g.setColor(Color.red);
g.drawString("Surprise!", (w-ws)/2, (h+hf)/2);

try
{
Thread.sleep(1000); // sleep for 1 sec
}
catch (InterruptedException t)
{
}

while (diameter > 1)
{
//The following draws circles in yellow,
//pauses, then redraws them in white (the background color),
//thus effectively erasing them. It then changes the color
//back to yellow and repeats the process for a circle
//of diameter one less than the previous one.

//Note that we have to rewrite the labels in white
//or medium will show behind small

// int ws, hf; // already declared above
// Font current;
// FontMetrics metrics;

g.setColor(Color.yellow);
g.fillOval((w-diameter)/2, (h-diameter)/2,
diameter, diameter);
// Note the -1
size_bin = (5*(diameter-1))/cmin;

// Added code for the size labels again
current = getFont();
metrics = getFontMetrics (current);
ws = metrics.stringWidth(size_labels[size_bin]);
hf = metrics.getHeight();

g.setColor(Color.blue);
g.drawString(size_labels[size_bin],
(w-ws)/2, (h+hf)/2);
try
{
Thread.sleep(10); // sleep for 10 msec
}
catch (InterruptedException t)
{
}

g.setColor (Color.white);
g.fillOval((w-diameter)/2, (h-diameter)/2,
diameter, diameter);
g.drawString(size_labels[size_bin],
(w-ws)/2, (h+hf)/2);

diameter--;

}

repaint(); //calls update() which CLEARS THE WINDOW,
//then calls paint()
}
}

### More on Drawing

Java has solid basic drawing capabilities defined in the Graphics class. Let us look at an applet to draw a crude expanding head instead of a balloon to understand some of the graphics methods and see two problems: image flicker caused by partial updates and the non-intuitive coordinate system used.

import java.awt.event.*;
import java.applet.*;

public class Head extends Applet {
//Surprise with an exploding balloon
// Author: rachel McDermott, September 27, 1996
// H. J. Bernstein, 11 November 2001

public void init() {
setBackground (Color.white);
}

public void paint (Graphics g) {
Dimension size = getSize();
int diameter = 0,
cx = size.width,
cy = size.height,
cmin = (int)(.8*Math.min(cx, cy));
// note: we adjust the size of the
// head to leave room for the ears

while (diameter < cmin) {

// Draw hair
g.setColor(Color.red);
g.fillOval(cx/2-diameter/6,(cy+diameter)/2-diameter/6,
diameter/3, diameter/3);

g.setColor(Color.yellow);
g.fillOval((cx-diameter)/2, (cy-diameter)/2,
diameter, diameter);

// Draw two ears

g.fillOval((cx-diameter)/2-diameter/10,cy/2-diameter/8,
diameter/5,diameter/4);
g.fillOval((cx+diameter)/2-diameter/10,cy/2-diameter/8,
diameter/5,diameter/4);

// Draw brow line and smile

g.setColor(Color.blue);
g.drawArc((cx-3*diameter/4)/2,(cy-3*diameter/4)/2,
3*diameter/4,3*diameter/4, 50, 80);
g.drawArc((cx-3*diameter/4)/2,(cy-3*diameter/4)/2,
3*diameter/4,3*diameter/4, -50, -80);

// Now draw two eyes
g.setColor(Color.blue);
g.drawOval((cx-3*diameter/8-diameter/5)/2,(cy-diameter/10)/2,
diameter/5,diameter/10);
g.fillOval((cx-3*diameter/8-diameter/10)/2,(cy-diameter/10)/2,
diameter/10,diameter/10);
g.drawOval((cx+3*diameter/8-diameter/5)/2,(cy-diameter/10)/2,
diameter/5,diameter/10);
g.fillOval((cx+3*diameter/8-diameter/10)/2,(cy-diameter/10)/2,
diameter/10,diameter/10);

diameter++;
try {
Thread.sleep(20); // sleep for 20 msec
} catch (InterruptedException t){}
}

Font current = getFont();
FontMetrics metrics = getFontMetrics (current);
int ws = metrics.stringWidth("Surprise!");
int hf = metrics.getHeight();

g.setColor(Color.red);
g.drawString("Surprise!", (cx-ws)/2, (cy+hf)/2);
try {
Thread.sleep(1000); // sleep or 1 sec
} catch (InterruptedException t) {}
repaint();
}
}

The hair has been drawn as a beard. That is because java uses a default coordinate system which is upside-down compared to the one commonly used in when laying out drawings by hand or drawing graphics in a physics class. The point with the coordinates (0,0) is at the top left and increasing y-coordinates go down the screen. This arises from the natural conflict between laying out images, for which it is common to place (0,0) at the bottom left corner, and laying out text, in which the first character of the first line is normally placed at the top left. Unless we introduce special transformations, when writing java, we have to use the text-oriented convention.

On most computers, the applet will show a disturbing flicker of partially drawn images. In the next applet, we cure the inverted image by changing a + to a -, and we cure the flicker by drawing using a Graphics object in memory and then transferring all the pixels at once to the displayed Graphics object:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.applet.*;

public class BufferedHead extends Applet {
//Surprise with an exploding balloon
// Author: rachel McDermott, September 27, 1996
//Modified to use an off-screen buffer
// H. J. Bernstein, 11 November 2001

public void init() {
setBackground(Color.white);
}

public void paint (Graphics g_real) {
Image image_g;
Graphics g;
Dimension size = getSize();
int diameter = 0,
cx = size.width,
cy = size.height,
cmin = (int)(.8*Math.min(cx, cy));
// note: we adjust the size of the
// head to leave room for the ears

image_g = createImage(cx,cy);
g = image_g.getGraphics();

while (diameter < cmin) {

// Draw hair
g.setColor(Color.red);
g.fillOval(cx/2-diameter/6,(cy-diameter)/2-diameter/6,
diameter/3, diameter/3);

g.setColor(Color.yellow);
g.fillOval((cx-diameter)/2, (cy-diameter)/2,
diameter, diameter);

// Draw two ears

g.fillOval((cx-diameter)/2-diameter/10,cy/2-diameter/8,
diameter/5,diameter/4);
g.fillOval((cx+diameter)/2-diameter/10,cy/2-diameter/8,
diameter/5,diameter/4);

// Draw brow line and smile

g.setColor(Color.blue);
g.drawArc((cx-3*diameter/4)/2,(cy-3*diameter/4)/2,
3*diameter/4,3*diameter/4, 50, 80);
g.drawArc((cx-3*diameter/4)/2,(cy-3*diameter/4)/2,
3*diameter/4,3*diameter/4, -50, -80);

// Now draw two eyes
g.setColor(Color.blue);
g.drawOval((cx-3*diameter/8-diameter/5)/2,(cy-diameter/10)/2,
diameter/5,diameter/10);
g.fillOval((cx-3*diameter/8-diameter/10)/2,(cy-diameter/10)/2,
diameter/10,diameter/10);
g.drawOval((cx+3*diameter/8-diameter/5)/2,(cy-diameter/10)/2,
diameter/5,diameter/10);
g.fillOval((cx+3*diameter/8-diameter/10)/2,(cy-diameter/10)/2,
diameter/10,diameter/10);
g_real.drawImage(image_g,0,0,this);
diameter++;
try {
Thread.sleep(20);   // sleep for 20 msec
} catch (InterruptedException t){}
}

Font current = getFont();
FontMetrics metrics = getFontMetrics (current);
int ws = metrics.stringWidth("Surprise!");
int hf = metrics.getHeight();

g.setColor(Color.red);
g.drawString("Surprise!", (cx-ws)/2, (cy+hf)/2);
g_real.drawImage(image_g,0,0,this);
try {
Thread.sleep(1000); // sleep or 1 sec
} catch (InterruptedException t) {}
repaint();
}
}

### Arrays

We began with a motivational example.  Suppose you want to calculate the average of a list of numbers (int or double) followed by a calculation of the standard deviation.  You quickly realize that by the time you're ready to do the standard deviation, you only have access to the last number in the list.  The solution is provided by arrays since they allow you to name a collection of memory locations with one identifier.  Subscripts or indexes then allow you to access each individual memory location.  The following example illustrates this.

//File:    NumberList.java
//This class will gather together in one place
//functions (or methods) which process lists of
//numbers (int or double).

import iostuff.*;
public class NumberList
{
//The following two methods calculate the average of a list
//of int's or double's respectively
public static int average (int [] a)
{
int sum=0;
for (int k=0; k<a.length; k++)
{
sum = sum + a [k];
}
return sum/a.length;
}

public static double average (double [] a)
{
double sum=0;
for (int k=0; k<a.length; k++)
{
sum = sum + a [k];
}
return sum/a.length;
}
}

//File:    Average.java
import NumberList;
import iostuff.*;
import java.text.DecimalFormat;
public class Average
{
public static void main (String [] args)
{
double number [];

System.out.print ("How many numbers? ");

number = new double [n];

//inputs the numbers into the array
for
(int k=0; k<n; k++)
{
}

//The following code displays the list to the screen
for (int k=0; k<number.length; k++)
{
System.out.println (number[k]);
}
System.out.println();

double avg = NumberList.average(number);

DecimalFormat output = new DecimalFormat("0.00");
System.out.println ("The average is: " + output.format(avg));
}
}

Note that arrays "know" their length.  That is, it is not necessary to pass the number of items as a parameter to any of the methods in NumberList.   Instead, when that information is required, the length of the array is retrieved from the array itself; e.g., a.length or number.length.

Lab Exercise 1.  Add a method that displays a list of int's to the NumberList class.  The signature for the method will look like:

public static void display (int [] a)

HINT:  This method should incorporate the section of Average.java (above) that "displays the list to the screen".

Lab Exercise 2.  Add a method that calculates the standard deviation of a list of int's to the NumberList class.  The signature for the method will look like:

public static int sd (int [] a, int average)

Feel free to consult Prof. Steinmetz's version if you get exasperated.

Adapted from Bill Steinmetz's course summary by H. J. Bernstein, 12 Nov 01