University of Washington, CSE 142 (190)

Lab 5: `while` loops, fencepost, Random numbers, boolean logic, midterm practice

Except where otherwise noted, the contents of this document are Copyright 2010 Stuart Reges and Marty Stepp.

lab document created by Whitaker Brand and Marty Stepp

Today's lab

Goals for today:

• use `while` loops for indefinite repetition
• exposure to fencepost and sentinel loop patterns
• use `Random` objects to produce random numbers
• use `boolean` expressions and variables to represent logical true/false expressions
• examine logical assertions that can be made about a running program
• practice problems similar to what will be on the midterm exam
• Where you see this icon, you can click it to check the problem in Practice-It!

Exercise : `while` loop mystery

Fill in the boxes at right with the output produced by each method call.

```public static void mystery(int x, int y) {
int z = 0;
while (x % y != 0) {
x = x / y;
z++;
System.out.print(x + ", ");
}

System.out.println(z);
}
```
 `mystery(25, 2);` `12, 1` `mystery(32, 4);` `0` `mystery(10345, 10);` `1034, 103, 10, 3` `mystery(63, 2);` `31, 15, 7, 3, 1, 0, 6`

Exercise : digitSum

• Write a method named `digitSum` that accepts an integer as a parameter and returns the sum of the digits of that number. For example, the call `digitSum(29107)` returns 2+9+1+0+7 or 19. For negative numbers, return the same value that would result if the number were positive. For example, `digitSum(-456)` returns 4+5+6 or 15. The call `digitSum(0)` returns 0.
• Try solving this problem in Practice-It! using the link above.
• (Hint: To extract a digit from a number, `use / 10` and `% 10` operations.)

Exercise : digitSum - solution

```public static int digitSum(int n) {
n = Math.abs(n);            // handle negatives
int sum = 0;
while (n > 0) {
int lastDigit = n % 10;
sum = sum + lastDigit;  // add last digit to sum
n = n / 10;             // remove last digit from n
}
return sum;
}
```

Recall: `Random` Methods

To use these methods, you need a variable of type `Random` in scope:

```Random randy = new Random();
int aRandomNumber = randy.nextInt(10);  // 0-9
```
Method name Returns...
`nextInt()` a random integer
`nextInt(max)` a random integer between 0 (inclusive) and max (exclusive)
`nextDouble()` a random real number between 0.0 and 1.0
`nextBoolean()` a random `boolean` value: `true` or `false`

Exercise : Random Expressions

• Fill in the boxes to produce expressions that will generate random numbers in the provided ranges. Assume that the following `Random` variable has been declared:
```Random rand = new Random();
```
 Example: a random integer from 1 to 5 inclusive: ```rand.nextInt(5) + 1 ``` a random integer from 0 to 3 inclusive: `rand.nextInt(4)` a random integer from 5 to 10 inclusive: ```rand.nextInt(6) + 5 ``` a random integer from -4 to 4 inclusive: ```rand.nextInt(9) - 4 ``` a random even integer from 16 to 28 inclusive: (Hint: To get only even numbers, scale up.) ```rand.nextInt(7) * 2 + 16 ```

Exercise : Boolean Expressions

Write the result of each expression as either `true` or `false`, given the following variables. Recall the logical operators: `&&` (and), `||` (or), `!` (not).

```int x = 12;
int y = 7;
int z = 28;
String s = "mid term";
```
 `x < 14` `true` `!(x % 2 < 1)` `false` `x < y || x < z` `true` `z / x < x / y * x` `true` `s.length() == y` `false` `s.toUpperCase().equals("MID TERM")` `true` `!s.equals("mid term") || x * y != z` `true` `s.substring(z / x).length() > y` `false`

Exercise : makeGuesses

Write a method named `makeGuesses` that will output random numbers between 1 and 50 inclusive until it outputs one of at least 48. Output each guess and the total number of guesses made. Below is a sample execution:

```guess = 43
guess = 47
guess = 45
guess = 27
guess = 49
total guesses = 5
```

Try solving this problem in Practice-It! from the link above.

Exercise : assertions

Identify whether each assertion is always/never/sometimes `true` at each point.

`x > y` `z == 0` `x == y`
A
B
C
D
E
```public static void mystery(int x, int y) {
int z = 0;

// Point A
while (x != y) {
// Point B
z++;

if (x > y) {
// Point C
x = x / 10;
} else {
// Point D
y = y / 10;
}
}

// Point E
System.out.println(x + " " + y + " " + z);
}
```

Exercise : allDigitsOdd

Write a method named `allDigitsOdd` that returns whether every digit of a positive integer is odd. Your method should return `true` if the number consists entirely of odd digits and `false` if any of its digits are even. 0, 2, 4, 6, and 8 are even digits, and 1, 3, 5, 7, 9 are odd digits.

