Spring Semester 2002


Lecture Notes Thirteen: More practice with loops. Loops, tokenizers, and Monte Carlo problems.
Do you like loops? I don't know: so far, so good.

Now we need to move on. First a few simple, basic exercises.

Can you explain this? I sure can.
frilled.cs.indiana.edu%cat Two.java
class Two {
    public static void main(String[] args) {
	for (int i = 0; i < 10; i++) {
	    System.out.print(i); 
	}
	i = 10; 
	System.out.println(i); 
    }
}
frilled.cs.indiana.edu%javac Two.java
Two.java:6: Undefined variable: i
	i = 10; 
	^
Two.java:7: Undefined variable: i
	System.out.println(i); 
	                   ^
2 errors
frilled.cs.indiana.edu%

Can you fix it? I sure can.
frilled.cs.indiana.edu%cat Two.java
class Two {
    public static void main(String[] args) {
	int i; 
	for (i = 0; i < 10; i++) {
	    System.out.print(i); 
	}
	i = 10; 
	System.out.println(i); 
    }
}
frilled.cs.indiana.edu%javac Two.java
frilled.cs.indiana.edu%java Two
012345678910
frilled.cs.indiana.edu%

How do you call that? I'd say: scope of a variable.
frilled.cs.indiana.edu%webster scope
scope \'sko^-p\ n
[It scopo purpose, goal, fr. Gk skopos; akin to Gk skeptesthai to
     watch, look at -- more at SPY]
(1555)
1: space or opportunity for unhampered motion, activity, or thought
2: INTENTION, OBJECT
3: extent of treatment, activity, or influence
4: range of operation
syn see RANGE 

frilled.cs.indiana.edu%
Sounds good. It's the range of operation for that variable.

Take a look at this: It doesn't compile!
class Wow {
    public static void main(String[] args) {
	{
	    int i; 
	    i = 3; 
	    System.out.println(i); 
	}
	System.out.println(i); 
    }
}

Why? The curly braces!

Indeed, they are defining the scope. And they do it in the same way for:
  • classes
  • if statements
  • for loops
  • while loops

As well as other kinds of loops. There's just one more, as we will see below.

In any event, having blocks of statements available as standalone entities that can be placed anywhere inside the program can sometimes be a source of confusion for the beggining Java programmer. Let me see some examples.

Here's one: That is not a source of any confusion!
frilled.cs.indiana.edu%cat Wow.java
class Wow {
    public static void main(String[] args) {
	int x = 1; 
	if (x > 2) {
	    System.out.println("Yes, " + x + " is greater than 2."); 
	}
    }
}
frilled.cs.indiana.edu%javac Wow.java
frilled.cs.indiana.edu%java Wow
frilled.cs.indiana.edu%

I know, but consider this: Ah, I see the semicolon!
frilled.cs.indiana.edu%cat Wow.java
class Wow {
    public static void main(String[] args) {
	int x = 1; 
	if (x > 2) ; {
	    System.out.println("Yes, " + x + " is greater than 2."); 
	}
    }
}
frilled.cs.indiana.edu%javac Wow.java
frilled.cs.indiana.edu%java Wow
Yes, 1 is greater than 2.
frilled.cs.indiana.edu%
I hope you do. That is an if with an empty body.

That's how we got an infinite loop last time. There's one thing to be learned from this.

Syntax rules. And people who use it properly, rock!

Let's look at other kind of loops. OK, here's a program that talks to the user.
frilled.cs.indiana.edu%cat Three.java
class Three {
    public static void main(String[] args) {
	ConsoleReader c = new ConsoleReader(System.in); 
	String line; 
	do {
	    System.out.print("Type something: "); 
	    line = c.readLine(); 
	    System.out.println("You typed: " + line); 
	} while (! line.equals("bye"));  
	System.out.println("Good bye!"); 
    } 
}
frilled.cs.indiana.edu%javac Three.java
frilled.cs.indiana.edu%java Three
Type something: I am here
You typed: I am here
Type something: You are there
You typed: You are there
Type something: Your name is Echo
You typed: Your name is Echo
Type something: Bye
You typed: Bye
Type something: bye
You typed: bye
Good bye!
frilled.cs.indiana.edu%

