Intro to Python, Chapter 5 – Loops


Baldric groggily opened his eyes and was greeted by a splitting pain in his head. He had been having the strangest dream, something about a crystal, and a snake eating its own tail, and…a singing head of cabbage? Strange indeed. He looked around in the dim torchlight and found himself in a large cell of some sort, gray stone on three sides and thick iron bars on the fourth. The room was filled with all kinds of contraptions of wood and metal, many with straps or chains or hooks. He was glad he didn’t know what they were for, and had no intention of finding out. Trying to move, he found his arms and legs were tied down to a table. He also saw he was garbed in a dreary gray jumpsuit with the number 601 stitched on the breast. The sounds of distant screams reverberated off the walls, and terror surged through Baldric’s veins as he realized where he was. Humanoid Resources.

He took a deep breath and managed to reign in his panic, if just barely. “Great job Baldric, look what you’ve got yourself into now. You just had to join up with a rebel and navigate an underground labyrinth to slay a bureaucratic abomination. Couldn’t have just called it a day. Nope, that would’ve been too easy. Sigh, I’m getting too old for this.” He paused and shook his head. “No, it’s not over yet. I’ll solve this problem just like all the others, one step at a time. First let’s see how sturdy these bars are.”

He attempted to cast pure Fire at the bars, but found he couldn’t channel a drop. It was as if there was a barrier between him and that endless well of Magic he had previously been tapped into. Surely they couldn’t take away someone’s ability to use Magic, could they? Panic rose up inside him again. He reached toward his bonds with his teeth, thinking maybe he could at least gnaw his way off of the table. That was when he noticed numbers on the ground.

He strained his neck trying to get a better look and saw circles of faint green glowing numbers surrounding him, magically inscribed into the floor of his cell. Two concentric circles, in fact, but he couldn’t see all the numbers from his position. He attempted to weave Logic to probe the mystical patterns, and found to his surprise that he could still channel that element at least. With a strand of Logic he mentally scanned the circles and found that each consisted of a sequence of 13 numbers.

>>> outer_sequence = [13, 19, 29, 37, 43, 53, 61, 71, 79, 89, 101, 107, 113]
>>> inner_sequence = [17, 23, 31, 41, 47, 59, 67, 73, 83, 97, 103, 109, 127]

Baldric couldn’t say why, but the outer circle felt like it needed to be added together, and the inner circle felt as if it needed to all be multiplied together. Decidedly odd, but he was fairly certain about it.

“For this outer sequence, I suppose I could just manually add the numbers, 13 + 17 + 19… and so on, but that would be tedious, and this looks like a good opportunity to finally test out loops. And specifically in this case, for loops, which, as I recall, cycle through each object in a series of objects.”

“I’d better test them out real quick first. Let’s see, what if we just have a list of numbers and want to print them all out one by one?”

# note how the contents of a for loop, after the first line, must be indented

>>> for num in [0, 1, 2, 3, 4]:
        print(num)
0
1
2
3
4

“Or what if we have a string and want to print each individual character?”

>>> for char in "abcde":
        print(char)

a
b
c
d
e

# note that the variable name 'char' is arbitrary
# you can use whatever name you want there
# as long as you correctly refer to it inside the loop

“Excellent. Well, lists and strings work with for loops. Maybe integers or floats do too. Or booleans, for that matter.”

>>> for something in 4:
        print(something)

Traceback (most recent call last):
  File "python", line 1, in 
TypeError: 'int' object is not iterable

# got an error looping on an integer

>>> for something in 4.2:
        print(something)

Traceback (most recent call last):
  File "python", line 1, in 
TypeError: 'float' object is not iterable

# another error for a float

>>> for something in True:
        print(something)

Traceback (most recent call last):
  File "python", line 1, in 
TypeError: 'bool' object is not iterable

# and yet another error for a boolean

“Hmm, integers, floats, and booleans aren’t ‘iterable’, but lists and strings are. Interesting. Anyways, it looks like I should be able to use a for loop and add up all the numbers in the outer circle, one at a time.”

outer_total = 0 # initialize the variable we'll add everything to

# iterate over each number in a list of numbers and add them all up, one at a time
for number in outer_sequence:
    outer_total += number
    # add a print statement here if you want to see what's happening at each step
    # print(outer_total, number)

print(outer_total)
815

“Now for the inner sequence, where I’m pretty sure I need to multiply all the numbers together. Nearly identical Magic, I just need to change the starting total to 1 and the operation to multiplication.”

inner_total = 1

for number in inner_sequence:
    inner_total *= number

print(inner_total)
77372585679822157429417

