Changing Program Behavior with Conditions In JavaScript

In This Chapter

Generating random numbers and converting them to integers
Understanding conditions
Using the if-else structure
Managing multiple conditions
Using the switch structure
Handling unusual conditions
One of the most important aspects of computers is their apparent ability to make decisions. Computers can change their behavior based on circumstances. In this chapter you learn how to create random numbers in JavaScript, and several ways to have your program make decisions based on the roll of a digital die.

Working with Random Numbers

Random numbers are a big part of computing. They add uncertainty to games, but they’re also used for serious applications like simulations, security, and logic. In this chapter, you generate random numbers to simulate dice and then explore various ways to modify the computer’s behavior based on the value of the roll.
Most languages have a feature for creating random numbers, and JavaScript is no exception. The Math.random() function returns a random floating point value between 0 and 1.
Technically, computers can’t create truly random numbers. Instead, they use a complex formula that starts with one value and creates a second semi-predictable value. In JavaScript, the first value (called the random seed) is taken from the system clock in milliseconds, so the results of a random number call seem truly random.

Creating a die to die for

It’s very easy to create a random floating-point number between 0 and 1, because that’s what the Math.random() function does. What if you want an integer within a specific range? For example, you might want to simulate rolling a six-sided die. How do you get from the 0-to-1 floating-point value to a 1-to-6 integer?


Here’s the standard approach:

1. Get a random floating-point value.
Use the Math.random() function to get a floating-point value between 0 and 1.
2. Multiply the zero-to-one value by 6.
This gives you a floating-point value between 0 and 5.999 (but never 6).
3. Use Math.ceil() to round up.
Here’s where you need to convert the number to an integer. In Chapter 2 I mention three functions to convert from a float to an integer. Math. ceil() always rounds up, which means you’ll always get an integer between 1 and 6.

Rolling the dice

Take a look at the RollDie.html code that rolls your digital dice:
tmp7B29_thumb_thumbtmp7B30_thumb_thumb

As you can see, I converted the strategy from the previous section directly into JavaScript code:

1. Create a random floating-point value.
The Math.random() function creates a random floating-point number and stores it in the variable number.
2. Multiply the number by 6.
To move the number into the appropriate range (6 values), I multiplied by 6, and stored the result in biggerNumber.
3. Round up.
I used the Math.ceil() function to round the number up to the next highest integer.
Figure 3-1 shows the program running.
You might need to run the rollDice.html page a few times to confirm that it works as suspected.
If you want to re-run a program you’ve already loaded into the browser, just hit the Refresh button on the browser toolbar.
This program generates a value between 1 and 6.
Figure 3-1:
This program generates a value between 1 and 6.

Using if to Control Flow

If you can roll a die, you’ll eventually want different things to happen in different circumstances. Figure 3-2 shows two different runs of a simple game called deuce.html.
Nothing happens when you roll a 5, but something exciting happens when you roll a 2.
Figure 3-2:
Nothing happens when you roll a 5, but something exciting happens when you roll a 2.
Okay, it’s not that exciting. I promise to add dancing hippos in a later version. In any case, the “You got a deuce” message only happens when you roll a 2. The code is simple but profound:
tmp7B33_thumb_thumb
As usual, I’m only showing the <script> tag and its contents here, because the rest of the page is blank.

If and only if

The key to this program is the humble if statement. This powerful command does a number of important things:
It sets up a condition. More on conditions in a moment, but the main idea is this: A condition is a true or false question. if statements always include some type of condition in parentheses.
It begins a block of code. if statements set up a chunk of code that won’t always execute. The end of the if line includes a left brace ({).
It usually has indented code under it. The line or lines immediately after the if statement are part of the block, so they are indented to indicate they are special.
It ends several lines later. The end of the if statement is actually the right brace (}) several lines down in the code. In essence, an if statement contains other code.
It’s indented. The convention is to indent all the code between the if statement and its ending brace.
While not required, it’s common to put a comment indicating that the right brace ends an if statement. In the C-like languages, the same symbol (}) is used to end a bunch of things, so it’s nice to remind yourself what you think you’re ending here.

