Week 2: Loops with for and while

Outcome: Students will learn basic control flow structures, for and while for repeating code execution under certain conditions. Students will also be exposed to basic cryptography, and its strong relationship to computation.

What we will do:
  • Concept of for loops and while loops

  • Exercise: ASCII Animation

  • Exercise: Prime solver

  • Exercise: Caesar cipher

Concept of for loops and while loops

To start off, let’s recap on some printing exercises. Picture what you need to do to print these numbers on your console.

0
1
2
3
...
...
99
100

You will need to type print(n) for each number n. Imagine doing this for numbers 0 to 100. Doing this can get exhausting and does take more time that we would want. Here, we’ll introduce for loops!

for loops

For loops are amazing in a sense that they make repetitive tasks a piece of cake. First, type this into the editor:

for n in range(6):
    print(n)

As we can see, it gives the same exact output that we wanted to achieve without us typing print(n) for each and every number n.

Note

The range constructor allows you to iterate over an integer range. The format is range(start, stop) or range(stop), with the latter beginning from 0. For more info, Google it :)

Now, remember how we created lists?

my_zoo = ['elephant', 'tiger', 'dinosaur', 'dolphin', 'flamingo']

And how we printed lists before was:

print(my_zoo)

Which gives:

['elephant', 'tiger', 'dinosaur', 'dolphin', 'flamingo']

Now, let’s say we want to print out the contents of our list, but with each item on its own line:

elephant
tiger
dinosaur
dolphin
flamingo

In short, we want to look at each number process them separately. We can achieve this by typing into Spyder as follows:

for animal in my_zoo:
    print(animal)

At this point, have you pieced together the syntax for for loops? Here is the breakdown.

for var in iterable:
    # This indent is important! Use the Tab key to indent
    # It tells Python to loop over the chunk of code here
    # 'var' is a variable that exists within the loop
    # it refers to the nth item in the iterable, in the nth loop
    # Do something with 'var', such as the following
    print(var)

You will want to be careful with your variable names inside and outside the for loop. Try the following:

# We define x outside the for loop
x = 'I am x outside the for loop!'
list_of_x = ['I am x!', 'I am also x!!', 'Me three x!!!']
print(x)

# We re-use 'x' as the loop variable:
for x in list_of_x:
    print(x)

# So ... what is 'x' now?
print(x)

You should see the following:

I am x outside the for loop!
I am x!
I am also x!!
Me three x!!!
Me three x!!!

Therefore, we see that loop variables will persist i.e. still remain after the loop is completed. For this reason, we conventionally like to reserve i as a loop variable.

Nested for loops

What if we want to do a for loop in a for loop? These are what we call nested for loops.

Let’s say you want to open a potion shop, and want all potions to have a bipartite name (i.e. two parts). You think of a list of words that are suitable in front, and a list of words suitable at the back. You want to see all combinations of words and choose your potion names from there. The fact that your newfound knowledge in Python will come in handy fills you with determination.

words_in_front = ['lemongrass', 'eternal', 'kampung-style', 'unbelievable', 'gypsy']
words_at_back = ['zing', 'spice', 'danger', 'espresso']
## YOUR CODE HERE

while loops

We’ve seen how you can use for loops to iterate over a known range. But … what if you don’t know the range in advance?

There is another way to write loops, by using the while loop. If you know how many times you want to loop, by all means use for loops. However, if you don’t know exactly how many times to loop, then it’s best to use while loops. while loops ends when a specific condition is met while for loops end when the number of iterations are met. Now, let’s look at the syntax of while loops to see what this means.

Let’s use the same objective we had before with the for loop, i.e to print all numbers from 0 to 100. This is how we would put it in a while loop:

# We need to instantiate, i.e. create 'i'
# Last time the 'for' loop created it for us
i = 0

# While the condition is True, keep going!
while(i < 100):
    # Do something
    print(i)

    # In this case, we keep a counter
    # 'for' loops do this automatically
    # What happens if we don't have a counter?
    i = i + 1

The danger with while loops is that your loop might never end, as the end state is never met. Wonder what will happen if you try the following?

while(True):
    print('.', end='')

Note

Press Ctrl + C to interrupt the console. This is equivalent to pressing the red stop square above Spyder’s IPython console. If the console still does not respond, restart the console in Spyder from the menu bar. If somehow nothing is working, turn your computer off and on again.

Exercise: ASCII Animation I

Use Python to animate the ball moving from the left to right by printing the ball’s position on console. We want the code to output the following:

[O___________________]
[_O__________________]
[__O_________________]
[___O________________]
[____O_______________]
[_____O______________]
[______O_____________]
[_______O____________]
[________O___________]
[_________O__________]
[__________O_________]
[___________O________]
[____________O_______]
[_____________O______]
[______________O_____]
[_______________O____]
[________________O___]
[_________________O__]
[__________________O_]
[___________________O]

The output shown above has the character ‘O’ move from left to right, for every next line printed.

There are many methods to solve this problem. Hint: You can do 5 * ‘_’ to output _____, which is 5 underscores in a row.

Begin with the following template, and pay attention to the comments:

LENGTH = 20 # Use this as length of animation
PAUSE = 0.1

import time
# Use `time.sleep(PAUSE)` after printing a line
# to prevent the computer from going too fast!

## YOUR CODE HERE

Exercise: ASCII Animation II

Repeat ASCII Animation I, following the instructions below carefully:

i. make your code print on the same line:

# `line` contains your string to print

# Original
# print(line)