Using while is just a bit longer. Yes, since the test comes first.
frilled.cs.indiana.edu%cat Three.java
class Three {
    public static void main(String[] args) {
	ConsoleReader c = new ConsoleReader(System.in); 
	String line; 
	System.out.print("Type something: ");
	line = c.readLine();
	System.out.println("You typed: " + line);
        while (! line.equals("bye")) { 
	    System.out.print("Type something: "); 
	    line = c.readLine(); 
	    System.out.println("You typed: " + line); 
	}	
	System.out.println("Good bye!"); 
    } 
}
frilled.cs.indiana.edu%javac Three.java
frilled.cs.indiana.edu%java Three
Type something: Works the same, doesn't it?
You typed: Works the same, doesn't it?
Type something: It does seem so. 
You typed: It does seem so. 
Type something: I am happy. 
You typed: I am happy. 
Type something: BYe
You typed: BYe
Type something: byE
You typed: byE
Type something: bye
You typed: bye
Good bye!
frilled.cs.indiana.edu%

In both cases we work with whole loops. Yes, we know we're done either at the beginning or at the end of the loop's body of statements.

Sometimes we'd like to allow for being able to realize we're done halfway through the loop. And end your processing in mid-loop? Doesn't this coding situation have a specific name?

Yes, it's called the loop and a half problem. Very good. Here's an example: A program that reads lines from a file, then reverses them.
frilled.cs.indiana.edu%cat Four.java
class Four {
    public static void main(String[] args) {
	ConsoleReader c = new ConsoleReader(System.in); 
	boolean done = false; 
	String line; 
	while (! done) {
	    System.out.print("Echo> "); 
	    line = c.readLine(); 
	    if (line == null) { // EOF or ctrl-D for that
		done = true; 
	    } else {
		System.out.println(line); 
	    } 
	} 
    } 
} 
frilled.cs.indiana.edu%javac Four.java
frilled.cs.indiana.edu%java Four
Echo> Hello!
Hello!
Echo> I am here.
I am here.
Echo> How are you?
How are you?
Echo> I am fine, how about you?
I am fine, how about you?
Echo> You don't say...
You don't say...
Echo> I am going to type control-D now
I am going to type control-D now
Echo> Bye!
Bye!
Echo> frilled.cs.indiana.edu%
Where's the file? You can pipe one into your program! (See your friendly TA or check with the book on pages 248 and 241 for more details).

Alright. So we read lines, one by one. When the line we read is empty there's nothing to be reversed. So the program simply quits the loop. Oh, I see: and we skip the lower half of the loop.

Indeed, at that point we simply quit it. How do you do that?

One can do that with break (page 242), or... ... using a boolean variable, and an if statement.

We choose the second approach, because one can argue it's a bit more structured. But the first one is also often used, and it greatly simplifies code on occasion.

So now we have a basic echo program. Yes, but as of right now nothing is being reversed. Wasn't that what we set out to do?

OK, let's make this more exciting, as if through a looking glass. Yes, s'tel esrever sretcarahc ni sdrow!

Well, yletanutrofnu ew t'nac od taht. ?neht ,elbissop si siht spahrep tuB

That, we can do.
frilled.cs.indiana.edu%cat Four.java
class Four {
    public static void main(String[] args) {
	ConsoleReader c = new ConsoleReader(System.in); 
	boolean done = false; 
	String line; 
	while (! done) {
	    System.out.print("Echo> "); 
	    line = c.readLine(); 
	    if (line == null) { // EOF or ctrl-D for that
		done = true; 
	    } else {
		String rev = ""; 
		int i; 
		for (i = line.length() - 1; i >= 0; i--) {
		    rev += line.charAt(i);
		}
		System.out.println(rev); 
	    } 
	} 
    } 
} 
frilled.cs.indiana.edu%javac Four.java
frilled.cs.indiana.edu%java Four
Echo> Hello!
!olleH
Echo> I say, that's Spanish.
.hsinapS s'taht ,yas I
Echo> Arabic?
?cibarA
Echo> What's going on, can you please tell me. 
 .em llet esaelp uoy nac ,no gniog s'tahW
Echo> Hmmm... 
 ...mmmH
Echo> :-)
)-:
Echo> ...ees I
I see...
Echo> .ahctoG
Gotcha.
Echo> frilled.cs.indiana.edu%

I like this guy, Gotcha. Once upon a time there was a Polish carpenter, by the name of Zbigniew Gotcha, who lived in Kracow. You know the story?

No. I don't either, but I like the way it starts.

Time to wrap up. Let's do random numbers.

Yes, we kept for dessert. Do you like sherbet?