“And now for breaking this thing! Probing the seal, it feels as if…I need to combine these results in some way, probably by multiplying them together. But there’s something else…I think it might need my HR ID number too.”

answer = outer_total * inner_total * 601
print(answer)
37898253054762090041289887855

As soon as Baldric’s Logic printed out the answer, the circles began to dissolve. One by one, starting with the outer sequence, the green glowing numbers evaporated until the entire seal was gone. Baldric attempted to weave Fire, and elemental power surged through him. It had worked!

A door creaked open from down the hall, then crashed closed. Footsteps were approaching, a confident, relaxed stride.

A wave of dread washed over Baldric. He immediately channeled Fire at the ropes holding him to the table and stood up. “I need to break out of here, I won’t let them review my performance! But I need to think, how to escape…I know, I’ll make a key!” He visualized a key that would fit perfectly into his cell door’s lock, then wove Earth into the keyhole, feeling it out, and let the weaves solidify when he thought he had the shape right. He rushed over to turn the key, but it didn’t budge. The key had fused to the keyhole! The footsteps began to hurry, and Baldric backed away from the front of his cell.

“Deep breaths, there has to be a way out of this. Well, if I can’t open the door…I’ll just melt it!”

He channeled pure Fire at the bars of his cell. Nothing happened. He channeled more, strained to pour as much Fire as he could draw on straight into the iron. The metal began to glow, soft at first, then brighter, until it illuminated the hallway, but they didn’t melt. That’s when he saw Cassandra stroll in front of his cell in all her icy beauty, smiling.

“So you were the Emperor’s pawn all along,” Baldric grumbled. “Do your worst, I’m not afraid of the Empire anymore lady. Someday this bureaucratic nightmare will crumble and I’ll be laughing all the way to dwarven heaven when you and your cronies…”

“That day may come sooner than you think,” replied Cassandra, still smiling. She held out her hand, and Baldric saw thick flows of Wind and Water being woven in extremely complex patterns. It looked like Ice Magic. Frantically, Baldric began preparing his own Fire and Earth-based counterattack. “I’m warning you, if you don’t think I’ll…” Baldric trailed off as Cassandra directed her Ice flows at the cell bars, which glowed a deep arctic blue. Baldric shivered at the sudden drop in room temperature. Then she wove a club of Wind and smashed it straight into the iron bars, shattering them like glass. Baldric shielded his face from the frozen metal shards.

“My apologies for earlier Baldric, there was no other way. I didn’t expect you to cause such a commotion with the HR Manager, and events have been moving faster than I can keep up with. How did you manage to defeat the beast? I knew you had a natural talent for Magic, for Logic at least, but obliterating the creature like that…”

“It wasn’t me, I just helped out a little. I met someone named Geofram Hammerfell on my way the Manager’s office.”

“So the Hammer of the Light still lives…there may be hope yet. Where did he go?”

“Not sure, he didn’t say much. But Cassandra, I don’t get it. Are you an Imperial or not? You were with all those Managers, and they wouldn’t be fooled by just any rebel.”

“I’m a defector, Baldric. I was in charge of the Imperial Secret Police, but realized some time ago that the Empire wasn’t what I thought it was. It’s evil to its core Baldric, evil almost beyond comprehension, and something needed to be done about it. Remember the Emperor’s mysterious power source I told you about? It is locked behind an enchanted Door that can only be opened with powerful Logic, far too powerful for me to handle. I needed to find a rebellion-minded Logic user, and that’s where you came in.”

“The Emperor somehow has the power to not only sense but pinpoint Magic use in the city, and when you began channeling he sent me after you. Searching your home, we found evidence you clearly possessed rebellious leanings, but I still needed to find out if you were strong enough in Logic for the task ahead. That request you got at work was from me. It was a test to ensure your powers of Logic were sound, but it was also part of the Logical puzzle whose solution will open the Emperor’s Door. I solved the first part of the puzzle by hand, just shifting every letter by two, which yielded the instructions in the letter. The number you answered with somehow relates to the second section of the puzzle, though I’m not sure how.”

“Then of course I sent you to fetch the Teleportation Circle key in the HR Manager’s lockbox.” Cassandra pulled out a pale green crystal from her pocket and handed it to Baldric. “The Emperor possesses a key as well, but the HR Manager’s was much less risky to go after. Meanwhile I myself, with the help of some scrolls, teleported to the rebel base in the mountains to the south, spoke to them while under a truth-telling spell, and convinced that this plan of mine was their last hope. My two half-elf assistants, who you may have noticed previously, are still with them, briefing them on the layout of the city and defenses of the castle. Once we free the prisoners here, we’ll proceed to the Teleportation Circle, which you’ll need to unlock with the help of that key. Then we’ll transport the rebel army here and move on the Emperor himself.”