# Change to the following
# You actually only need to introduce the line carraige character at the end,
# shouldn't matter how you do it. Spyder has known issues with this though:
# https://github.com/spyder-ide/spyder/issues/195
#
# To see this in Spyder, select in the menu bar:
# Tools -> Preferences -> Run -> Execute in an external system terminal
#
# To revert to normal, do:
# Tools -> Preferences -> Run -> Execute in current console

print(line, end='\r')
  1. make the ball rebound from the right to left, and

  2. make the animation loop indefinitely.

Note

  • \r is the carriage return character. It moves the cursor to the beginning of the line.

  • print automatically ends with \n, the newline character, making each print call begin on its own line. Thus, Specifying end = ‘r’ in print means the cursor will be moved to the front of the line for the next line.

  • Combined, this causes each successive call to print to overwrite the existing line, giving the impression of animation!

Exercise: Prime finder

To repeat the message at the beginning of today’s class, using loops is great when it comes to iterating, or in other words, repeating. One useful application is to check whether a number is a prime number.

A prime number is an integer greater than 1 that can only be divided by 1 and itself. A simple method to determine whether a number is prime or not, is to check all potential divisors one by one. All potential divisors for a number are basically all integers smaller than it, up to one. If the number is fully divisible by any number, we then know it is not a prime number. If we go through all possible divisors, and no divisor works, the number is therefore prime.

Given the description above, find all primes up to 1000 using the following tips:
  • % is the modulo operator. If a % b == 0, this means that a can be fully divisible by b. Keep in mind the definition of a prime number.

  • For your reference, first eight primes are: 2, 3, 5, 7, 11, 13, 17, 19. If you can get these eight right, then your code should be okay.

Use the boilerplate code below as we haven’t covered if/else yet:

NUM = 100

## YOUR CODE HERE
# For loop to iterate over each number
        is_prime = True

        ## YOUR CODE HERE
        # Logic for prime checking

        if is_prime is True:
                print(str(i) + ' is prime')

Exercise: Caesar cipher

As we get to the end of the class, let’s look at one field that has greatly relied on computation: cryptography. In oversimplified terms, it is the art of sending coded messages.

Just to show a peek into the field, from Wikipedia:

A key should, therefore, be large enough that a brute-force attack (possible against any encryption algorithm) is infeasible – i.e. would take too long to execute. Shannon’s work on information theory showed that to achieve so-called perfect secrecy, the key length must be at least as large as the message and only used once (this algorithm is called the one-time pad). In light of this, and the practical difficulty of managing such long keys, modern cryptographic practice has discarded the notion of perfect secrecy as a requirement for encryption, and instead focuses on computational security, under which the computational requirements of breaking an encrypted text must be infeasible for an attacker.

Today, we will be looking at one of the earliest cryptographic methods: the Caesar cipher, best known to be used by Julius Caesar. It works by shifting all letters in the message by a set number down the alphabet. For example, to encode “roses are red” with a shift of 3, we replace A with D, B with E, C with F, etc.

Plaintext: ROSES ARE RED

Ciphertext: URVHV DUH UHG

To translate ciphertext back to plaintext, we simply shift the letters back to the left by three letters.

In this exercise, use for loops to decipher the following ciphertext, as well as identify the shift. Run the following code for hints:

# Converting letters to their integer representation
print(ord('a'))
print(ord('b'))
print(ord('c'))
print(ord('a') + 2)

# Converting integers to letters
print(chr(97))
print(chr(98))
print(chr(99))

# Example: Shifting 'g' to the right by 4 to get 'k'
shift = 4
k_num = ord('g') + shift
print(chr(k_num))

# Example: Shifting 'x' to the right by 5 to get 'c'
shift = 5
x_num = ord('x') + shift
print(chr(x_num))

# Oops!
# Pay attention to where the alphabets begin and end!
print(ord('a'))
print(ord('z'))

# One more time!
# Remember that we have 26 letters in the alphabet
# Example: Shifting 'x' to the right by 5 to get 'c'
shift = 5
x_num = (ord('x') - ord('a') + shift) % 26 + ord('a')
print(chr(x_num))

# Printing each character in a string
# Remember that a string is basically a list of characters?
for i in 'this should be printed on a single line!':
        print(i, end='')

# Note that a blank space has a number too!
# You will want to skip spaces to not confuse yourselves
print(ord(' '))

# This is how to skip spaces
string_with_spaces = 'this is how to skip spaces'
for i in string_with_spaces:
        if i == ' ':
                continue
        else:
                print(i, end='')

Go ahead and get started with the ciphers below:

cipher1 = "jhlzhy jpwolyz jhu il jyhjrlk if mylxblujf huhsfzpz"
cipher2 = "lo yv yorqb clozfkd xii mlppfyib pefcq zljyfkxqflkp"
cipher3 = "fsqoxobo mszrobc swzbyfo ezyx mkockb mszrobc li"
cipher4 = "caqvo i lqnnmzmvb apqnb ib mikp xwaqbqwv qv bpm bmfb"
cipher5 = "sldmprslyrcjw uc ugjj lm em mtcp rfc bcrygjq md tgeclcpc agnfcpq"
cipher6 = "qtrpjht rdktgxcv iwtb lxaa gtfjxgt sdjqat iwt pkpxapqat raphh ixbt"
cipher7 = "exw wkdwv zkb zh kdyh d olvw ri olqnv xqghu wkh ixuwkhu uhdglqj vhfwlrq"

Conclusion

Take-away message for these week: Problems that can be iterated can be solved by looping, which allows us to make use of the computational advantage of computers :)

Further Reading