Let's program the following simulation:
Darts are thrown at random points onto the square with corners (1 ,1) and (-1, -1). If the dart lands inside the unit circle, that is, the circle with center (0, 0) and radius 1 it is a hit. Otherwise it is a miss. Run this simulation to determine an experimental value for the fraction of hits in the total number of attempts, multiplied by 4.
Oh, this is so easy! Easy as !

Fine, if it's easy, why don't you do it first? Relax, here it is:
frilled.cs.indiana.edu%cat Pi.java
import java.util.Random;

public class Pi {
    public static void main(String[] args) {
	Random r = new Random();
	double x, y, d;
	int i, count = 0;
	for (i=0; i < 100000 ; i++) {
	    x = r.nextDouble() * 2 - 1;
	    y = r.nextDouble() * 2 - 1;
	    d = Math.sqrt(x * x + y * y);
	    if (d < 1) count++;
	}
	System.out.println("Pi is approximately " + 4.0 * count / i);
    }
}

frilled.cs.indiana.edu%javac Pi.java
frilled.cs.indiana.edu%java Pi
Pi is approximately 3.13648
frilled.cs.indiana.edu%java Pi
Pi is approximately 3.15064
frilled.cs.indiana.edu%java Pi
Pi is approximately 3.14424
frilled.cs.indiana.edu%java Pi
Pi is approximately 3.1422
frilled.cs.indiana.edu%java Pi
Pi is approximately 3.1438
frilled.cs.indiana.edu%

Can you explain it? The probability of a hit is the fraction that the circle represents of the total area.

It is also close to the ratio of the measured frequencies: hits divided by attempts. So we write the formulas, and the radius simplifies, as it appears on both sides.

But there is a factor of half (1/2) which... ... is squared, so it participates as a fourth (1/4) in the end, and there you have it.

Pretty good. I want to do more problems.

I was hoping you would. I'm in great shape today.

Here's a program that helps with problem 6.1
What does it do?
import java.util.*;
import java.io.*; 

/* pages 239 - 241 and 246 - 250 */ 

class Six {
    public static void main(String[] args) {
	ConsoleReader console = new ConsoleReader(System.in); 
	System.out.print("Hello> "); 
        String line = console.readLine(); 
        while (line != null) { // ^D would do it 
	    StringTokenizer tokenizer = new StringTokenizer(line); 
            while (tokenizer.hasMoreTokens()) {
		String token = tokenizer.nextToken(); 
		System.out.println(token.toUpperCase()); 
	    } 
            System.out.print("Hello> "); 
            line = console.readLine(); // what if we take this out? 
        }
	System.out.println("End of program.");
    } 
} 

Reads lines, one by one. When does it end?

When you type Control-D. Which is EOF (end of file).

Yes, in that case the line is null. What does it do, line by line?

Looks at the tokens, and prints them back, but converted into uppercase. Not much different from the one about Zbigniew, except this one uses this StringTokenizer.

Exactly, that's the main difference. How does that work?

Take a closer look:
StringTokenizer tokenizer = new StringTokenizer(line); 
while (tokenizer.hasMoreTokens()) {
  String token = tokenizer.nextToken(); 
  System.out.println(token.toUpperCase()); 
}
Better look this class up.

It's like a machine gun loaded with words. Or like a stapler, if you don't mind.

A stapler would also be a good analogy. With staples of variable length.

Glued together by blank spaces. Staples are tokens.
frilled.cs.indiana.edu%webster token
to-ken \'to^--ken\ n
[ME, fr. OE ta^-cen, ta^-cn sign, token; akin to OHG zeihhan sign, Gk
     deiknynai to show -- more at DICTION]
(bef. 12c)
1: an outward sign or expression 
2a: SYMBOL, EMBLEM <a white flag is a token of surrender>
2b: an instance of a linguistic expression 
3: a distinguishing feature: CHARACTERISTIC
[...]

frilled.cs.indiana.edu%

For both problem 6.2 and 6.3 the trick is to interpret (read and promptly evaluate) input. I think I can handle that.

You're going to have to read
  • a rate,
  • then numbers,
  • finished by zero...
... then numbers again, ending with EOF.
Which is Control-D (in Unix).

Or some such thing. I could even end it with a keyword, such as "quit" or "bye", or some other meaningful word.

Really, how?
Take a look.
import java.util.*;
import java.io.*; 

