lec-14
I will only mark the 2 files that were included in the starter code.
Let's do a brain dump: write down everything you can remember - words, phrases, pictures, whatever - about things we covered in lecture and lab last week.
You've got 1 minute.
⦾ counted loops
⦾ sentinel loops
⦾ loopsies
Some textbooks, sites, and instructors suggest categorizing while loops...but agreement on the definition of these further categorizations isn't always great.
This can be pretty confusing - especially when you're first learning this stuff!
Nevertheless, since our department uses certain terms in certain ways, it's best if I bring them up, since you'll be encountering them over your stay here.
Flavour 1
Do something a specific number of times.
counter = 0
DESIRED_COUNT = 4
while counter != DESIRED_COUNT:
# do something
print('something')
counter += 1
Flavour 2
Do something until some upper/lower bound is reached (or exceeded).
counter = int(input("times to loop? "))
while counter != 0:
# do something
print('something')
counter -= 1
counting UP version
counting DOWN version
curr_val = int(input("Yer number? "))
UPPER_BOUND = 14
while curr_val < UPPER_BOUND:
# do something
print('something')
curr_val += 2
counting UP by 2's version
curr_val = int(input("Yer number? "))
LOWER_BOUND = 2
while curr_val > LOWER_BOUND:
# do something
print('something')
curr_val -= 3
counting DOWN by 3's
Flavour 1 is just a specific case of flavour 2!
We could also use <0 here.
In fact, it might even be a better idea?....
🙋🏻♂️❓🙋🏻♀️While we're here...can you identify the 6 required parts of any while loop here?
def sing_that_song():
number_of_bottles = 99
while number_of_bottles > 2:
print(f"{number_of_bottles} bottles of age-appropriate beverages on the wall,")
print(f"{number_of_bottles} bottles of age-appropriate beverages,")
print("take one down, pass it around,")
number_of_bottles = number_of_bottles - 1
print(f"{number_of_bottles} bottles of age-appropriate beverages on the wall,")
print()
# other stuffs here
sing_that_song()
Questions
HONOURS_CUTOFF = 3.6
PASS_CUTOFF = 2.0
def display_grade_stats(num_students: int) -> None:
student_count = 0
num_honours = 0
num_passed = 0
num_failed = 0
while student_count < num_students:
gpa = float(input(f"Student {student_count + 1} GPA: "))
if gpa >= HONOURS_CUTOFF:
num_honours += 1
if gpa >= PASS_CUTOFF:
num_passed += 1
else:
num_failed += 1
student_count += 1
print(num_honours, num_passed, num_failed)
The bounds on your counted loop do NOT have to be hard-coded in the code itself!
Questions
To be called a counted loop, you only need to be able to figure out how many times the loop will loop when you RUN the code, not when you DESIGN it.
from random import randint
def dice_sum(num_dice: int) -> int:
sum = 0
dice_rolled = 0
while dice_rolled < num_dice:
sum += randint(1, 6)
return sum
Question
from random import randint
def dice_sum(num_dice: int) -> int:
sum = 0
dice_rolled = 0
while dice_rolled < num_dice:
sum += randint(1, 6)
dice_rolled += 1
return sum
from random import randint
def dice_sum(num_dice: int) -> int:
sum = 0
dice_rolled = 0
while dice_rolled < num_dice:
sum += randint(1, 6)
return sum
This error creates an infinite loop.
🙋🏻♂️❓🙋🏻♀️Which of the 3 categories of bug is this?
You've just attached an altimeter to a little birdie. (Go science!)
You plan on releasing said bird into the wild, letting it fly around for a few days, and then capturing it - and the altimeter.
You then want to grab the data off the altimeter so you can get a feel for the different altitudes the feathered fellow flew.
Say that the altimeter records integers representing the altitude (rounded to the nearest whole meter) at fixed intervals of one minute and marks the end of recording with an altitude of -1.
TASK
Write a program that echoes the data in the altimeter's memory to the console in minute : altitude format .
Assume you have a function called next_altitude() which gets the next altitude out of the altimeter's memory.
As an example, if this is what's in the altimeter's memory...
0
5
4
0
10
0
-1
...then this is what we'd want our code to print to the console:
1:0
2:5
3:4
4:0
5:10
6:0
minute #s
altitudes
altitudes
We don't know in advance how many readings there are going to be, so a definite loop won't cut it.
We're going to need an indefinite loop!
altitude = next_altitude()
curr_minute = 1
while altitude != -1:
print(f"{curr_minute}:{altitude}")
curr_minute += 1
altitude = next_altitude()A condition determines what keeps the loop going.
The condition uses a variable - the LCV (loop control variable).
The LCV is given a useful initial value.
The LCV is changed inside the loop.
One or more statements are run while the loop is going. (the loop body)
This has everything we come to expect from a good loop:
What's this step called again?
altitude = next_altitude()
curr_minute = 0
while altitude != -1:
print(f"{curr_minute}:{altitude}")
curr_minute += 1
altitude = next_altitude()The textbook calls this a listener loop.
altitude = next_altitude()
curr_minute = 0
while altitude != -1:
print(f"{curr_minute}:{altitude}")
curr_minute += 1
altitude = next_altitude()Here, we'd never expect to have a negative value for altitude;
we could choose any negative value (like -999), but it's a good idea to keep things simple!
Choosing a reasonable sentinel value isn't always as easy as it seems at first glance - it requires some knowledge about the problem domain!
altitude = next_altitude()
curr_minute = 0
while altitude != -1:
print(f"{curr_minute}:{altitude}")
curr_minute += 1
altitude = next_altitude()I sometimes call these bugs "loopsies", because my brain's an idiot that thinks its clever.
LETTER_LIMIT = 3
print("Enter a 3-letter word, one letter per line.")
num_letters_read = 0
num_lowercase_read = 0
while num_letters_read != LETTER_LIMIT:
letter = input()
if letter.islower():
num_lowercase_read += 1
print("There were", num_lowercase_read, "letters in that word.")
There is ONE loopsie in this code.
What is it? Trace to find it.
How would you fix this bug?
Loopsie: forgot to update the LCV every time through the loop. Super-common bug!
oops!
dial_reading = int(input("dial reading? "))
while dial_reading < 0 and dial_reading > 10:
dial_reading = int(input("dial reading? "))
print("The dial is set to", dial_reading)
There is ONE loopsie in this code.
What is it? Trace to find it.
How would you fix this bug?
Loopsie: that loop condition isn't what you think it is...
def damage_from_enemy():
return 3
def fight_unbeatable_foe(hit_points):
while hit_points != 0:
print(f"Ow! {hit_points} hp left!")
hit_points -= damage_from_enemy()
fight_unbeatable_foe(4)There are TWO loopsies in this code.
What are they? Trace to find it.
How would you fix these bugs?
Loopsie: that loop condition is too picky!
Loopsie: that loop condition is too picky!
Loopsie: that print happens too soon!
low_bound = int(input("lower bound? "))
high_bound = int(input("upper bound? "))
curr_num = low_bound
num_odds = 0
while curr_num < high_bound:
curr_num += 1
if curr_num % 2 != 0:
num_odds += 1
print(f"# odds in [{low_bound},{high_bound}]: {num_odds}")
Loopsie #1: counted loop condition is off-by-one
Loopsie #2: LCV is changing too soon
There is TWO loopsies in this code.
What is it? Trace to find it.
How would you fix this bug?