Baldric just stood there, trying to process everything he’d just heard.

“In any case, we must move with all haste Baldric. The Emperor is planning something big, something called “Plan Z”, which according to my sources is some sort of ultimate budget-cutting measure. Rumor has it they’re saving up to remodel the whole empire according to an open floor plan. I don’t know what that means, but it won’t be good. So Baldric, I need you to free the prisoners. All of them. You’re the only person I know with enough talent for Logic to do it.

“Each cell block has a different method of sealing. This is cell block A, which has 600 prisoners, you being the latest addition. B has 800 prisoners, and C 1,000. Many of them are rebels and magic users that we will need to complete our plan, though of course some are just here for infractions like being late to work or thinking critically. Regardless, we must free them quickly before the Emperor is alerted to our actions. I’ve taken care of some of the guards already, but more will be coming.”

Cell Block A

The pair left the torture room and Cassandra led him through several storerooms containing large quantities of whips, corpse shrouds, and impaling stakes. They soon came to a large open 3-tiered cell block with catwalks along the perimeter of each tier and staircases connecting them. They were on the top tier, and moving towards the railing of the walkway on this level they got a view of most of the block. Scattered around it were ice sculptures that strongly resembled guards. The cells had no doors or locks of any kind, the Magic seals alone apparently being enough to hold the prisoners on their own. Each cell had a number over it, from 1 to 600.

“I’ll be exhausted long before I can weave enough Logic to break 600 seals. But actually, every seal I can see here looks just like mine did. I’ll bet I can make a function to speed things up, since the same Logic will be needed every time. The only thing that changes is the ID of the prisoner, so that’s the argument that the function will take.”

outer_sequence = [13, 19, 29, 37, 43, 53, 61, 71, 79, 89, 101, 107, 113]
inner_sequence = [17, 23, 31, 41, 47, 59, 67, 73, 83, 97, 103, 109, 127]

def block_A_seal_breaker(id_number):
    outer_total = 0
    for number in outer_sequence:
        outer_total += number

    inner_total = 1
    for number in inner_sequence:
        inner_total *= number

    answer = outer_total * inner_total * id_number
    return answer

With his function completed, Baldric began running from cell to cell, casting his function. He started with the first cell, which contained prisoner #1, and went from there.

>>> print(block_A_seal_breaker(1))
63058657329055058304974855

>>> print(block_A_seal_breaker(2))
126117314658110116609949710

>>> print(block_A_seal_breaker(3))
189175971987165174914924565

>>> print(block_A_seal_breaker(4))
252234629316220233219899420

>>> print(block_A_seal_breaker(5))
315293286645275291524874275

After releasing the fifth prisoner and hearing their incredulous cries of joy, Baldric had to stop and lean against the wall to catch his breath. “There’s no way I can do this for every cell, there’s too many. There’s got to be a better way…wait, what if I used another for loop? For every ID number, I call my function on that ID! I’ll just need to make a list of the numbers to iterate over, from 6 to 600. And I think I should be able to make that list with a while loop.”

id_list = [] # create empty list
id_number = 6 # prisoners with ID's 1-5 freed already, so start with #6

# while loops keep going until their condition is met (or forever if condition is never met)
# this one keeps on going until id_number gets to 601
while id_number 
[6, 7, 8...598, 599, 600]

“And now I can iterate over that list and plug all those ID numbers into my seal breaker function.”

# call the seal breaker function on every id number in the list and print the result
for id_number in id_list:
    print(block_A_seal_breaker(id_number))
378351943974330349829849130
441410601303385408134823985
504469258632440466439798840
.
.
.
37709077082774924866374963290
37772135740103979924679938145
37835194397433034982984913000

The seal-breaking number was rapidly printed for one cell after another, and all the prisoners on that block were released from their magical confines almost instantaneously. Baldric was surprised by a low, rumbling voice behind him.

“You make mistake dwarf.”

Baldric turned around to see the biggest half-orc he had ever seen standing behind him, arms crossed.

“If you add one thing at a time to a list, you should use append() list method.”

Baldric saw the half-orc weave his own Logic. The flows were weak but precise. Perhaps this half-orc didn’t have much power with Logic, but he knew what he was doing.

id_list = []
id_number = 6

while id_number 
[6, 7, 8...598, 599, 600]

“But it is still stupid. No need for a while loop. Just use built-in range() function. Works like this.”

for num in range(0, 5): # also try leaving out the first argument, range(5)
    print(num)
