Variables, decisions, and procedures - Hello App Inventor!: Android programming for kids and the rest of us (2015)

Hello App Inventor!: Android programming for kids and the rest of us (2015)

Chapter 5. Variables, decisions, and procedures

In this chapter, we’ll experiment with three powerful programming ideas. First we’ll look at how programs can remember and use pieces of information using variables. You’ll learn how programs can ask questions and make decisions using comparison operators and control blocks. Then we’ll look at how you can split up programs into reusable chunks called procedures, and why you will want to do this. Along the way, we’ll also look at some debugging and commenting tools that will help you troubleshoot pesky errors (programmers spend lots of their time doing this).

Remembering useful things

Often you’ll want an app to remember something that just happened so it can do something else later. Here are some examples:

· Keeping score —How many coins have been collected? How many lives have been lost? In a fitness app, you might want to remember how many steps someone has taken during a run.

· Tracking other game events —For example, a player may have picked up a magnifying glass; if they have it later, they can use it to examine a fingerprint.

· Storing a list of contacts —A text message uses contacts in a communications app.

· Using the start and end destination in a navigation app —This way, you know how far you’ve travelled and how far you have to go.

Sometimes you only need to store information while the app is running (like a game score), so you use a variable stored in the phone’s working memory (see the next Learning Point about RAM). Variables are temporary—if you restart the app or switch off the phone, you’ll be starting with no memory of what happened before. Sometimes you want the app to remember information even after the phone is switched off, like a list of contacts or high scores—this is called persistence. To make data persistent, you can save the variables to a storage device and then load them back into the phone’s working memory the next time the app runs (see chapter 11 for how to do this using the TinyDB database). Your phone is likely to have two places to store data permanently: internal storage (the phone’s built-in memory that can’t be removed) and a memory card.

Learning Point: Random access memory (RAM)

Variables are stored in your phone’s working memory, called random access memory (RAM). It’s random access because the computer in your phone can jump right in and retrieve data from any part of this memory without having to go through all the memory in sequence. When you use a dictionary, you use random access by jumping to the beginning letters of the word you’re searching for.

When you stop an app or turn off the phone, the RAM you were using gets wiped. It’s sometimes called volatile memory.

Total recall: naming and retrieving variables

Just storing information in the phone’s memory isn’t enough—you need some way to retrieve it, and for that you give each variable a name. You might have come across this idea in algebra, where you say something like x = 100: that means whenever you write x, you mean 100. Computer variables are similar to algebra variables, but they can store lots of types of information (not just numbers). They can also have labels that mean something (instead of just x). Can you work out what these variables might be used for?

· Score = 120

· Sex = “F”

· Surname = “Moriarty”

· ArrivedAtDestination = False

These examples show that variables can be different types. Score is a number. Sex and Surname are text variables (sometimes called strings). ArrivedAtDestination is a Boolean variable that can be either true or false.

You’ll start out using variables by making a simple Flattery app that remembers and uses somebody’s name. Then we’ll look at how variables help you write flexible programs.

Flattery app

PURPOSE OF THIS APP

This is an app to make you feel good by telling you how wonderful you are! Inputting your name and clicking each of the four buttons gives you different personalized messages. The app works because it remembers your name in a variable you’ll call UsersName.

APP RATING

ASSETS YOU’LL NEED

Four button images.

You’ll stage what happens in this app so the user can’t click a flattery button (Happy, Sing, Friends, or Dance) until they have entered their name and you’ve stored it in a variable to use later. Here’s how the entire app will look when you’re finished:

1. Setting up the screen

When the app starts, only the Start button and FlatteryLabel are showing. To do this, set MainTable’s Visible property to Hidden in the App Inventor Designer (see the previous Flattery app setup table). Hiding any screen arrangement also hides everything inside it, so all the buttons are hidden, too. Next, use the setup table to set up your screen. Don’t forget that you can continue to work on hidden elements in App Inventor by checking Display Hidden Components in Viewer.

2. Coding the blocks: creating a UsersName variable

Creating a variable means you tell App Inventor its name (or label) and what kind of thing it is (text, number, Boolean, list, and so on). Switch to Blocks, click Variables in the Built-in list, and choose the top orange block that says initialize global [name] to. Initialize means to create a new variable. The variable is global because you can use it in any block anywhere in the app. Name is the name or label—you don’t want it to say name, you want to call it UsersName—so change this now (click the word name, and type over it).

To tell the app that this variable will hold text, plug an empty text block into it. The final result should look like this.

You’ve created a variable called UsersName that can store some text.

3. Getting and storing UsersName

When the user clicks the Start button, you want to pop up a notifier. This takes you all the way back to the Hello World! app—can you remember how to do it? There is a small difference, though: in Hello World!, you just had a message and button, but you want this notifier to show an input text box. You’ll need to use the ShowTextDialog notification function block.

When the user clicks the button and the notifier pops up, you can’t store the user’s name immediately—they haven’t had time to type it in yet! The time to store their name is when they have clicked the OK button—and in your AskNameNotifier blocks, there’s a notifier event handler for that called AfterTextInput. Add it to your workspace now.

Did you notice that an extra orange response argument came along with your After-TextInput block? This argument can tell you what someone typed into the notifier. So if I type Carl and click OK, the value of response is “Carl”—and that’s exactly what you want to store in your variable. Changing a variable’s stored value means you need to create a set block—in this case, set global UsersName. Then you plug in the value of the response argument like this:

4. Revealing the buttons

There’s one other vital thing to do after the user enters their text and clicks OK: you need to display the four buttons in the hidden MainTable. You did something like this in chapter 2’s Ewe Scared Her! app by setting a component’s Visible property to True for visible and False for hidden. It’s the same again here, so the final block looks like this:

5. Stringing it all together: making the flattery messages

When the user clicks the Happy, Sing, Friends, or Dance button, the app changes Flattery-Label to display a related personalized message with the user’s name in it. It does this by retrieving the user’s name, which you just stored, and sticking it onto a premade sentence. As an example, if you join together UsersName and the sentence “, just seeing you makes me smile!” you will see “Carl, just seeing you makes me smile!” To do this joining, you’ll use a Built-in > Text block called join.

The event handler triggers are straightforward: one Button.Click event for each button. Let’s do the HappyButton.Click block first. Select and join these blocks:

You use the join block to put the two parts of your message (UsersName and flattery text) together like so:

You can change the messages, if you like, and you can play around with whether the name is included at the beginning, end, or middle of the message. One thing to bear in mind is that if you join UsersName Carl to the message “is an App Inventor”, the result will be “Carlis an App Inventor”—so you’ll have to make sure the message part always has spaces or punctuation marks in the right places.

That’s it—you should have a fully functioning Flattery app. Fire it up, enter your name, and click the buttons to see how great you truly are! You’ll adapt this app in a sneaky way in the next section so that you can play a prank on your friends.

Taking it further

1. Skip ahead to chapter 11 to look at the TexttoSpeech component. Then have the app also speak the flattery messages. We find the robotic voice telling us what good dancers we are hilarious!

2. Once the user has entered their name, either hide the Start button or, even better, change its text to say “Click to Change Name”.

Learning Point: Variables vs. text boxes

In the Flattery app, you could have achieved a similar effect by putting a TextBox on screen for the user to type their name. Then the app could use something like Textbox1.Text instead of needing a variable. In fact, text boxes and other components that let you input information can be thought of as kinds of variables—they let you store data, and they have names. So why don’t you use them instead of variables? Because text boxes are often useful, but

· They take up space and can quickly clutter the screen. Imagine if you needed 5 or even 10 pieces of information from the user.

· You can’t predict when a user may choose to click and change the text box. This may cause the program to crash if it was expecting a piece of data that the user just deleted.

· A variable name like UsersName is easier to read and understand than something like Users-NameTextbox.Text.

· A text box is a relatively large area that users may accidentally click.

· For notifiers, you have to store the result in a variable. The notifier’s response is wiped once the notifier has finished its work.

We aren’t saying that you always need to store data in a variable. Sometimes a text box is fine. But usually, setting up a variable makes more sense.

Decisions, decisions: using variables to choose an action

You now know how to create a variable like UsersName, store a piece of information like “Carl”, and retrieve it later. Variables become even more useful when you know how to use them to make decisions in your apps. To do this, you need to understand how to get apps to

1. Ask a question.

2. Make a decision based on the answer.

Let’s deal with asking questions first. These aren’t big, complex questions like, “How big is the universe?” “What’s the meaning of life, the universe, and everything?” and “What color underpants should I wear?” (The answers, of course, are infinite, 42, and any except mustard yellow.) They’re much simpler questions, like “Is 5 bigger than 4?” “Are you a girl or a boy?” “Does this word begin with z?” “Has the app repeated the same action 5 times?” and “Has the spaceship collided with the asteroid?” All these simple questions use comparison, where you ask whether things are the same or different.

Comparison operators

Computer programs do comparison by using comparison operators. You probably recognize most of them from mathematics lessons. The following tables shows the most useful comparison operators; each comparison block gives (or returns) either a True or False answer. The tables include comparison operators that can be used for text or numbers, and the first table applies to both. In each case, we have listed when each block returns True; for all other cases, it will automatically report False.

Text and number comparison operators

Comparison operator

Block

What does it do?

Equals

Answers True if the two numbers or pieces of text plugged into the sockets are the same

Does not equal

The opposite of equals—answers True if two numbers or pieces of text aren’t the same

Greater than

Answers True if the number in the left socket is larger than the number in the right socket

Less than

Answers True if the number in the left socket is smaller than the number in the right socket

Greater than or equal to

Answers True if the number in the left socket is larger than or the same as the number in the right socket

Less than or equal to

Answers True if the number in the left socket is smaller than or the same as the number in the right socket

Is a number?

Answers True if the item in the socket is a number

Text comparison operators

Comparison operator

Block

What does it do?

Text less than

Answers True if text 1 is alphabetically smaller than text 2 (meaning it’s earlier in the alphabet). For example “Apple” < “Bumblebee” is True.

Text greater than

Answers True if text 1 is alphabetically greater than text 2. For example, “Inventor” > “App” is True.

Text contains

Answers True if the text in the top socket contains the text in the bottom socket anywhere in it. For example, [text “AppInventor” contains piece “Inventor”] is True.

Is text empty?

Answers True if the text is empty—for example, if a user hasn’t entered any text in a notifier box.

These comparison blocks are the basis of all questions. To make a question, you plug values or variables into the comparison block sockets. Let’s take a simple example. If you want to take the Flattery app and check whether the user is called Carl, you can make an equals block as shown here.

Here we have plugged in the variable UsersName on the left side and the value Carl on the right side. You could also plug in the value directly from a text box’s text property.

Now you have a question that will return True or False depending on what the user types in—but what do you do with this information? What does it plug into? For that you have to understand how App Inventor uses control blocks to make decisions.

How can a dumb machine make a decision?

Computers (including phones) are pretty dumb at present—they can just follow simple rules fast—so how do you get them to do things like make decisions? When human beings make decisions, they often start with an “If” statement like these:

· If the price is less than $20, then buy the t-shirt.

· If the movie review is good, then get tickets.

· If the alarm sounds, then leave the building immediately.

Sometimes decisions have several outcomes:

· If the light is green, then go, otherwise stop.

· If the pasta is cooked, then drain it, otherwise cook it for another minute.

Most programming languages have a version of the basic “If ... then do ...” statement, including App Inventor—we’ll call this an if block. The second set of “If ... then, otherwise ...” statements are also found in App Inventor using if ... else blocks. All if statements live in the Built-in > Control drawer. Here’s an example of how a couple of the previous statements would look if you wrote them using App Inventor blocks:

You can also combine decisions using the logical operators and and or. The first example that follows states, “If the t-shirt is orange or purple, then buy it.” The second example states, “If the movie reviews in both Empire and Total Film have five stars, then buy a ticket.”

You’re going to use if ... else blocks now to build a prank version of the Flattery app.

Prankster Flattery app (Personality Judge app)

PURPOSE OF THIS APP

This app looks exactly like the Flattery app, but it only says nice things about you if it recognizes your name—otherwise it says something rude! The app pretends that it’s judging your personality by reading bio-signs from your thumb (we made this up).

APP RATING

ASSETS YOU’LL NEED

A working version of the Flattery app.

The user will enter their name in a notifier box in exactly the same way as in the Flattery app. But you’ll change the code blocks for each Button.Click event so that before displaying a message, the app makes a decision about whether it recognizes your name. If your name is Carl, then the decision looks something like this:

1. If UsersName = Carl (or whatever name you choose when you write the app) ...

2. Then display the usual flattery message ...

3. Else display an alternative rude message.

1. Setting up the app

1. Make a copy of the Flattery app by opening it and clicking Save As. Call it PersonalityJudge.

2. Change the Title property of Screen1 to “Personality Judge”.

3. Change the Text property of FlatteryLabel to “Enter your name and press your thumb onto any button - so that I can read your bio-signals.”

4. Change the Width property of FlatteryLabel to Fill Parent so the whole message fits onscreen.

2. Coding the if ... else blocks

Look at the words that begin the three decision points for this app: if, then, else. That tells you you’ll need some if ... else blocks. In App Inventor 2, you make an if ... else block by getting an if block from Built-in > Control and then using the mutator (blue square) to add anelse, like this:

In the Blocks Editor, you need to alter the code for each of your four Button.Click events (Happy, Sing, Friends, and Dance). For each button, here’s what to do:

1. Create four if ... else blocks (as just explained).

2. Make a comparison block out of the equals comparison, the variable UsersName, and a text block containing the name you want to recognize, and plug it into the if ... else block like this:

3. Now you have to say what to do if the test is true (top socket) or false (bottom socket). If the test is true, you want to display your usual flattery message; so, you can steal/drag this block from the existing flattery Button.Click code and click it into the top socket of if ... else.

4. For the bottom socket, you want to display a joke message (nothing that will offend the user, though—after all, they might be holding your phone when they read it!). The easiest way to do this is to copy and paste the text block from the top socket into the bottom socket and then change the message.

5. Plug the whole if ... else block you’ve just made into your (now empty) Button.Click event. The end result should look like this:

Now repeat these steps for each of the other three buttons. Make up your own rude messages, or you can use ours:

· HappyButton —“It’s not often a chimpanzee presses that button! Hi” UsersName “oo, ooo, ooo, oook!”

· SingButton —“Wow, I’m detecting you can sing like a bird” UsersName “- you honk like a goose.”

· FriendsButton UsersName”, you are the most popular of all your friends. (Shame they’re all imaginary.)”

· DanceButton —“You are a WILD dancer” UsersName“. That’s a Weirdly Inelegant Ludicrous Diva!”

Using creative comparison conditions

The Personality Judge app isn’t terribly practical because every time you want it to recognize and respond to a different name, you have to reprogram the blocks and repackage it for your phone. It would be possible to make it a bit more flexible by combining a number of name check tests using the or condition, say If UsersName = 'Carl' or UsersName = 'Lynne' or UsersName = 'Ellie' or UsersName = 'Daniel'. But that would be a long block onscreen; and if you want to include Susanna in your group, you still need to go back to the app, add the new or, and repackage the app.

Wouldn’t it be more fun if you could directly control whether the app says something nice or rude? It would confuse your friends—they might even believe the app was reading their bio-signs. In this section, you’ll change just the test part of the if ... else blocks to do that.

There are a number of sneaky ways you could tell the phone to do one thing or another. For example:

· Timing events —For example, if you enter a name and wait 5 seconds before clicking OK, the phone gives the nice message; otherwise it displays the rude version.

· Orientation events —The message depends on you tipping the phone in a certain direction after typing the name.

· Voice recognition —For example, the phone listens for a keyword that you say after entering the name (this is probably unreliable, though).

You’re going to do something much simpler, but equally sneaky. You’ll detect whether the user types a space at the beginning of their name (we said it was sneaky). That way, you (and anyone you tell the secret) will get a nice message, and your other friends and family won’t be able to work out the trick. To get started, save a new version of the Personality Judge app with a name like PersonalityJudge2.

Learning Point: Characters and bytes

In programming, a character is usually a number, a letter, or a punctuation mark. It can also mean a control character like Enter or Tab. The easiest way to think about a character is as a key press. Incidentally, have you ever wondered what a byte is? Well, a byte is a way to measure memory; and, conveniently, this is true:

1 byte = 1 character = 1 key press

If you have a device that can store 16 GB (gigabytes), that means you could open a word processor and type 16 billion letters or numbers and save them on your device. That’s because a gigabyte is roughly equal to 1 billion bytes!

App Inventor has lots of text blocks that can search for a piece of text or split up a text block. Take a look at them now, and see which one you think would be best for isolating the first character of UsersName.

Hey—we said to stop reading and go look at the text blocks in App Inventor! Have you done that yet? Really? OK, we believe you.

If you said that the segment block is the one to choose, then level up—you’re thinking like a programmer! The segment block isn’t the only way to do it, but it’s the simplest. Here’s an example of segment in action: the command segment "Apples", start = 1, length = 3returns the text string “App”. Have you figured out what’s going on? Try these for practice:

segment "grind", start=1, length = 4

segment "slaughter", start=2, length = 8

Hopefully you’ve worked out that the segment block takes some text and extracts a block of characters from it. It knows what to extract because you tell it where to begin (start) and how many characters to extract (length).

Question: What segment command could extract “ink” from “think”?

The text you want segment to work on is UsersName, and you want to look only at the first character, so start = 1 and length =1. The final test looks like this:

Duplicate the if ... else block, and insert it into the other three buttons. Now you have a prankster app that should make people scratch their heads puzzling over how it works.

Taking it further

1. Play a positive sound (like a fanfare) for the first part of each if ... else and a rude sound (use your imagination) for the second part. To do this, you’ll need to add sound objects and media in the Designer and then add two Sound.Play blocks in each if ... else block.

2. Change the test in each if ... else block so that it just tests for a number of names. You’ll need to read ahead and find out how lists and for each blocks work in chapter 6.

3. Use lists (chapter 6) and random numbers (keep reading this chapter) to pick a random response (positive or rude) from a list of statements.

Keeping track with comments

Before we move on from the Personality Judge app, there’s one last thing we suggest you do: add comments to your blocks. Comments are notes made by programmers that help them remember how the program works; they’re also useful to other people with whom you share your app code. In addition, writing comments as you go along can help you remember what needs to be done and clarify your own problem solving. Programmers often spend lots of time solving different parts of a problem at the same time, and it’s hard to keep track and easy to get confused or forget something. In summary, comments

· Help clarify your thinking and problem solving

· Help you remember how the program works

· Help people understand and build on your program

You can write anything in a comment, and you can add a separate comment to every single block if you want to. To add a comment to a block, right-click the block and select Add Comment. You’ll see a blue question-mark icon appear on the block to indicate a comment has been created. Click it, and a yellow text box opens that you can type in (the cursor doesn’t always flash, but you can still type). You can move the position of the comment by clicking and dragging, you can collapse or minimize a comment by clicking the question mark. Here are some examples:

From now on, we suggest you use comments whenever you want to remember something for the future, you have questions, or you want to clarify your thinking about how a program works. Keep your comments short (the ones we used are a little wordy)—this helps make your programs easy for others to understand.

Changing variables

You know how to make variables, assign values to them, and use them to make decisions. The final thing you’ll do in this chapter is look at how to change the value of a variable in an app. You’re going to combine all this a little later in the chapter to make a Guessing Game app in which the user has to guess a number that the app has chosen at random. But first, you need to understand random numbers.

Dice Roll app

PURPOSE OF THIS APP

There are many times when you want an app to behave in a random or irregular way. For example, you might want a character in a game to move in an unpredictable way. In this simple example, you’ll simulate a dice roll on your phone—the user shakes the phone to see a new random number. At this stage, you’ll just display a number; later you’ll make the result look more like an actual dice.

APP RATING

ASSETS YOU’LL NEED

Optional: six dice images (dice_1.png–dice_6.png). See “Taking it further.”

1. Programming the blocks

This is a simple app because App Inventor has a block called random integer that generates random whole numbers (integers). You’ll find it in the Built-in > Math drawer. Plug two numbers into it, and it generates a random number between them (inclusive). So, plugging in 5 and 10 means it will pick 5, 6, 7, 8, 9, or 10. In your app, you’ll choose from 1 to 6 as your lowest and highest numbers, because you’re simulating a dice roll.

As you can see, you plug the random integer block into a set DiceLabel.Text block and then plug it all into an AccelerometerSensor1.Shaking event trigger (just like you did with the sheep button in chapter 2).

There you have it—the simplest app you’ve made since Hello World!—and now you know how to make a random whole number. If you ever need a random fraction for something, there’s a sister block to random integer called random fraction that doesn’t need a high and low value—it generates a random number between 0 and 1.

2. Taking it further

We’ve provided some dice-face images on the website so that instead of just a label showing the number, you can display a random dice face after each shake. Here are the essential parts of the task:

1. Load all six dice images using the Upload New button in the Media pane at the bottom of Designer. (You need to do this one image at a time.)

2. Delete DiceLabel, and add an Image called DiceImage. Set its image property to dice_1.png (a dice with one spot).

The interface changes are done. There are two ways to tackle the programming of the blocks. One is straightforward but long winded; the second isn’t as obvious but is efficient. Programmers find this kind of thing in lots of situations: they’re always searching for an efficient way of doing things because it saves them time, makes code easier to maintain, and usually makes apps run faster. Let’s look at the two options.

The Long Way Around: Using If ... Then

In this block, you use a variable called DiceNumberRoll. When the phone is shaken, you set DiceNumberRoll to be a random number (1–6).

To decide which image to show, you have six if decisions (three of which are shown here). These show a different DiceImage if their number is chosen.

This is straightforward, but look at all those if statements. The app will process all six of these, even if the first one is true. The only thing that changes each time is the DiceNumberRoll test and the picture that is displayed. These two things match (if the random number is 2, you want Dice_2.png to appear), so wouldn’t it make sense to say, “Pick a number from 1 to 6” and then load the image with that number in its filename? That’s exactly what you’ll do in your super-duper efficient version of the app.

The Shortcut: Concatenating an Image Filename

Concatenating means joining things together (usually text), just like the join block you used earlier. In this case, you’re going to set DiceImage.Picture to be a filename that joins (concatenates) the text “dice_”, then a random number from 1 to 6, and finally “.png”. Put them all together, and you have an efficient way to display a random dice image whenever the phone is shaken.

Of course, it doesn’t have to be dice images you display, and you aren’t limited to six—as long as your image filenames all had the same format and contained a unique sequential number, you could have hundreds of images displayed at random this way. Imagine if you had to make hundreds of if blocks!

The Dice Roll app is one of the simplest in the book. The next app is the most complex you’ve made so far. It brings together everything you’ve learned about variables and random numbers, plus we’ll add some new ideas like using procedures that make your code more efficient and explore the idea of validation. You’ll also learn how to watch variables while the app is running to make sure they’re doing what you expected.

Guess What I Am Thinking app

PURPOSE OF THIS APP

This is a simple guessing game in which the app thinks of a random number that the player has to guess. After each guess, the app tells you whether its number is higher or lower than the guess. Each guess you make reduces your score; and if you take more than 10 guesses, it’s game over. To make things more interesting, you’ll set three levels of difficulty. Easy uses numbers from 1 to 100, Medium from 1 to 200, and Hard 1 to 300.

APP RATING

ASSETS YOU’LL NEED

None, but you might want to add your own sounds for Higher and Lower guesses and also for when the player wins or loses.

1. Setting up the screen

Once you have all your components laid out, your screen should look as shown. Make sure the two vertical arrangements contain the right components. This is because you want the app to show different things at different times, just like in the Flattery, Personality Judge, and Ewe Scared Her! apps. That’s why the Guess-Arr arrangement’s Visible property is set to Hidden.

To begin with, you’ll display the screen in step 1, shown next. Once the user clicks a difficulty setting, you’ll hide the SelectDifficultyArr arrangement and show the GuessArr arrangement that contains all the components shown in step 2. If the user clicks the Reset Game button, you’ll reverse the process to go back to step 1.

Think about the app in three stages:

· Initialization —Where you’ll set up the variables and figure out how step 1 works

· Game play —When the user makes their guesses (steps 2 and 3)

· Reset —When the player clicks the Reset Game button to restart the game (step 4)

2. Initializing

Think about what variables you’ll need in the app. There are four—can you guess what they will be? One good way to figure this out is to look at steps 1–4. Three of the variables appear on the phone screen:

· The difficulty setting —Changes the highest number the computer might randomly choose, called HighestNumber

· The score—Score

· The player’s last guessPlayerGuess

Have you figured out the fourth variable? You use it all the time, but it only appears on screen at the end of the game:

· The secret number that the player has to guessSecretNumber

In the Blocks Editor, set up these variables with the starting values shown:

Next, think about what happens when the player clicks one of the three difficulty buttons. First you want to set the HighestNumber variable to match the difficulty level: 100, 200, or 300. Here’s the code block for HardButton.

Duplicate this for EasyButton and MediumButton, but obviously change the values to 100 and 200.

What else does clicking a difficulty button do? It needs to start playing the game by hiding everything in the SelectDifficultyArr arrangement and showing the GuessArr arrangement. Finally, it needs to choose the secret number. Here are the code blocks; you can make them now:

Now here’s a vital programming trick: all three difficulty buttons do exactly these same steps. That’s important, because it means rather than copying and pasting the blocks of code three times, you can instead use a programming idea called procedures that will save you lots of time and make your code easier to understand.

Learning Point: Creating procedures

In chapter 2, you used the Sound.Play procedure—a block of code that has a name. You can create your own procedures and call them whenever you like. But it’s possible to write all the programs in this book without creating procedures—so why use them?

Procedures help programmers save time and make apps that are more understandable and efficient. Procedures are also reusable:

· Saving time —Procedures are used in the real world all the time. When a doctor says “Take his temperature” or a chef says “Fry the sausages,” they’re using a shortcut that saves them having to issue lots of detailed instructions. Even “Tidy your room” is a kind of procedure. Procedures save programmers time because once they have defined a procedure in detail, they can call that procedure whenever they need it. Also, if a programmer makes a mistake in a procedure, they only have to correct it once—whereas if those blocks were copied and pasted into many different places, the mistake would take much longer to fix.

· Understandable apps —Procedures can be given helpful names (just like variables), and that makes understanding someone else’s code much easier. This is a form of abstraction (see chapter 1).

· Efficient apps —Apps that call procedures are smaller, are more efficient, and generally run faster than apps that use lots of repeated code.

· Reusable procedures —If you’ve written a great procedure that could be used in lots of apps, then it’s a simple matter to copy and paste it whenever you need it.

Creating and using procedures is similar to creating and using variables. You find them in the Built-in > Procedures section. Drag out a new to procedure do block now.

Just like with variables, you want to change the name of the procedure to something meaningful—in this case, StartPlaying. Click the word procedure in your new block and change it now.

Now that you’ve created and named a procedure, you’ll find a new block named call StartPlaying in the Built-in > Procedures section of the Palette. Add it to your workspace.

Time to put all the blocks onscreen together now.

Just Do It!

At this point, it would be useful to check that the app is doing what you expect. If you run it on the phone or the emulator and click a button, you should see that the buttons disappear and the game screen appears with buttons and a score. The problem is, you don’t know whether the app has set HighestNumber correctly and chosen an appropriate SecretNumber. App Inventor has a feature that lets you activate individual blocks to test them and also to see what variables are doing while the app is running—it’s called Do It.

Right-clicking any block and choosing Do It executes that block on the phone. Let’s say you want to check whether EasyButton is working. Right-click the set global HighestNumber block and choose Do It, and then repeat this on the call StartPlaying block. You’ll see that the phone displays the game screen.

Many blocks also give you a pop-up comment that tells you their value. You can check that the value of HighestNumber is still 100 and find out what the secret number is by creating temporary get variable blocks and clicking Do It on them. It’s important to realize that these results only update when you click Do It, like a snapshot. If the user clicks a button that changes the values, you won’t see the change until you click Do It again.

In this example, it looks like everything is working as expected—I clicked Easy, and the app has set HighestNumber to 100; it has chosen a random number of 67, which is in the range from 1–100.

Watching variables like this is a useful way to debug programs—if you can’t figure out what’s happening in a program, add some get blocks, activate Do It, and check that blocks and variables are doing what was expected. Remember to delete any temporary get blocks once you’re done. This means that your app isn’t doing unnecessary steps and is easier for others to read.

3. Gameplay

Clicking GuessButton should open a notifier to enter a guess—you did this kind of thing already at the start of the chapter. I thought it might be good to always have the score on screen, so you add a concatenated join text block for the title of the notifier that says something like “Your Score is ... 100.”

When a guess has been made and the player clicks OK, the notifier’s AfterTextInput event fires. You can store their response in the PlayerGuess variable like this.

You could move straight to checking whether they’re correct, too low, or too high. Before we get to that, let’s consider another possibility—what if they type some text like “eighty eight” or “banana”? Unlikely, but how about if they accidentally click OK without entering text? In all these cases, your program will behave strangely, because asking a question like “Does SecretNumber = "banana"?” doesn’t make any sense! If the text isn’t valid, then it must not be processed, and the user must be given an error message and asked to input a different value. You need a way of checking that the player has put in something reasonable or valid—that’s called validation.

Learning Point: Validation (and verification)

There are lots of ways of checking whether a user has entered valid input. They include these:

· Presence check —Has the user typed anything?

· Data-type check —Has the user typed letters, numbers, symbols, or a combination? For example, people’s names can only contain letters, and their dates of birth can only contain numbers.

· Range check —Has the user typed a value in a certain range? For example, the month of birth must be between 1 and 12.

· Format check —For example, date of birth must use the format mm/dd/yyyy.

· Table-lookup check —For example, the user can only choose an item from a list.

All of these will tell you whether input is reasonable or valid—but they won’t tell you whether it’s correct or true. For instance, I could tell you my date of birth is 12/12/1971—a perfectly valid date, but completely untrue. Checking facts by, for example, asking a user to enter data twice is a different kind of check called verification.

For your validation, you’re going to use a combined presence and data-type check—that means the user must enter a number as their guess. The test you’ll use is a Math comparison block called is number. If the player’s answer is a number, that’s fine—you’ll call a new procedure that you’ll create called CheckPlayersGuess. But if the user didn’t enter a number, you’ll pop up a notifier asking them to try again. Here’s the final block:

(Note that you’ll need to define a new procedure called CheckPlayersGuess so you can plug in the call CheckPlayersGuess block.)

Try typing banana—what happens? How about if you enter no data and just click OK? Finally, try typing a number like 55. You have a way of entering a valid guess—now you need to do something with that information. There are three possibilities: the user has entered a guess that is too high, too low, or exactly right. You can check these possibilities with three if ... then blocks. If the user is wrong, you’ll reduce their score—and so you also need to keep track of whether their score is less than zero, at which point they lose and have to start again. You’ll split out this bit into two procedures: CheckPlayersGuess works out which one of the three conditions is true and tells the user whether they’re too high, too low, or correct. Then a new procedure you’ll create called DisplayScore will update the score onscreen and check whether the player has lost.

Have I won yet? CheckPlayersGuess

Here are the if ... then questions and actions in English:

· If PlayersGuess is greater than SecretNumber, output “Too High”. Reduce the player’s score by 10.

· If PlayersGuess is less than SecretNumber, output “Too Low”. Reduce the player’s score by 10.

· If PlayersGuess is equal to SecretNumber, output “You win!”

You should be able to work out how to turn these three questions into blocks. You’ll tell the player the result of these questions by setting LastGuessLabel.Text.