class TwoAndThree {
    public static void main(String[] args) {

	ConsoleReader console = new ConsoleReader(System.in); 

	System.out.print("Rate>"); 
	String line = console.readLine(); 

	StringTokenizer tokenizer = new StringTokenizer(line); 
	double rate = Double.parseDouble(tokenizer.nextToken()); 

	double amount; 

	do {

	    System.out.print("Dollars>"); 
	    line = console.readLine(); 

	    tokenizer = new StringTokenizer(line); 

	    amount = Double.parseDouble(tokenizer.nextToken()); 

	} while (amount > 0); 

	do {

	    System.out.print("Euros>"); 
	    line = console.readLine(); 

	    if (line == null || line.equalsIgnoreCase("quit")) 
		break; 

	    tokenizer = new StringTokenizer(line); 

	    amount = Double.parseDouble(tokenizer.nextToken()); 

	} while (true); 
	System.out.println("Thank you for using this program."); 
    } 
} 
This should get you started.

Nice, but I see that you're assuming the user will never type more than one number on a line. So I could get by without a tokenizer. I agree, but I used one for the sake of practice.

I have a larger set of problems for next time. Can't wait. Let's press on with the ones for today. Next one up: problem 6.4, page 263.

There are many ways of solving problem 6.4. Yes, but empathy would not be one of them.

Of course. What I meant was that you need to generate random directions. And you have more than one way to produce random numbers.

Let's use whatever the book uses. It's a good book.

I know. Page 253.

In addition to that, I would like to use an object oriented approach. And bring a drunkard into the picture.

Exactly. A drunkard is like a BankAccount.

I was going to say.
Well, here's how I'd get started.
import java.util.*;

class Drunkard {
    int x, y; 
    Drunkard(int x, int y) {
	this.x = x; 
	this.y = y;
    } 
    void moveNorth() {
	this.y -= 1; 
    }
    void moveEast() {
	this.x += 1; 
    }
    void report() {
	System.out.println("Hiccup: " + x + ", " + y); 
    } 
} 

class Four {
    public static void main(String[] args) {
	Random generator = new Random(); 
	Drunkard drunkard = new Drunkard(100, 100); 
	int direction; 
	for (int i = 0; i < 100; i++) {
	    direction = Math.abs(generator.nextInt()) % 4; 

	    if        (direction == 0) { // N
		drunkard.moveNorth();

	    } else if (direction == 1) { // E
		drunkard.moveEast(); 

	    } else if (direction == 2) { // S
		System.out.println("Should move South."); 

	    } else if (direction == 3) { // W
		System.out.println("Should move West."); 

	    } else {
		System.out.println("Impossible!"); 

	    } 
	    drunkard.report(); 
	} 
    }
} 
Not bad at all. Of course, one needs to finish it first.

Reminds me of homework assignment two. Somewhat. Now let's look at 6.5 and 6.6.

Isn't a cannonball like a drunkard? Yes, they're both tiggers.

They all deal directly with gravitational fields.
Cannonballs require more physics, though.
class Cannonball {
    double x; 
    double y; 
    double vx; 
    double vy;
    final double g = 9.81; 

    Cannonball(double speed, double angle) {
	x = 0; 
	y = 0; 
	vx = Math.cos(angle) * speed; 
	vy = Math.sin(angle) * speed; 
    } 

    void move() {
	double deltaT = 0.01; 
	x += vx * deltaT;
	y += vy * deltaT; 
	vy -= g * deltaT;
    }

    void report() {
	System.out.println("Located at: (" + x + ", " + y + ")"); 
    }

    double height() {
	return y; 
    } 

}

class FiveAndSix {
    public static void main(String[] args) {

	Cannonball c = new Cannonball(10, Math.PI / 4);

	for (int i = 0; i < 10 * 100; i++) { // flying 10 seconds 

	    c.move(); 
	    c.report(); 

	    if (c.height() < 0) {
		System.out.println("SPLOOOF! The cannonball landed!"); 
		break; 
	    } 

	}

    }
} 
Homework assignment one! Almost, only in finer steps.

Could you also compute the highest point that the cannonball gets to? That would almost be problem 16, wouldn't it?

It would. We'd have to update our notion of a current maximum every time we are looking at a height.

Come to think of it the cannonball could do it. Intelligent cannonball.

Intelligent, but misguided. Well, here it is anyway:
class Cannonball {
    double x; 
    double y; 
    double vx; 
    double vy;
    final double g = 9.81; 

    double max; 