0
1
2
3
4

“And for your spell, it will look like this.”

for id_number in range(6, 601):
    print(block_A_seal_breaker(id_number))

“So now whole seal-breaker looks like this:”

outer_sequence = [13, 19, 29, 37, 43, 53, 61, 71, 79, 89, 101, 107, 113]
inner_sequence = [17, 23, 31, 41, 47, 59, 67, 73, 83, 97, 103, 109, 127]

def block_A_seal_breaker(id_number):
    outer_total = 0
    for number in outer_sequence:
        outer_total += number

    inner_total = 1
    for number in inner_sequence:
        inner_total *= number

    answer = outer_total * inner_total * id_number
    return answer

for id_number in range(6, 601):
    print(block_A_seal_breaker(id_number))
378351943974330349829849130
441410601303385408134823985
504469258632440466439798840
.
.
.
37709077082774924866374963290
37772135740103979924679938145
37835194397433034982984913000

“But if you ever do use a while loop, just make sure the loop finishes. Infinite loops are bad juju.”

Baldric pondered the half-orc’s Logic. “Hmm, built-in functions and methods…they were mentioned in that Book, but I don’t remember much about them.”

Cassandra walked up to Baldric. “Perhaps you can chat with your new friend after we’ve freed the prisoners, hmm?”

“Yeah yeah, I’m on it. What was your name, friend? I’m Baldric.”

“Doomboom. You free prisoners, I smash Emperor.”

Baldric extended his hand, but regretted it even before that massive greenish hand engulfed his own. He thought he could hear his bones creaking.

The prison erupted in chaos. Several crashes sounded simultaneously throughout the cell block, followed by streams of armed Imperial guards. Several rebels fell immediately to flurries of arrows, but soon elemental projectiles were flying in the opposite direction. The screams of the wounded and dying mixed with the crashes and explosions of lethal spells.

“Baldric, we need to get to Cell Block B, now!” Cassandra shouted over the din. He followed Cassandra along the walkway to a heavy iron-reinforced door. She tried opening it with a flow of Wind, but it didn’t budge. Guards were flooding in from another door on this level and heading toward them. Baldric and Cassandra were both readying spells when Doomboom appeared from behind. To Baldric’s suprise, it looked like the half-orc was actually channeling Magic directly into himself! Doomboom’s muscles bulged and in one smooth motion he yanked the door off its hinges and hurled it like a frisbee of death at the oncoming guards, sending them all flying backwards or over the railing. Doomboom looked around for a moment then leapt over the railing himself to join the battle below.

Cassandra looked impressed for only a moment, then shook herself and shouted, “Through here, hurry!” Baldric rushed through the door and into Cell Block B.

Cell Block B

This cell block was much like the last, but one story deeper. And unlike the last one, guards were already waiting and launched volleys of arrows at them as soon as they were through. Cassandra wove a spell faster than Baldric had thought possible, and a wall of ice rose around them just in time to intercept the arrows. She channeled more, and the wall of ice broke down the center and each half went flying towards a different group of guards. This was followed by a barrage of ice spears that impaled guards left and right. Guards elsewhere in the cell block were getting in position for more volleys, and with another of Cassandra’s spells the floor became slick with ice, sending them slipping and falling over each other. Without pausing in her channeling, she shouted over her shoulder, “What are you waiting for Baldric? Get these people free!”

Baldric rushed over to the closest cell, this one containing a gaunt, hopeless-looking halfing, and examined the seal. Again, there were two circles of numbers, each composed of the same numbers as in Cell Block A. But he could sense that different calculations were required for this one: the outer circle numbers needed to all be multiplied together again, but only the first digit of each number. And the inner circle numbers also needed to be multiplied together, but only the last digit of each number.

outer_sequence = [13, 19, 29, 37, 43, 53, 61, 71, 79, 89, 101, 107, 113]
inner_sequence = [17, 23, 31, 41, 47, 59, 67, 73, 83, 97, 103, 109, 127]

def block_B_seal_breaker(outer_sequence, inner_sequence, id_num):
    outer_total = 1
    for num in outer_sequence:
        first_digit = str(num)[0] # convert number to string, select first digit
        outer_total *= int(first_digit) # convert str back to int and multiply into total

    inner_total = 1
    for num in inner_sequence:
        last_digit = str(num)[-1] # convert number to string, select last digit
        inner_total *= int(last_digit) # convert str back to int and multiply into total

    return outer_total * inner_total * id_num

for id_num in range(1, 801):
    print(block_B_seal_breaker(outer_sequence, inner_sequence, id_num))
31122809988480
62245619976960
93368429965440
.
.
.
24836002370807040
24867125180795520
24898247990784000

Again the seals were shattered throughout the cell block, and once again the prisoners rushed out to take up the fight. A guard about to loose an arrow at Baldric was tackled by a familiar looking person. It was Steve from the office!

Cell Block C

Seeing Cassandra was still occupied, Baldric headed by himself towards the door to Cell Block C. He intuitively channeled a combustive mix of Wind and Fire mid-stride and blew the door open as he ran through. There weren’t any guards in here thankfully, just 1,000 more prisoners in varying states of despair. He inspected the seal in the first cell he came to and found the same sequences of numbers in use once again. But this time he sensed that the trick to breaking the seals was somewhat different.

It felt like he needed to loop through both sequences at the same time, concatenate the elements from each list together (i.e. 13 and 17 become 1317) and then multiply all these numbers together. And just like the last two times, that final product needed to be multiplied by a given prisoner’s ID number for the seal to be broken. But the question remained, how could he loop through two loops at the same time? A voice, as if in response to his thoughts, rumbled behind him.

“You need to loop through two lists. This is one way. I will show you a better way later.”

outer_sequence = [13, 19, 29, 37, 43, 53, 61, 71, 79, 89, 101, 107, 113]
inner_sequence = [17, 23, 31, 41, 47, 59, 67, 73, 83, 97, 103, 109, 127]

# use the built-in len() function to calculate the length of the lists
# note you could use length of either list since they have equal length
for i in range(len(outer_sequence)):
    print(outer_sequence[i], inner_sequence[i])
13 17
19 23
29 31
37 41
43 47
53 59
61 67
71 73
79 83
89 97
101 103
107 109
113 127

Baldric pondered the Logic. “Hmm, another built-in function, len(). Those are starting to seem pretty useful. Anyways, I need to break these seals, and fast, before Imperial reinforcements show up.”

outer_sequence = [13, 19, 29, 37, 43, 53, 61, 71, 79, 89, 101, 107, 113]
inner_sequence = [17, 23, 31, 41, 47, 59, 67, 73, 83, 97, 103, 109, 127]
 
def block_C_seal_breaker(outer_sequence, inner_sequence, id_num):
    total = 1
    for i in range(len(outer_sequence)):
        num = str(outer_sequence[i]) + str(inner_sequence[i])
        total *= int(num)
    return total * id_num

for id_num in range(1, 1001):
    print(block_C_seal_breaker(outer_sequence, inner_sequence, id_num))
2517890791215392745475846020056343678468338560034217
5035781582430785490951692040112687356936677120068434
7553672373646178236427538060169031035405015680102651
.
.
.
2512855009632961959984894328016230991111401882914148566
2515372900424177352730370174036287334789870221474182783
2517890791215392745475846020056343678468338560034217000

Baldric let loose his Logic, and one after another the seals throughout Cell Block C were dispelled. The former prisoners took up a raucous cheer, which was echoed from Cell Block B. But the celebrations were cut short by a boom and a tremor. The fortress was shaking. Cassandra’s voice called out from the adjacent block in what must have been a Magically amplified voice.

“Everyone to the roof of Cell Block B, immediately!”

The rebels in cell blocks A and C flooded into B, all of them rushing up a series of stairs and through a trap door to the roof. The room with the trap door just before the roof smelled awful, and Baldric saw why. A pile of rotting corpses wrapped tight in canvas corpse shrouds was stacked in the corner. He figured they must let them pile up for a while, then dump them off the roof and into the lava all at once.

Once up top, Baldric surveyed his surroundings. He was on top the central inverted pyramid of the three comprising the HR offices, all of which were suspended over a lake of lava by a wild array of stone pillars. He also saw that the suspension bridge, the only way to leave HR and cross over the lava, was in flames. Spread out across the shore of the lake were deep ranks of Imperial troops. Numerous catapults were in use, flinging boulders into the many spindly stone columns that held the fortress aloft, and a number of the Imperials were using Magic and also attacking the supports with boulders of their own conjuring. Several of the main supports were visibly compromised, webs of cracks spreading with every impact. Below Baldric bubbled the lake of fire, waiting to welcome the rebels into its uncomfortably warm embrace.


Congratulations, you earned 1,416 experience and 982 gold. You are now a Level 7 Dwarven Magician!
(cue victory music)

Here are the Python topics you covered (and may want to DuckDuckGo for further inquiry):

  • for loops
  • while loops
  • iterables (strings, lists, other?)
  • built-in range function
  • built-in len function
  • append string method


Chapter 6 – Built-in Functions and Methods >>>