Using conditions

A condition is the central part of if statements and several other important structures. Conditions deserve a little respect of their own. A condition is an expression that can be evaluated to be true or false. Conditions come in three main flavors:
A comparison: This is by far the most common kind of condition. Typically you compare a variable to a value, or two variables to each other. A number of different types of comparisons are described in Table 3-1.
A Boolean variable: Boolean variables are variables that only contain true or false values. In JavaScript, any variable can be a Boolean, if you assign it a true or false value. It’s unnecessary to compare a Boolean to anything else, because it’s already true or false.
A Boolean function: Sometimes you’ll have a function that returns a true or false value. This type of function can also be used as a condition.
Incidentally, Boolean variables are the only variable type capitalized in most languages. This is because they were named after a person, George Boole. He was a nineteenth-century mathematician who developed a form of binary arithmetic. He died thinking his logic research a failure. His work eventually became the foundation of modern computing. Drop a mention of George at your next computer-science function to earn muchos geek points.

Comparison operators

JavaScript supports a number of different types of comparisons, summarized in Table 3-1:

Table 3-1 JavaScript Comparison Operators
Name Operator Example Notes
Equal = = (x==3) Works with all variable types, including strings
Not equal (x != 3) True if values are not equal
Less than < (x < 3) Numeric or alphabetical comparison
Greater than > (x > 3) Numeric or alphabetical comparison
Less than or equal to (x <= 3) Numeric or alphabetical comparison
Greater than or equal to (x >= 3) Numeric or alphabetical comparison

You should consider a few things when working with conditions:

Make sure the variable types are compatible. You’ll get unpredictable results if you compare a floating-point value to a string.
You can compare string values. In JavaScript, the inequality operators can be used to determine the alphabetical order of two values, and you can use the same equality symbol (==) with strings that you use with other variables. (This is not true in all programming languages.)
Equality uses a double equals sign. The single equals sign (=) is used to indicate assignment. When you’re comparing variables, use a double equals sign (==) instead.
Don’t confuse assignment with comparison! If you accidentally say (x = 3) instead of (x == 3), your code won’t crash, but it won’t work properly. The first statement simply assigns the value 3 to the variable x. It returns the value true if the assignment was successful (which it will be). You’ll think you’re comparing x to 3, but you’re assigning x to 3, and the condition will always be true. It’s a nightmare. I still do it once in a while.

Do What I Say or Else

The Deuce game is pretty exciting and all, but it would be even better if you had one comment when the roll is a 2 and another comment when it’s something else. The else-if structure is designed to let you specify one behavior when a condition is true, and another behavior if the condition is false. Figure 3-3 shows a program with exactly this behavior.
You get one message for deuces and another message for everything else.
Figure 3-3:
You get one message for deuces and another message for everything else.

This program uses the same type of condition, but it adds an important section:

tmp7B35_thumb_thumb

The if statement is unchanged, but now there’s an else clause. Here’s how it works:

The if statement sets up a condition: The if indicates the beginning of a code branch, and it prepares the way for a condition.
The condition establishes a test: Conditions are true or false expressions, so the condition will indicate something that can be true or false.
If the condition is true: The code between the condition and the else clause runs. After this code is finished, program control moves past the end of the if structure. (That is, the computer skips the else clause and executes then next line of code outside the if structure.)
If the condition is false: The code between else and the end of the if runs instead.
The else clause acts like a fork in the road. The code will go along one path or another (depending on the condition), but never both at once.
You can put as much code as you want inside an if or else clause, including more if statements!
You can only use else in the context of an if statement. You can’t use else by itself.

Using else-if for more complex interaction

The if-else structure is pretty useful when you have only two branches, but what if you want to have several different options? Imagine for example that you want to output a different value for every single possible die value. You’ll need a variation of the if structure to make this work. I show such a tool next, but first, look at a program which uses this technique. Figure 3-4 shows a die only a geek could love. All its values are output in binary notation.

Binary?