You’ll also need to know how to reduce the score by 10—here’s the block. It says to set Score to itself minus 10; so, for example, a score of 50 becomes 40.

Try creating the three if blocks for the procedure CheckPlayersGuess. Then check what you come up with against the blocks shown next. You use Text blocks to provide the user with a reminder of what they guessed and whether it was high, low, or correct. Then you update their score by subtracting 10 points for a wrong answer (too high or too low).

If the player guesses correctly (the bottom if test) then you probably want to stop them from guessing again (what would be the point?). There are lots of ways to achieve this, but the simplest is to disable GuessButton by setting GuessButton.Enabled to false. This means the button text is greyed out and nothing happens until the app reenables the button, which you’ll do when the player clicks ResetButton. You’ll do the same thing if the player loses, so their score can never be less than zero.

Test the app now—it won’t display the score yet, but everything else should work.

DisplayScore

Games change scores for lots of different reasons. For example, in Temple Run, you get points both for running along a track and for collecting gems. In your game, having a separate procedure for updating the score and checking whether the user has lost is useful because it makes it easy to extend the game if you want to give points for actions other than guessing. For example, you could add a timer so that if the user spends too long between guesses, points are deducted—and at that point, you could also call DisplayScore.

Create a new procedure called DisplayScore now. It will check that Score is greater than zero. If it is, then DisplayScore will set ScoreLabel.Text to the current score; otherwise it will say that the player lost, reveal SecretNumber, and stop the player from guessing again. Remember that “otherwise” questions are usually if ... then ... else blocks, and that’s the case here:

Initialization and gameplay are finished! The final piece of the puzzle is what to do when ResetButton is clicked.

4. Resetting the game

To put the game back to its starting state, you’ll need to reverse your show and hide of the two arrangements. You also need to remember to

· Set Score back to 100

· Re-enable GuessButton

· Clear LastGuessLabel.text

In the block, you can see that to clear LastGuessLabel.Text, you plug in an empty text block.

You should now have a fully functioning guessing game. Of course, if it’s too easy or hard, you can always adjust the HighestNumber settings on the difficulty buttons (don’t forget to change the button labels too).

Taking it further

1. You could add considerable pizzazz to this game by adding sound effects for higher, lower, won, and lost conditions.

2. Change the scoring system so that harder levels give the player more points.

3. Add a Grand Total Score that keeps a running total of all the scores the player has achieved over several games.

4. Add notifiers so the player can enter the starting Score and HighestNumber values instead of clicking a preset difficulty button.

5. Add a timer (see chapter 7) so the player’s score decreases, the longer they take

What did you learn?

In this chapter, you learned the following:

· How to create, name, set, change, and use variables

· How to join text and variables together into one text string, and how to use a segment block to pull out a piece of text

· How to ask questions and make decisions using comparison operators and if ... then control blocks

· How to generate a random number

· How to use debugging tools, comments, and the Do It function to manually activate a block and use these debugging tools with a get variable block to watch variable values.

· Why procedures are important and how to create and use them

· How to validate data

Test your knowledge

1

Using the block above, decide whether these T-shirts would be bought:

1. A 20$ yellow t-shirt

2. A 15$ green t-shirt

3. A 1$ red t-shirt

4. A $20 red t-shirt

2

Which validation tests could you choose in the following situations: presence check, data-type check, or range check? (You can choose more than one.)

1. Checking whether someone’s age is between 8 and 16

2. Checking whether a telephone number is valid

3. Checking whether a user has entered their name

4. Checking whether a price has been entered on an item for sale

3

Write a segment command like this example Segment "Apples", Start = 1 Length = 3 to extract the following text:

1. grin from grinch

2. itch from stitch

3. tent from ostentatious

Try it out

1

Add a dice roll sound and/or animation to the Dice Roll app.

2

Make a percentage discount calculator that lets you input a percentage and then applies it as a discount to any amount you type in. This is handy for checking stores that offer “15% off all marked prices” type deals.

3

Add a stats counter to the Spooky Sound FX app that keeps track of how often each sound is played by displaying a counter under each button. Add a label that states the most popular sound and updates after each button click (use a procedure).

4

Create an area calculator for rectangles. Extend it to work for other shapes like circles and triangles.

5

Change the size of dots and lines in the Graffiti Artist app from chapter 3. Start with a copy of the app and add two buttons that call notifiers to let you set LineSize and DotSize variables. (Hint: Use Dotsize to set the radius of WallCanvas.Circle, instead of using the value 5. Use LineSize to change the width of the line—you’ll need to add a set WallCanvas.LineWidth block from WallCanvas.)