For example, `allDigitsOdd(135319)` returns `true` but `allDigitsOdd(9145293)` returns `false`.

Hint: You can pull apart a number into its digits using `/ 10` and `% 10`.

Exercise : hopscotch

Write a method named `hopscotch` that accepts an integer parameter for a number of "hops" and prints a hopscotch board of that many hops.

For example, the call `hopscotch(3);` would produce the following output:

```   1
2     3
4
5     6
7
8     9
10
```

Try solving this problem in Practice-It: click on the check-mark above!

Exercise : hasMidpoint

Write a method `hasMidpoint` that accepts three integers as parameters, and returns `true` if one of the numbers is the midpoint of the other two and returns `false` otherwise.

For example, the call `hasMidpoint(3, 7, 5)` would return `true` because one of the parameters (5) is the midpoint of the other two (3 and 7).

Try to solve this problem in Practice-It: click on the check-mark above!

Exercise : longestName

Write a method named `longestName` that reads names typed by the user and prints the longest name (the name that contains the most characters) in the format shown below. Your method should accept a console `Scanner` and an integer n as parameters and should then prompt for n names.

A sample execution of the call `longestName(console, 4)` might look like the following:

```name #1? roy
name #2? DANE
name #3? sTeFaNiE
name #4? Erik
Stefanie's name is longest
```

Try to solve this problem in Practice-It: click on the check-mark above!

Exercise : Syntax errors

• The following Java program has 11 errors. Can you find them all?  ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ``` ```public class StringOops { public static void main(String[] args) { Scanner console = new Scanner(System.in); System.out.print("Type your name: "); String name = console.nextString(); process(name); } public static void process(string "name") { if (name == Whitaker) { System.out.println("You must be really awesome."); } replace("a", "e"); toUppercase(name); name.substring(0, 3); System.out.println(name + " has " + name.length + " letters"); } } ```
• Copy and paste the code into jGrasp and see if you can fix the errors.

1. line 5: `nextString` should be `next`
2. line 9: `string` should be `String`
3. line 9: `name` should not be in quotes
4. line 10: `Whitaker` should be in quotes
5. line 10: cannot compare strings with `==`; must use `.equals`
6. line 13: cannot call `replace` without specifying a string object (`name`)
7. line 14: `toUppercase` should be `toUpperCase`
8. line 14: `name.` should come before `toUpperCase`, not passed as a parameter to it
9. line 14: must say `name =` to store the result of `toUpperCase`
10. line 15: must say `name =` to store the result of `substring`
11. line 16: must use parentheses `()` when calling `length`

Exercise - Corrected version

```public class StringOops {
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
String name = console.next();
process(name);
}

public static void process(String "name") {
if (name.equals("Whitaker")) {
System.out.println("You must be really awesome.");
}
name = name.replace("a", "e");
name = name.toUpperCase();
name = name.substring(0, 3);
System.out.println(name + " has " + name.length() + " letters");
}
}
```

Exercise : ProcessName

• Copy/paste and save this program in jGRASP, then go to the next slide.
```import java.util.*;  // for Scanner

public class ProcessName {
public static void main(String[] args) {
Scanner console = new Scanner(System.in);

System.out.println("Your name is: " + name);
}
}
```

• Add code to the program so that it reads the user's first and last name (read an entire line as a single string), then prints the last name followed by a comma and the first initial. (Assume that the user types a valid name.) Example:
```Type your name: Jessica Miller
```
• (Notice that the program reads an entire line of user input, not just one word.)

• The following is a completed version of the program:
```import java.util.*;  // for Scanner

public class ProcessName {
public static void main(String[] args) {
Scanner console = new Scanner(System.in);

String name = console.nextLine();
int space = name.indexOf(" ");
String first = name.substring(0, space);
String last = name.substring(space + 1, name.length());
String firstInitial = first.substring(0, 1);
name = last + ", " + firstInitial + ".";

System.out.println("Your name is: " + name);
}
}
```

Exercise : ProcessName2

• Modify your `ProcessName` program so that it re-prompts until the user types a name that is at least 5 letters total in length and has at least one space in it. Example:
```Type your name: Joe
Error, must be at least 5 chars with a space.
Error, must be at least 5 chars with a space.
Error, must be at least 5 chars with a space.
```

```import java.util.*;  // for Scanner