Binary notation is the underlying structure of all data in a computer. It uses 1s and 0s to store other numbers, which can be combined to form everything you see on the computer, from graphics to text to music videos and adventure games. Here’s a quick conversion chart so you can read the dice:
tmp7B36_thumb_thumb
You can survive just fine without knowing binary (unless you’re a computer science major — then you’re expected to dream in binary). Still, it’s kind of cool to know how things really work.
A die for the true geek gamer.
Figure 3-4:
A die for the true geek gamer.
A simple if-else structure won’t be sufficient here, because you have six different options, and if-else only gives you two choices. Here’s some code that uses another variation of if and else:
tmp7B38_thumb_thumb
This program begins with an ordinary if statement, but it has a number of else clauses. You can include as many else clauses as you want if each includes its own condition.

For example, imagine the computer generates the value 3. The process would look like this:

1. The first condition (die == 1) is false, so the program immediately jumps to the next else.
2. This sets up another condition (die == 2), which is also false, so program control goes to the next else clause.
3. This one has yet another condition (die == 3) — which is true! The code inside this clause is executed (alerting the value “011″).
4. A condition has finally been triggered — so the computer skips all the other else conditions and moves to the line after the end if.
5. This is the last line of code — so the program ends.

The mystery of the unnecessary else

When you use multiple conditions, you can (and should) still indicate an ordinary else clause without a condition as your last choice. This special condition sets up code that should happen if none of the other conditions is triggered. It’s useful as a “garbage collection” function, in case you didn’t anticipate a condition in the else if clauses.
If you think carefully about the binary dice program, the else clause seems superfluous. It isn’t really necessary! You went through all that trouble to create a random number scheme that guarantees you’ll have an integer between 1 and 6. If you checked for all six values, why have an else clause? It should never be needed.
There’s a big difference between what should happen and what does happen. Even if you think you’ve covered every single case, you’re going to be surprised every once in a while. If you use a multiple if structure, you should always incorporate an else clause to check for surprises. It doesn’t need to do much but inform you that something has gone terribly wrong.

It’s Time to Switch Your Thinking

The dice problem is a special type of branching, where you have one expression (the die) that could have multiple values (1 through 6). Many programming languages include a handy tool for exactly this type of situation. Take a look at Figure 3-5, where you’ll see yet another variation of the die roller.
Ancient Roman dice, useful if we come across any ancient Romans.
Figure 3-5:
Ancient Roman dice, useful if we come across any ancient Romans.
Once again I start with an ordinary 1 through 6 integer and assign a new value based on the original roll. This time I use another structure specialized for “one expression with lots of values” situations. Take a look at the code:
tmp7B40_thumb_thumb

Creating an expression

The switch structure is organized a little bit differently than the if with a bunch of else ifs business.
The switch keyword is followed immediately by an expression in parentheses. The expression is usually a variable with several possible values. The switch structure then provides a series of test values and code to execute in each case.

Here’s how to create a switch statement:

1. Begin with the switch keyword.
This sets up the structure. You’ll indent everything until the right brace (}) that ends the switch structure.
2. Indicate the expression.
This is usually a variable you want to compare against several values. The variable goes inside parentheses and is followed by a left brace({).
3. Identify the first case.
Indicate the first value you want to compare the variable against. Be sure the case is the same type as the variable.
4. End the case description with a colon (:).
Be careful! Case lines end with a colon (indicating the beginning of a case) rather than the more typical semicolon. It’s easy to forget this.
5. Write code for the case.
You can write as many lines of code as you want. This code will only be executed if the expression is equal to the given case. Typically all the code in a case is indented.
6. Indicate the end of the case with a break statement.
The break statement tells the computer to jump out of the switch structure as soon as this case has been evaluated (which is almost always what you want).
7. Repeat with other cases.
Build similar code for all the other cases you want to test.
8. Trap for surprises with the default clause.
The special case default works like the else in an else if structure. It manages any cases that haven’t already been trapped. Even if you think you’ve got all the bases covered, you should put some default code in place just in case.
You don’t need to put a break statement in the default clause, because it always happens at the end of the switch structure anyway.

Switching with style

The switch structure is powerful, but it can be a little tricky, because the format is a little strange. Here are a few handy tips to keep in mind:
You can compare any type of expression. If you’ve used another language (like C or Java) you might have learned that switches only work on numeric values. JavaScript switches can be used on any data type.
It’s up to you to get the type correct. If you are working with a numeric variable and you compare it against string values, you might not get the results you’re expecting.
Don’t forget the colons. At the end of most lines, the switch statement uses semicolons like most other JavaScript commands. The lines describing cases end with colons (:) instead. It’s really easy to get confused.
Break each case. Use the break statement to end each case, or you’ll get weird results.
If you’ve got some programming experience, you might argue that another option involving something called arrays would be a better solution for this particular problem. I tend to agree, but for that, look ahead to Chapter 5. Switches and if – else if structures do have their place, too.

Nesting if Statements

It’s possible to combine conditions in all kinds of crazy ways. One decision might include other decisions, which could incorporate other decisions. You can put if statements inside each other to manage this kind of (sometimes complicated) logic.

What’s this L337 stuff?

Leet (L337) is a wacky social phenomenon primarily born of the online gaming community. Originally it began as people tried to create unique screen names for multiplayer games. If you wanted to call yourself “gamer,” for example, you’d usually find the name already taken. Enterprising gamers started substituting similar-looking letters and numbers (and sometimes creative spelling) to make original names that are still somewhat readable. The practice spread, and now it’s combined with text messaging and online chat shortcuts as a sort of geek code. Get it? L337 94m3r is “Leet Gamer,” or “Elite Gamer.” Before you ask, I don’t know why the referee is sometimes a surfer and sometimes a L337 94m3r. It must have been some sort of bizarre childhood circumstances.
Figure 3-6 shows a particularly bizarre example. Imagine you’re watching the coin toss at your favorite sporting event. Of course, a coin can be heads or tails. Just for the sake of argument, the referee also has a complex personality. Sometimes he’s a surfer and sometimes he’s a L337 94m3r (translation: elite gamer). The figure shows a few tosses of the coin.

This is getting pretty strange, so you might as well look at some code:

tmp7B41_thumb_thumbHeads or tails? Surfer or gamer?
Figure 3-6:
Heads or tails? Surfer or gamer?

Building the nested conditions

Once you understand how nested if structures work, you can see how this all fits together. The following refers to the example in the previous section:
1. You flip a coin.
I just used a variation of the die-rolling technique. A coin can be only heads or tails, so I rolled a value that would be 1 or 2 for the coin variable.
2. Flip another coin for the personality.
The referee’s persona will be reflected in another random value between 1 and 2.
3. Check for the surfer.
If the character roll is 1, we have a surfer, so set up an if statement to handle the surfer’s output.
4. If it’s the surfer, check the coin toss.
Now that you know it’s a surfer speaking, you’ll need to check the coin for heads or tails. You’ll need another if statement for this.
5. Respond to the coin toss in surfer-speak.
Use alert() statements to output the result in the surfer dialect.
6. Handle the L337 character.
The outer if structure determines which character is speaking. The else clause of this case will happen if character is not 1, so all the LEET stuff goes in the else clause.
7. Check the coin again.
Now you know you’re speaking in gamer code, determine what to say by consulting the coin in another if statement.

Making sense of nested ifs

As you can see, nested if structures aren’t all that difficult, but they can be messy, especially as you get several layers deep (as you will, eventually). Here’s a batch of tips to make sure everything makes sense:
Watch your indentation. Indentation is a great way to tell what level of code you’re on, but be vigilant on the indentation scheme you choose. An editor like Aptana, which automatically indents your code, is a big plus.
Use comments. It’s easy to get lost in the logic of a nested condition. Add comments liberally so you can remind yourself where you are in the logic. Note that in the examples in this chapter I specify which if statement is ending.
Test your code. Just because you think it works doesn’t mean it will. Surprises happen. Test thoroughly to make sure the code does what you think it should do.

Next post:

Previous post: