Jump to content
New account registrations are disabed. This website is now an archive. Read more here.
  • entries
    15
  • comments
    11
  • views
    14,482

Lesson 7: Flow Control -- Looping

kellessdee

881 views

Lesson 7: Flow Control - Looping

 

Ah, looping. Loops, in my opinion, are what separate a "script" from a "program." So, here comes the obligatory...

 

What is a loop?

 

Think of the word loop, in the terms of a song loop -- we say a song is looping when it repeats, once it reaches the end.

A loop in programming, is generally a block of code that is repeated any arbitrary number of times.

For example, at its very essence, all a video game is, is a huge loop continuously taking input and reacting based on the input and the game's current state, until the player quits the game.

So how does it work? Well, in ruby, there are actually many ways to "loop" or iterate -- as it's commonly referred to as -- let's start with the while loop.

while condition do
 # Loop block
end

The `do` portion of the while - loop syntax is optional --

while condition
 # Loop block
end

works as well.

 

So, "while" the "condition" evaluates to true (anything except false or nil), execute block. The while loop will continuously repeat until condition is false or nil.

Be Careful -- Endless loops. Endless loops refer to a loop that never ends. This happens because the condition never becomes false. If you get stuck in an endless loop, usually CTRL + C will break the loop.

As a programmer, we need to have some kind of control over how long a program repeats its statements.

One common method of loop control, is through use of a counter:

i = 0
while i < 5
 puts "Hello!"
 i += 1
end

the output would be:

Hello!
Hello!
Hello!
Hello!
Hello!

How did this happen?

The interpreter sets a variable, `i`, to 0. It then enters the loop:

Is i less than 5? yes, display "Hello". i is now 1

Is i less than 5? yes, display "Hello". i is now 2

Is i less than 5? yes, display "Hello". i is now 3

Is i less than 5? yes, display "Hello". i is now 4

Is i less than 5? yes, display "Hello". i is now 5

Is i less than 5? no, i is equal to 5, stop looping.

We can use a variable as a counter, and use an arbitrary maximum number of iterations and then by counting the number of iterations we can determine when to stop executing the block.

Here's a better example:

"In mathematics, the factorial of a non-negative integer n, denoted by n!, is the product of all positive integers less than or equal to n. For example, 5! = 5 x 4 x 3 x 2 x 1 = 120 " (http://en.wikipedia.org/wiki/Factorial) (Yea, I was lazy and they had a better explanation......)

Er, let's translate this to our code!

Let's say we want a program that takes a number from the user, and calculates that number's factorial.

# Calculate the factorial
print("Enter a number: ")
number = gets.to_i
# Get first number
factorial = number
print("#{number}!\n#{number}")
while number > 1
 # move to next number
 number -= 1
 # get product of n..n-1
 factorial *= number
 print(" * #{number} ")
end
puts("= #{factorial}")

Test:

Enter a number: 5
5!
5 * 4  * 3  * 2  * 1 = 120

Looks good! As you can see, counters can decrement as well. How you do it, will mostly depend on the situation (remember, you don't always have to increment/decrement by 1, either.)

 

Of course, condition can be ANY expression, and is also used to loop based on a program's "current state."

Let's go back to the guessing game we created. Wouldn't it be much better if we let the user keep guessing until they quit or guess the number?

# Set a number to guess
number = 10
# define the current "state"
game_over = false
while !game_over
 # Prompt the user to guess what number it is:
 print("I am thinking of a number. What is it? (Type q to quit) ")
 # Get the guess
 guess = gets.strip
 if guess.upcase == "Q"
   puts("Goodbye!")
   # Change current "state"
   game_over = true
 elsif guess.to_i < number
   puts("Too low!")
 elsif guess.to_i > number
   puts("Too high!")
 elsif guess.to_i == number
   puts("Wow! You got it!")
   # Won the game, change state
   game_over = true
 end
end

 

Now, our simple guessing game is actually a game! Well, mostly. We'd want to randomize the number to make it more of a game, but I will go over random number generation another time. For now, it does what we need. The game will now continuously prompt the user until the variable game_over is true. Notice that, we could have instead made a variable, say, game_playing, and set it to true. Then, while game_playing is true, prompt the user -- either way would work.

 

Before we finish, I'd like to introduce to another form of looping, and some more loop control methods.

The next loop you will learn about, is called the "for" loop. The for loop can be considered a special type of iterator, but for now, just think of it as a loop with very specific bounds. (I will go over more about for and iterators, in a later lesson)

 

Let's go back to the factorial program we made. If you notice, a factorial always loops a very specific number of times. The number of times it loops may be dependant on the input, but it will always be a set value. This is where for loops come in.

for i in 0..5
 puts i
end

produces:

0
1
2
3
4
5

So how does this work?

Well, the syntax is:

for variable in set
 # Block
end

For loops, will iterate through each item in a "set" (for now, we will only discuss ranges), and store the current object in the set, in the variable 'i'.

So what happened in the above loop? Well, in Ruby, a Range object (denoted by min..max or min...max), is actually a representation of a set of numbers from min to max.

Be careful with ranges, 0..5 means 0 to 5 inclusive, while 0...5 means 0 to 5 exclusive:

0..5 => 0, 1, 2, 3, 4, 5

0...5 => 0, 1, 2, 3, 4

Then, based on this analysis, i is first set to 0 (first item in the set), then we print i in the block. When we move to the next item/iteration, i is then set to 1, and we print it. The loop continues this pattern, until we reach the last item, then when there are no items left to be stored in i, we break out of the loop.

Why is this useful? Well, let's put this to more practical use. Let's go back to the factorial program -- like I promised.

# Calculate the factorial
print("Enter a number: ")
number = gets.to_i
factorial = number
for i in 1...number # 

factorial *= i

end

puts("#{number}! = #{factorial}")[/code]Note, that unfortunately, ranges don't work in reverse. For example, 5...1 is not 5,4,3,2. It will not work. There are ways to reverse ranges, but that would be treading into an area I want to save for another lesson.

 

Ahem, any who, carrying on... (I apologize for a larger amount of "later..."s, I would like, for this lesson, to focus on the concept of loops, without worrying too much about extra technical details, at least not yet)

 

Another good use of for loops, is for generating rows and columns of display. Say, we want to generate a pattern like this:

***************
***************

We could simply hard code a couple puts, and it would work...but what if we want to be able to draw any size?

# Get rows and columns
print("Enter number of rows: ")
rows = gets.to_i
print("Enter number of columns: ")
cols = gets.to_i
# Display pattern
for i in 0...rows
 for j in 0...cols
   print("*")
 end
 print("\n")
end

could produce:

Enter number of rows: 2
Enter number of columns: 15
***************
***************

It may seem silly, but if you can grasp this concept of nested for loops, you will find it VERY useful later on. But what exactly happens?

 

So, rows == 2 and cols == 15.

 

We enter the first loop at i = 0, and the second loop at j = 0.

 

Then j will become 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 (remember, 0...cols is 0 to cols exclusive) and on each iteration, the interpreter will print a `*` on a single line.

 

When we break out of the nested loop, ruby prints a \n (newline character), then i becomes 1.

 

We then reach the nested loop again, and it does the exact same thing, printing 15 `*`s on the next line (notice, 0-14 inclusive or 0-15 exclusive, is 15 different numbers).

 

We break, print a new line, i runs out of numbers (0...rows exclusive => 0, 1) and therefore break from the outerloop, and stop looping altogether.

 

This concept will become very useful, when looping through grid-based data structures. (A single for loop, if you noticed, is meant/really good at looping through list-based data structures).

 

Finally, before I finish loops, I would like to teach you a couple useful control statements for loops -- break, and next.

 

loop do
 # Prompt the user to guess what number it is:
 print("I am thinking of a number. What is it? (Type q to quit) ")
 # Get the guess
 guess = gets.strip
 if guess.upcase == "Q"
   puts("Goodbye!")
   break
 end

 guess = guess.to_i

 if guess < number
   puts("Too low!")
   next
 end

 if guess > number
   puts("Too high!")
   next
 end

 if guess == number
   puts("Wow! You got it!")
   break
 end
end

So, this is a slightly modified version of our guessing game. If you try it out, you might notice it works exactly the same! Let's analyze what I changed.

Firstly, the loop is no longer a while loop...

loop do
 # Code
end

This is just another form of loop that ruby has, that represents an infinite loop -- when the interpreter finds this, it will continuously loop the block of code. (This is useful for if you need to loop, but not based on a certain state/condition).

 

Now, when a guess is made, if the guess is 'Q' or the right number, the loop will "break." break is a keyword in ruby, and is also a special function. It will "break out" of the current, immediate loop, and stop looping (Note, if you use break in a nested loop, it will only break out of the loop it is called from, not all loops).

 

We also, use `next` if the number is incorrect. next is like break (a special function for controlling loops), but what it does, is tell the ruby interpreter to skip to the "next" iteration, meaning next will skip the rest of the block of code, and restart the loop. If used in a for loop, this also means i becomes the next item in the list.

 

Well, that's all for today's lesson! I apologize for taking so long this time. Things are getting busy for me again, and I may take a little bit longer to finish each lesson. I will try my best, however, to keep the lessons coming once a week!

 

Now, I will leave you with a few more challenges:

 

1. Make a simple "menu" script, that will continuously prompt the user to enter a numeric selection, and display a different message based on the input. If the user types "q" or "Q" the menu should stop.

 

2. Write a script that will generate this output:

*
**
***
****
*****
******
*******
********
*********
**********

or, if you're feeling really creative, try making it look like this:

	 *
   ***
  *****
 *******
*********
***********

(Kinda late for Christmas isn't it????)

 

3. The formula for converting degrees celsius to degrees fahrenheit is:

F = C * 9 / 5 + 32

Write a script that will display a Celsius -> Fahrenheit conversion table

from -10 celsius to 40 celsius.

i.e

-10C = 14F
-9C = 15.8F
-8C = 17.6F
-7C = 19.4F
...etc.


0 Comments


Recommended Comments

There are no comments to display.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...