public class ProcessName2 {
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
String name = console.nextLine();

while (name.length() < 5 || name.indexOf(" ") < 0) {
System.out.println("Error, must be at least 5 chars with a space.");
name = console.nextLine();
}

int space = name.indexOf(" ");
String first = name.substring(0, space);
String last = name.substring(space + 1, name.length());
String firstInitial = first.substring(0, 1);
name = last + ", " + firstInitial + ".";
System.out.println("Your name is: " + name);
}
}
```

Exercise : repl

• Write a method named `repl` that accepts a `String` and a number of repetitions as parameters and returns the `String` concatenated that many times. For example, the call `repl("hello", 3)` returns `"hellohellohello"`. If the number of repetitions is 0 or less, an empty string is returned.
• Try solving this problem in Practice-It! using the link above.
• (Hint: This is best solved with a cumulative algorithm. Start with an empty string and build it up piece by piece.)

Exercise : ZuneBug

The following code from Microsoft's Zune music player calculates today's date from the years/days passed since 1980. But all Zune players locked up on Jan 1 2009. Why? Download ZuneBug.java and modify it to fix the bug.

```int days = getTotalDaysSince1980();   // pretend this method exists
int year = 1980;
while (days > 365) {                  // subtract out years
if (isLeapYear(year)) {           // pretend this method exists
if (days > 366) {
days = days - 366;
year++;
}
} else {
days = days - 365;
year++;
}
}
```

The bug occurs when the current year is a leap year and there are exactly 366 days left (i.e., if today is Jan 1 on a year after a leap year). The code gets stuck in an infinite loop with `days == 366` because the `while` test is `true` but the `if (days > 366)` is `false`. Here is a fixed version:

```int days = getTotalDaysSince1980();   // pretend this method exists
int year = 1980;
while (days > 365 || (isLeapYear(year) && days > 366)) {
if (isLeapYear(year)) {
days = days - 366;
} else {
days = days - 365;
}
year++;
}
```

Exercise : printLetters

Consider the following flawed method `printLetters`, which accepts a `String` as its parameter and attempts to print the letters of the String, separated by dashes. For example, the call of `printLetters("Rabbit")` should print `R-a-b-b-i-t` .

```public static void printLetters(String text) {
for (int i = 0; i < text.length(); i++) {
System.out.print(text.substring(i, i + 1) + "-");
}
System.out.println();   // to end the line of output
}
```

What is wrong with the code? Paste the code in Practice-It! and fix it.

```public static void printLetters(String text) {
if (text.length() > 0) {
System.out.print(text.substring(0, 1));   // fencepost
for (int i = 1; i < text.length(); i++) {
System.out.print("-" + text.substring(i, i + 1));
}
System.out.println();   // to end the line of output
}
}
```

Exercise : printFactors

Write a method named `printFactors` that accepts an integer as its parameter and uses a fencepost loop to print the factors of that number, separated by the word `"and"`. For example, the call `printFactors(24)` should print as the following output:

```1 and 2 and 3 and 4 and 6 and 8 and 12 and 24
```

You may assume that the parameter value passed is greater than 0.

• Try solving this problem in Practice-It! using the link above.
• (Hint: This is an example of a fencepost problem.)

Exercise : swapPairs

• Write a method named `swapPairs` that accepts a `String` as a parameter and returns that `String` with each pair of adjacent letters reversed. If the `String` has an odd number of letters, the last letter is unchanged. For example, the call `swapPairs("forget")` should return `"ofgrte"` and the call `swapPairs("hello there")` should return `"ehll ohtree"`.
• Try solving this problem in Practice-It! using the link above.

Exercise : "Boolean Zen"

This attempted solution to Self-Check 5.15 (`isVowel`) has several problems:

```// Returns whether the given string represents a vowel:
// a, e, i, o, or u, case insensitively.
public static boolean isVowel(String s) {
if (s == "a") {
return true;
} else if (s == "e") {
return true;
} else if (s == "i") {
return true;
} else if (s == "o") {
return true;
} else if (s == "u") {
return true;
} else {
return false;
}
}
```

Open Practice-It from the link above, copy/paste this code into it, then see the next slide.

Exercise - things to fix

Fix the following aspects of the code:

• It has a bug related to how strings are compared.
• It isn't case sensitive; it fails for uppercase vowels.
• It has too many unnecessary if/else statements.
• (advanced) It does not use "Boolean Zen" as described in textbook section 5.3.

```public static boolean isVowel(String s) {
s = s.toLowerCase();
if (s.equals("a") || s.equals("e") || s.equals("i")
|| s.equals("o") || s.equals("u")) {
return true;
} else {
return false;
}
}
```

The above can be improved. "Boolean Zen" version:

```public static boolean isVowel(String s) {
s = s.toLowerCase();
return s.equals("a") || s.equals("e") || s.equals("i")
|| s.equals("o") || s.equals("u");
}
```

If you finish them all...

If you finish all the exercises, try out our Practice-It web tool. It lets you solve Java problems from our Building Java Programs textbook.

You can view an exercise, type a solution, and submit it to see if you have solved it correctly.

Choose some problems from Chapter 5 and try to solve them!