Figure 10-1: When you satisfy a condition, you’re happy.
Chapter 10
Which Way Did He Go?
In This Chapter
Untangling complicated conditions
Writing cool conditional code
Intertwining your
if
statements
It’s tax time again. At the moment, I’m working on Form 12432-89B:
If you’re married with fewer than three children, and your income is higher than the EIQ (Estimated Income Quota), or if you’re single and living in a non-residential area (as defined by Section 10, Part iii of the Uniform Zoning Act), and you’re either self-employed as an LLC (Limited Liability Company) or you qualify for veterans benefits, then skip Steps 3 and 4 or 4, 5, and 6, depending on your answers to Questions 2a and 3d.
This chapter has nothing as complex as Form 12432-89B, but it does deal with the potential complexity of if
statements.
Forming Bigger and Better Conditions
In Listing 9-2, the code chooses a course of action based on one call to the Random
class’s nextInt
method. That’s fine for the electronic oracle program described in Chapter 9, but what if you’re rolling a pair of dice? In Backgammon and other dice games, rolling 3 and 5 isn’t the same as rolling 4 and 4, even though the total for both rolls is 8. The next move varies, depending on whether or not you roll doubles. To get the computer to roll two dice, you execute myRandom.nextInt(6) + 1
two times. Then you combine the two rolls into a larger, more complicated if
statement.
So to simulate a Backgammon game (and many other, more practical situations) you need to combine conditions.
If die1 + die2 equals 8
and
die1 equals die2, ...
You need things like and and or — things that can wire conditions together. Java has operators to represent these concepts, which are described in Table 10-1 and illustrated in Figure 10-1.
Figure 10-1: When you satisfy a condition, you’re happy.
Combined conditions, like the ones in Table 10-1, can be mighty confusing. That’s why I tread carefully when I use such things. Here’s a short explanation of each example in the table:
4 < age && age < 8
The value of the age
variable is greater than 4 and is less than 8. The numbers 5, 6, 7, 8, 9 . . . are all greater than 4. But among these numbers, only 5, 6, and 7 are less than 8. So only the numbers 5, 6, and 7 satisfy this combined condition.
age < 4 || 8 < age
The value of the age
variable is less than 4 or is greater than 8. To create the or condition, you use two pipe symbols. On many U.S. English keyboards, you can find the pipe symbol immediately above the Enter key (the same key as the backslash, but shifted).
In this combined condition, the value of the age
variable is either less than 4 or is greater than 8. So for example, if a number is less than 4, then the number satisfies the condition. Numbers like 1, 2, and 3 are all less than 4, so these numbers satisfy the combined condition.
Also, if a number is greater than 8, then the number satisfies the combined condition. Numbers like 9, 10, and 11 are all greater than 8, so these numbers satisfy the condition.
!eachKidGetsTen
If I weren’t experienced with computer programming languages, I’d be confused by the exclamation point. I’d think that !eachKidGetsTen
means, “Yes, each kid does get ten.” But that’s not what this expression means. This expression says, “The variable eachKidGetsTen
does not have the value true
.” In Java and other programming languages, an exclamation point stands for negative, for no way, for not.
Listing 8-4 has a boolean
variable named eachKidGetsTen
. A boolean
variable’s value is either true
or false
. Because !
means not, the expressions eachKidGetsTen
and !eachKidGetsTen
have opposite values. So when eachKidGetsTen
is true, !eachKidGetsTen
is false (and vice versa).
Combining conditions: An example
Here’s a handy example of the use of logical operators. A movie theater posts its prices for admission.
Regular price: $9.25
Kids under 12: $5.25
Seniors (65 and older): $5.25
Because the kids’ and seniors’ prices are the same, you can combine these prices into one category. (That’s not always the best programming strategy, but do it anyway for this example.) To find a particular moviegoer’s ticket price, you need one or more if
statements. You can structure the conditions in many ways, and I chose one of these ways for the code in Listing 10-1.
Listing 10-1: Are You Paying Too Much?
import java.util.Scanner;
class TicketPrice {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
int age;
double price = 0.00;
System.out.print(“How old are you? “);
age = myScanner.nextInt();
if (
age >= 12 && age < 65
) {
price = 9.25;
}
if (
age < 12 || age >= 65
) {
price = 5.25;
}
System.out.print(“Please pay $”);
System.out.print(price);
System.out.print(“. “);
System.out.println(“Enjoy the show!”);
}
}
Several runs of the TicketPrice
program (see Listing 10-1) are shown in Figure 10-2. (For your viewing pleasure, I’ve copied the runs from Eclipse’s Console view to Windows Notepad.) When you turn 12, you start paying full price. You keep paying full price until you become 65. At that point, you pay the reduced price again.
The pivotal part of Listing 10-1 is the lump of if
statements in the middle, which are illustrated in Figure 10-3.
Figure 10-2: Admission prices for Beginning Programming with Java For Dummies: The Movie.
The first
if
statement’s condition tests for the regular price group. Anyone who’s at least 12 years of age and is under 65 belongs in this group.
The second
if
statement’s condition tests for the fringe ages. A person who’s under 12 or is 65 or older belongs in this category.
Figure 10-3: The meanings of the conditions in Listing 10-1.
When to initialize?
Take a look at Listing 10-1 and notice the price
variable’s initialization:
double price
= 0.00
;
This line declares the price
variable and sets the variable’s starting value to 0.00
. When I omit this initialization, I get an error message:
The local variable price may not have been initialized
What’s the deal here? I don’t initialize the age
variable, but the compiler doesn’t complain about that. Why is the compiler fussing over the price
variable? The answer is in the placement of the code’s assignment statements. Consider the following two facts:
The statement that assigns a value to
age
(age = myScanner. nextInt()
) is not inside an if
statement.
That assignment statement always gets executed, and (as long as nothing extraordinary happens) the variable age
is sure to be assigned a value.
Both statements that assign a value to
price
(price = 9.25
and price = 5.25
) are inside if
statements.
If you look at Figure 10-3, you see that every age group is covered. No one shows up at the ticket counter with an age that forces both if
conditions to be false
. So whenever you run the TicketPrice
program, either the first or the second price
assignment is executed.
The problem is that the compiler isn’t smart enough to check all this. The compiler just sees the structure in Figure 10-4 and becomes scared that the computer won’t take either of the true
detours.
If (for some unforeseen reason) both of the if
statements’ conditions are false
, then the variable price
doesn’t get assigned a value. So without an initialization, price
has no value. (More precisely, price
has no value that’s intentionally given to it in the code.)
Eventually, the computer reaches the System.out.print(price)
statement. It can’t display price
unless price
has a meaningful value. So at that point, the compiler throws up its virtual hands in disgust.
Figure 10-4: The choices in Listing 10-1.
More and more conditions
Last night I got a discount coupon along with the meal at the local burger joint. The coupon is good for $2.00 off a ticket at the local movie theater. To make use of the coupon in the TicketPrice
program, I have to tweak the code in Listing 10-1. The revised code is in Listing 10-2. In Figure 10-5, I take that new code around the block a few times.
Listing 10-2: Do You Have a Coupon?
import java.util.Scanner;
class TicketPriceWithDiscount {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
int age;
double price = 0.00;
char reply;
System.out.print(“How old are you? “);
age = myScanner.nextInt();
System.out.print(“Have a coupon? (Y/N) “);
reply = myScanner.findWithinHorizon(“.”, 0)
.charAt(0);
if (age >= 12 && age < 65) {
price = 9.25;
}
if (age < 12 || age >= 65) {
price = 5.25;
}
if (reply == ‘Y’ || reply == ‘y’) {
price -= 2.00;
}
if (reply != ‘Y’ && reply != ‘y’ &&
reply!=’N’ && reply!=’n’) {
System.out.println(“Huh?”);
}
System.out.print(“Please pay $”);
System.out.print(price);
System.out.print(“. “);
System.out.println(“Enjoy the show!”);
}
}
Figure 10-5: Running the code in Listing 10-2.
Listing 10-2 has two if
statements whose conditions involve characters:
In the first such statement, the computer checks to see whether the
reply
variable stores the letter Y
or the letter y
. If either is the case, then it subtracts 2.00 from the price
. (For information on operators like -=
, see Chapter 7.)
The second such statement has a hefty condition. The condition tests to see whether the
reply
variable stores any reasonable value at all. If the reply isn’t Y
, and isn’t y
, and isn’t N
, and isn’t n
, then the computer expresses its concern by displaying, “Huh?” (As a paying customer, the word “Huh?” on the automated ticket teller’s screen will certainly get your attention.)
Using boolean variables
No matter how good a program is, you can always make it a little bit better. Take the code in Listing 10-2. Does the forest of if
statements make you nervous? Do you slow to a crawl when you read each condition? Wouldn’t it be nice if you could glance at a condition and make sense of it very quickly?
To some extent, you can. If you’re willing to create some additional variables, you can make your code easier to read. Listing 10-3 shows you how.
Listing 10-3: George Boole Would Be Proud
import java.util.Scanner;
class NicePrice {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
int age;
double price = 0.00;
char reply;
boolean isKid, isSenior, hasCoupon, hasNoCoupon;
System.out.print(“How old are you? “);
age = myScanner.nextInt();
System.out.print(“Have a coupon? (Y/N) “);
reply = myScanner.findWithinHorizon(“.”, 0) .charAt(0);
isKid = age < 12;
isSenior = age >= 65;
hasCoupon = reply == ‘Y’ || reply == ‘y’;
hasNoCoupon = reply == ‘N’ || reply == ‘n’;
if (!isKid && !isSenior) {
price = 9.25;
}
if (isKid || isSenior) {
price = 5.25;
}
if (hasCoupon) {
price -= 2.00;
}
if (!hasCoupon && !hasNoCoupon) {
System.out.println(“Huh?”);
}
System.out.print(“Please pay $”);
System.out.print(price);
System.out.print(“. “);
System.out.println(“Enjoy the show!”);
}
}
Runs of the Listing 10-3 code look like the stuff in Figure 10-5. The only difference between Listings 10-2 and 10-3 is the use of boolean
variables. In Listing 10-3, you get past all the less-than signs and double equal signs before the start of any if
statements. By the time you encounter the two if
statements, the conditions can use simple words — words like isKid
, isSenior
, and hasCoupon
. You can read more about boolean
variables in Chapter 8.
Adding a boolean
variable can make your code more manageable. But some programming languages don’t have boolean
variables, so many programmers prefer to create if
conditions on the fly. That’s why I mix the two techniques (conditions with and without boolean
variables) in this book.
Mixing different logical operators together
If you read about Listing 10-2, you know that my local movie theater offers discount coupons. The trouble is, I can’t use a coupon along with any other discount. I tried to convince the ticket taker that I’m under 12 years of age, but he didn’t buy it. When that didn’t work, I tried combining the coupon with the senior citizen discount. That didn’t work, either. The theater must use some software that checks for people like me. It looks something like the code in Listing 10-4. Take a look at Figure 10-6.
Listing 10-4: No Extra Break for Kids or Seniors
import java.util.Scanner;
class CheckAgeForDiscount {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
int age;
double price = 0.00;
char reply;
System.out.print(“How old are you? “);
age = myScanner.nextInt();
System.out.print(“Have a coupon? (Y/N) “);
reply = myScanner.findWithinHorizon(“.”, 0)
.charAt(0);
if (age >= 12 && age < 65) {
price = 9.25;
}
if (age < 12 || age >= 65) {
price = 5.25;
}
if ((reply == ‘Y’ || reply == ‘y’) &&
(age >= 12 && age < 65)) {
price -= 2.00;
}
System.out.print(“Please pay $”);
System.out.print(price);
System.out.print(“. “);
System.out.println(“Enjoy the show!”);
}
}
Figure 10-6: Running the code in Listing 10-4.
Listing 10-4 is a lot like its predecessors, Listings 10-1 and 10-2. The big difference is the bolded if
statement. This if
statement tests two things, and each thing has two parts of its own:
1. Does the customer have a coupon?
That is, did the customer reply with either Y
or with y
?
2. Is the customer in the regular age group?
That is, is the customer at least 12 years old and younger than 65?
In Listing 10-4, I join items 1 and 2 using the &&
operator. I do this because both items (item 1 and item 2) must be true in order for the customer to qualify for the $2.00 discount, as illustrated in Figure 10-7.
Using parentheses
Listing 10-4 demonstrates something important about conditions. Sometimes, you need parentheses to make a condition work correctly. Take, for example, the following incorrect if
statement:
//This code is incorrect:
if (reply == ‘Y’ || reply == ‘y’ &&
age >= 12 && age < 65) {
price -= 2.00;
}
Compare this code with the correct code in Listing 10-4. This incorrect code has no parentheses to group reply == ‘Y’
with reply == ‘y’
, or to group age >= 12
with age < 65
. The result is the bizarre pair of runs in Figure 10-8.
Figure 10-7: Both the reply and the age criteria must be true.
Figure 10-8: A capital offense.
In Figure 10-8, notice that the y
and Y
inputs yield different ticket prices, even though the age is 85 in both runs. This happens because, without parentheses, any &&
operator gets evaluated before any ||
operator. (That’s the rule in the Java programming language — evaluate &&
before ||
.) When reply
is Y
, the condition in the bad if
statement takes the following form:
reply == ‘Y’ ||
some-other-stuff-that-doesn’t-matter
Whenever reply == ‘Y’
is true
, the whole condition is automatically true
, as illustrated in Figure 10-9.
Figure 10-9: “True or false” makes “true.”
Building a Nest
The year is 1968, and The Prisoner is on TV. In the last episode, the show’s hero meets his nemesis, “Number One.” At first, Number One wears a spooky happy-face/sad-face mask, and when the mask comes off, there’s a monkey mask underneath. To find out what’s behind the monkey mask, you have to watch the series on DVD. But in the meantime, notice the layering: a mask within a mask. You can do the same kind of thing with if
statements. This section’s example shows you how.
But first, take a look at Listing 10-4. In that code, the condition age >= 12 && age < 65
is tested twice. Both times, the computer sends the numbers 12, 65, and the age
value through its jumble of circuits, and both times, the computer gets the same answer. This is wasteful, but waste isn’t your only concern.
What if you decide to change the age limit for senior tickets? From now on, no one under 100 gets a senior discount. You fish through the code and see the first age >= 12 && age < 65
test. You change 65
to 100
, pat yourself on the back, and go home. The problem is, you’ve changed one of the two age >= 12 && age < 65
tests, but you haven’t changed the other. Wouldn’t it be better to keep all the age >= 12 && age < 65
testing in just one place?
Listing 10-5 comes to the rescue. In Listing 10-5, I smoosh all my if
statements together into one big glob. The code is dense, but it gets the job done nicely.
Listing 10-5: Nested if Statements
import java.util.Scanner;
class AnotherAgeCheck {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
int age;
double price = 0.00;
char reply;
System.out.print(“How old are you? “);
age = myScanner.nextInt();
System.out.print(“Have a coupon? (Y/N) “);
reply = myScanner.findWithinHorizon(“.”, 0).charAt(0);
if (age >= 12 && age < 65) {
price = 9.25;
if (reply == ‘Y’ || reply == ‘y’) {
price -= 2.00;
}
} else {
price = 5.25;
}
System.out.print(“Please pay $”);
System.out.print(price);
System.out.print(“. “);
System.out.println(“Enjoy the show!”);
}
}
Nested if statements
A run of the code in Listing 10-5 looks identical to a run for Listing 10-4. You can see several runs in Figure 10-6. The main idea in Listing 10-5 is to put an if
statement inside another if
statement. After all, Chapter 9 says that an if
statement can take the following form:
if (
Condition
) {
SomeStatements
} else {
OtherStatements
}
Who says SomeStatements
can’t contain an if
statement? For that matter, OtherStatements
can also contain an if
statement. And, yes, you can create an if
statement within an if
statement within an if
statement. There’s no predefined limit on the number of if
statements that you can have.
if
(age >= 12 && age < 65) {
price = 9.25;
if
(reply == ‘Y’ || reply == ‘y’) {
if
(isSpecialFeature) {
price -= 1.00;
} else {
price -= 2.00;
}
}
} else {
price = 5.25;
}
When you put one if
statement inside another, you create nested if
statements. Nested statements aren’t difficult to write, as long as you take things slowly and keep a clear picture of the code’s flow in your mind. If it helps, draw yourself a diagram like the one shown in Figure 10-10.
Figure 10-10: The flow in Listing 10-5.
Figure 10-11: Be careful about adding the proper indentation and braces.
Cascading if statements
Here’s a riddle: You have two baseball teams — the Hankees and the Socks. You want to display the teams’ scores on two separate lines, with the winner’s score coming first. (On the computer screen, the winner’s score is displayed above the loser’s score.) What happens when the scores are tied?
Do you give up? The answer is, there’s no right answer. What happens depends on the way you write the program. Take a look back at Listing 9-4 in Chapter 9. When the scores are equal, the condition hankees > socks
is false
. So the program’s flow of execution drops down to the else
clause. That clause displays the Socks score first and the Hankees score second. (Refer to Figure 9-7.)
The program doesn’t have to work this way. If I take Listing 9-4 and change hankees > socks
to hankees >= socks
then, in case of a tie, the Hankees score comes first.
Suppose that you want a bit more control. When the scores are equal, you want an It’s a tie
message. To do this, think in terms of a three-pronged fork. You have a prong for a Hankees win, another prong for a Socks win, and a third prong for a tie. You can write this code in several different ways, but one way that makes lots of sense is in Listing 10-6. For three runs of the code in Listing 10-6, see Figure 10-12.
Listing 10-6: In Case of a Tie . . .
import java.util.Scanner;
import static java.lang.System.out;
class WinLoseOrTie {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
int hankees, socks;
out.print(“Hankees and Socks scores? “);
hankees = myScanner.nextInt();
socks = myScanner.nextInt();
out.println();
if
(hankees > socks) {
out.println(“Hankees win...”);
out.print(“Hankees: “);
out.println(hankees);
out.print(“Socks: “);
out.println(socks);
}
else if
(socks > hankees) {
out.println(“Socks win...”);
out.print(“Socks: “);
out.println(socks);
out.print(“Hankees: “);
out.println(hankees);
}
else
{
out.println(“It’s a tie...”);
out.print(“Hankees: “);
out.println(hankees);
out.print(“Socks: “);
out.println(socks);
}
}
}
Figure 10-12: Go, team, go!
Listing 10-6 illustrates a way of thinking about a problem. You have one question with more than two answers. (In this section’s baseball problem, the question is “Who wins?” and the answers are “Hankees,” “Socks,” or “Neither.”) The problem begs for an if
statement, but an if
statement has only two branches — the true
branch and the false
branch. So you combine alternatives to form cascading if statements.
In Listing 10-6, the format for the cascading if
statements is
if (
Condition1
) {
SomeStatements
} else if (
Condition2
) {
OtherStatements
} else {
EvenMoreStatements
}
In general, you can use else if
as many times as you want:
if
(hankeesWin) {
out.println(“Hankees win...”);
out.print(“Hankees: “);
out.println(hankees);
out.print(“Socks: “);
out.println(socks);
} else if
(socksWin) {
out.println(“Socks win...”);
out.print(“Socks: “);
out.println(socks);
out.print(“Hankees: “);
out.println(hankees);
} else if
(isATie) {
out.println(“It’s a tie...”);
out.print(“Hankees: “);
out.println(hankees);
out.print(“Socks: “);
out.println(socks);
} else if
(gameCancelled) {
out.println(“Sorry, sports fans.”);
} else {
out.println(“The game isn’t over yet.”);
}
Nothing is special about cascading if
statements. This isn’t a new programming language feature. Cascading if
statements take advantage of a loophole in Java — a loophole about omitting curly braces in certain circumstances. Other than that, cascading if
statements just gives you a new way to think about decisions within your code.
Note: Listing 10-6 uses a static import declaration to avoid needless repetition of the words System.out
. To read a little bit about the static import declaration (along with an apology for my not explaining this concept more thoroughly), see Chapter 9. Then to get the real story on static import declarations, see Chapter 18.
Enumerating the Possibilities
Chapter 8 describes Java’s boolean
type — the type with only two values (true
and false
). The boolean
type is very handy, but sometimes you need more values. After all, a traffic light’s values can be green
, yellow
, or red
. A playing card’s suit can be spade
, club
, heart
, or diamond
. And a weekday can be Monday
, Tuesday
, Wednesday
, Thursday
, or Friday
.
Life is filled with small sets of possibilities, and Java has a feature that can reflect these possibilities. The feature is called an enum
type. It’s available from Java version 5.0 onward.
Creating an enum type
The story in Listing 10-6 has three possible endings — the Hankees win, the Socks win, or the game is tied. You can represent the possibilities with the following line of Java code:
enum WhoWins {home, visitor, neither}
This week’s game is played at Hankeeville’s SnitSoft Stadium, so the value home
represents a win for the Hankees, and the value visitor
represents a win for the Socks.
One of the goals in computer programming is for each program’s structure to mirror whatever problem the program solves. When a program reminds you of its underlying problem, the program is easy to understand and inexpensive to maintain. For example, a program to tabulate customer accounts should use names like customer
and account
. And a program that deals with three possible outcomes (home wins, visitor wins, and tie) should have a variable with three possible values. The line enum WhoWins {home, visitor, neither}
creates a type to store three values.
The WhoWins
type is called an enum type. Think of the new WhoWins
type as a boolean
on steroids. Instead of two values (true
and false
), the WhoWins
type has three values (home
, visitor
, and neither
). You can create a variable of type WhoWins
WhoWins who;
and then assign a value to the new variable.
who = WhoWins.home;
In the next section, I put the WhoWins
type to good use.
Using an enum type
Listing 10-7 shows you how to use the brand new WhoWins
type.
Listing 10-7: Proud Winners and Sore Losers
import java.util.Scanner;
import static java.lang.System.out;
class Scoreboard {
enum WhoWins {home, visitor, neither}
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
int hankees, socks;
WhoWins who;
out.print(“Hankees and Socks scores? “);
hankees = myScanner.nextInt();
socks = myScanner.nextInt();
out.println();
if (hankees > socks) {
who = WhoWins.home;
out.println(“The Hankees win :-)”);
} else if (socks > hankees) {
who = WhoWins.visitor;
out.println(“The Socks win :-(“);
} else {
who = WhoWins.neither;
out.println(“It’s a tie :-|”);
}
out.println();
out.println(“Today’s game is brought to you by”);
out.println(“SnitSoft, the number one software”);
out.println(“vendor in the Hankeeville area.”);
out.println(“SnitSoft is featured proudly in”);
out.println(“Chapter 6. And remember, four out”);
out.println(“of five doctors recommend”);
out.println(“SnitSoft to their patients.”);
out.println();
if (who == WhoWins.home)
{
out.println(“We beat ‘em good. Didn’t we?”);
}
if (who == WhoWins.visitor)
{
out.println(“The umpire made an unfair”);
out.println(“call.”);
}
if (who == WhoWins.neither)
{
out.println(“The game goes into overtime.”);
}
}
}
Three runs of the program in Listing 10-7 are pictured in Figure 10-13. Here’s what happens in Listing 10-7:
I create a variable to store values of type
WhoWins
.
Just as the line
double amount;
declares amount
to store double
values (values like 5.95 and 30.95), the line
WhoWins who;
declares who
to store WhoWins
values (values like home
, visitor
, and neither
).
I assign a value to the
who
variable.
I execute one of the
who = WhoWins.something
;
assignment statements. The statement that I execute depends on the outcome of the if
statement’s hankees > socks
comparison.
Notice that I refer to each of the WhoWins
values in Listing 10-7. I write WhoWins.home
, WhoWins.visitor
, or WhoWins.neither
. If I forget the WhoWins
prefix and type
who = home; //This assignment doesn’t work!
then the compiler gives me a home cannot be resolved to a variable
error message. That’s just the way enum
types work.
I compare the variable’s value with each of the
WhoWins
values.
In one if
statement, I check the who == WhoWins.home
condition. In the remaining two if
statements, I check for the other WhoWins
values.
Near the end of Listing 10-7, I could have done without enum
values. I could have tested things like hankees > socks
a second time.
if (
hankees > socks
) {
out.println(“The Hankees win :-)”);
}
// And later in the program...
if (
hankees > socks
) {
out.println(“We beat ‘em good. Didn’t we?”);
}
But that tactic would be clumsy. In a more complicated program, I may end up checking hankees > socks
a dozen times. It would be like asking the same question over and over again.
Instead of repeatedly checking the hankees > socks
condition, I store the game’s outcome as an enum value. Then I check the enum value as many times as I want. That’s a very tidy way to solve the repeated checking problem.
Figure 10-13: Joy in Hankeeville?