    Cannonball(double speed, double angle) {
	x = 0; 
	y = 0; 
	vx = Math.cos(angle) * speed; 
	vy = Math.sin(angle) * speed; 

	max = 0; 

    } 

    void move() {
	double deltaT = 0.01; 
	x += vx * deltaT;
	y += vy * deltaT; 
	vy -= g * deltaT;

	if (y > max) { max = y; } 
    }

    void report() {
	System.out.println("Located at: (" + x + ", " + y + ") "); 

        System.out.println("     max altitude so far: " + max); 

    }

    double height() {
	return y; 
    } 

}

class Max {
    public static void main(String[] args) {

	Cannonball c = new Cannonball(10, Math.PI / 4);

	for (int i = 0; i < 10 * 100; i++) { // flying 10 seconds 

	    c.move(); 
	    c.report(); 

	    if (c.height() < 0) {
		System.out.println("The cannonball landed!"); 
		break; 
	    } 

	}

    }
}

You just added three lines? Four, and yes, that was all.

But how often do those get executed? They're part of the cannonball's movement.

Let's move on to problem 6.7. This one is easy.

Yes, from two values we compute a third. And we keep doing this over and over again. Now only this new value and the most recent of the two it was computed from should be kept.

And these two values are then added to compute a new value. And the whole process is repeated, as follows:
for (int i = 3; i <= n; i++) {    
  fNew = fOld + fOlder; 
  fOlder = fOld; 
  fOld = fNew; 
} 

Yes, that's it. This reminds me of another problem:

What problem is that? See if you can figure it for yourself.
import java.io.*; 

class Mistery {
    public static void main(String[] args) {

	ConsoleReader console = new ConsoleReader(System.in);
	System.out.print("Pass the salt please: "); 
	double a = console.readDouble(); 

	System.out.print("And the butter: "); 
	int n = console.readInt(); 

	double xold, xnew; 
	xold = ... ; 
	do {

	  xnew = xold - (Math.pow(xold, n) - a) / (n * Math.pow(xold, n - 1));
	  xold = xnew; 
	  System.out.println("     " + (Math.pow(xnew, n) - a)); 

	} while (Math.abs(Math.pow(xnew, n) - a) > 0.001); 

	System.out.println(xnew); 
	System.out.println(Math.pow(xnew, n) + " " + a); 
        System.out.println("Thank you!"); 

    } 
} 

P6.14 perhaps? But what's the ...? It doesn't matter, if it has a value.

For this problem, at least. Problems 6.9, 6.10, and 6.15 are easy, although for 10 and 15 we need to wait until we look at applets to do any graphics.

Let's do number 10. OK, but I won't draw circles, I'll just create them.

Drunkards, circles, cannonbals: they're all the same.
Especially drunkards. Here's the code:
import java.util.*; 

class Ten {
    public static void main(String[] args) { 

	System.out.print("Enter number of circles: "); 

        ConsoleReader console = new ConsoleReader(System.in); 
	int n = console.readInt(); 

	System.out.println("Generating " + n + " circles.");

	Random generator = new Random(); 

	for (int i = 0; i < n; i++) {

	    int x = 100 + Math.abs(generator.nextInt()) % 200; 
	    int y = 100 + Math.abs(generator.nextInt()) % 200; 

	    int r = 10 + Math.abs(generator.nextInt()) % 40;

	    Circle e = new Circle(x, y, r); 

	    System.out.println(e); // looks better when you draw it

	} 

	System.exit(0); 

    }
}

class Circle {
  double xCenter, yCenter, radius;
  Circle (double x, double y, double r) {
    xCenter = x; 
    yCenter = y;
    radius = r; 
  } 
  public String toString() {
    return "I am a circle at: ("     + 
           xCenter + ", " + yCenter  + 
           ") with a radius of "     +  
           radius;
  } 
} 

Why is 6.15 easy? Because it's like 10, and in addition you have complete information about the position of the squares. You'll see, later.

Why is 6.15 hard? Because you should come up with a formula for the position of a square given its row and column (or line and column).

This way you can use a for loop for the lines, ... and another one for the columns.

One, inside each other. Like for the patterns we developed last week.

And why is 6.9 easy? Because you just have to compute two sums, and take a square root at the end.

Why is 6.9 hard? 6.9 is not hard, but you have to read the problem carefully and use the right formula.

Which is the last one (second of two). The last one for today anyway.

We'll do a lot more next time. I can (always) hardly wait.

Last updated: Feb 18, 2002 by Adrian German for A201