<jupyter_start><jupyter_text>While loops [Download exercises zip](../_static/generated/while.zip)[Browse online files](https://github.com/DavidLeoni/softpython-en/tree/master/while) Let's see how to repeat instructions by executing them inside `while` loops.The main feature of `while` loop is allowing to explicitly control when the loop should end. Typically, such loops are used when we must _iterate_ on a sequence of which we don't know the dimension, or it can vary over time, or several conditions might determine the cycle stop.  What to do1. Unzip [exercises zip](../_static/generated/while.zip) in a folder, you should obtain something like this:```while    while1.ipynb    while1-sol.ipynb    while2-chal.ipynb    jupman.py    ```**WARNING: to correctly visualize the notebook, it MUST be in an unzipped folder !** 2. open Jupyter Notebook from that folder. Two things should open, first a console and then a browser. The browser should show a file list: navigate the list and open the notebook `while.ipynb`3. Go on reading the exercises file, sometimes you will find paragraphs marked **Exercises**  which will ask to write Python commands in the following cells. Shortcut keys:- to execute Python code inside a Jupyter cell, press `Control + Enter`- to execute Python code inside a Jupyter cell AND select next cell, press `Shift + Enter`- to execute Python code inside a Jupyter cell AND a create a new cell aftwerwards, press `Alt + Enter`- If the notebooks look stuck, try to select `Kernel -> Restart`  Counting with a whileA `while` cycle is a code block which is executed when a certain boolean condition is verified. The code block is repeatedly executed as long as the condition is true.Let's see an example:<jupyter_code>i = 1

while i < 4:
    print('Counted', i)
    i += 1
    
print('Loop is over!')<jupyter_output>Counted 1
Counted 2
Counted 3
Loop is over!<jupyter_text>In the example, the boolean condition is```pythoni < 4```the block to repeatedly executed is```python    print('Counted', i)    i += 1```Like any Python code blocks, the block is indented with spaces (usually 4).Have a better look at the execution in Python Tutor and read the following comment.<jupyter_code># WARNING: FOR PYTHON TUTOR TO WORK, REMEMBER TO EXECUTE THIS CELL with Shift+Enter
#          (it's sufficient to execute it only once)

import sys
sys.path.append('../')
import jupman
i = 1
while i < 4:
    print('Counted', i)
    i += 1
    
print('Loop is over !')

jupman.pytut()<jupyter_output>Counted 1
Counted 2
Counted 3
Loop is over !<jupyter_text>In the example we used a variable we called `i` and we initialized it to zero.At the beginning of the cycle `i` is valued `1`, so the boolean expression `i < 4` is evaluated as `True`. Since it's `True`,  execution continues inside the block with the `print` and finally MODIFIES `i` by incrementing `i += 1`.Now the execution goes to `while` row, and condition `i < 4` is evaluated again. At this second iteration `i` is valued `2`, so the boolean expression `i < 4` is again evaluated to `True` and the execution remains inside the block. A new print is done and `i` gets incremented.Another loop is done until `i` is valued `4`. A that point `i < 4` produces `False` so in that moment execution _exits_ the `while` block and goes on with the commands at the same indentation level as the `while`   Terminating `while` When we have a `while` cycle, typically sooner or later we want it to terminate  (programs which hang aren't users' favourites ...). To guarantee termination, we need:1. initializing a variable outside the cycle2. a condition after the `while` command which evaluates that variable (and optionally other things)3. at least one instruction in the internal block which MODIFIES the variable, so that sooner or later is going to satisfy condition 2If any of these points is omitted, we will have problems. Let's try forgetting them on purpose: **Error 1: omit initialization.** As in those cases in Python where we forgot to initialize a variable (let's try `j` in this case), the execution is interrupted as soon we try using the variable:```pythonprint("About to enter the cycle ..")while j < 4:    print('Counted', j)    j += 1    print('Loop is over !')``````About to enter the cycle ..---------------------------------------------------------------------------NameError                                 Traceback (most recent call last) in ()      1 print("About to enter the cycle ..")----> 2 while j < 4:      3     print('Counted', j)      4     j += 1      5 NameError: name 'j' is not defined``` **Error 2: omit using the variable in the condition.** If we forget to evaluate the variable, for example using another one by mistake (say `x`), the loop will never stop:```pythoni = 1x = 1print('About to enter the cycle ..')while x < 4:    evalutes x instead of i    print('Counted', i)    i += 1    print('Loop is over !')``````About to enter the cycle ..Counted 1Counted 2Counted 3Counted 4Counted 5Counted 6..``` **Error 3: Omit to MODIFY the variable in the internal block.** If we forget to place at least one instruction which MODIFIES the variable used in the condition, whenever the condition is evaluated it will always produce the same boolean value `False` preventing a cycle exit:```pythoni = 1print('About to enter the cycle ..')while i < 4:    print('Counted', i)print('Loop is over !')``````About to enter the cycle ..Counted 1Counted 1Counted 1Counted 1Counted 1..```  Non terminating `while`**QUESTION**: Can you imagine a program which _never_ terminates? **ANSWER**: if you live nearby a hydropower or nuclear plant, what happens if the program regulating the water stops?Or: suppose you are inside an airplane and the program which checks the fuel flux to the engine suddenly stops. Could this be a problem?All programs if well written must foresee termination, but some software are executed for such a long time that termination is to be considered an exceptional event.  Questions **QUESTION**: Look at the following code fragments , and for each try guessing the result it produces (or if it gives an error):1.  ```python    i = 0    while i < 3:    print(i)        ```1.  ```python    k = 0    while k < 5:        print(k)        k + 1    ```    1.  ```python    i = 0    while i < 3:        print(i)    i += 1    ```    1.  ```python    i = 0    while False:        print(i)        i += 1    print('Done !')    ```    1.  ```python    i = 0    while i < 3:        print(i)        i += 1    ```   1.  ```python    k = 0    while k < 2        print(i)        k += 1    ```        1.  ```python    i = 0    while i < 3:        print('GAM')        i = i + 1    ```1.  ```python    while zanza < 2        print('ZANZA')        zanza += 1    ```         1.  ```python    i = 0    while False:        print(i)        i = i + 1    print('DARK')    ```1.  ```python    i = 0    while True:        print(i)        i = i + 1    print('LIGHT')    ```1.  ```python    while 2 + 3:        print('z')    print('')    ```1.  ```python    i = 10    while i > 0:        if i > 5:            print(i)            i -= 1    print('WAM')    ```1.  ```python    i = 10    while i > 0:        if i > 5:            print(i)        i -= 1    print('MAW')    ```1.  ```python    import random    x = 0    while  x < 7:        x = random.randint(1,10)        print(x)    print('LUCK')    ```1.  ```python    x,y = 0,0    while x + y < 4:        x += 1        y += 1        print(x,y)    ```1.  ```python    x,y = 0,3    while x < y:        print(x,y)        x += 1        y -= 1    ```  Esercises  Exercise - printeven✪ Write some code to  print all the odd numbers from `1` to `k` in a `while` cycle- for `k<1` prints nothingExample - given:```pythonk = 5```after your code it must print:```135```<jupyter_code>#jupman-purge-output
k = 5   # 1 3 5
#k = 1  # 1
#k = 0  # no print

# write here
i = 1
while i <= k:
    if i % 2 == 1:
        print(i)
    i += 1<jupyter_output>1
3
5<jupyter_text>Exercise - average✪ Write some code that given a list `numbers`, calculates the average of values  using a `while` and then prints it.- if the list is not empty, the average is supposed to be `0.0`- **DO NOT** use the function `sum`- DO NOT create variables called `sum` (would violate the [V COMMANDMENT](https://en.softpython.org/commandments.htmlV-COMMANDMENT): you shall never ever redefine system functions)Example - given:```pythonnumbers = [8,6,5,9]```prints```7.0```<jupyter_code>#jupman-purge-output
numbers = [8,6,5,9] # 7.0
#numbers = [3,1,2]  # 2.0
#numbers = []       # 0

# write here
s = 0.0
i = 0
while i < len(numbers):
    s += numbers[i]
    i += 1
    
if len(numbers) > 0:
    print(s / len(numbers))
else:
    print(0.0)<jupyter_output>7.0<jupyter_text>`break` and `continue`  commandsFor getting even more control on cycle execution we can use the commands `break` and `continue`**NOTE: Use them sparingly!**    When there is a lot of code in the cycle it's easy to 'forget' about their presence and introduce hard-to-discover bugs. On the other hand, in some selected cases these commands may increase code readability, so as everything use your judgement.     Terminate with a `break`The scheme we've seen to have a terminating `while` is the recommended one, but if we have a condition which does NOT evaluate the variable we are incrementing (like for example the constant expression `True`), as an alternative to immediatly exit the cycle we can use the command `break`:<jupyter_code>i = 1
while True: 
    
    print('Counted', i)    
    
    if i > 3:        
        print('break! Exiting the loop!')
        break    
        print('After the break')
            
    i += 1    

print('Loop is over !')<jupyter_output>Counted 1
Counted 2
Counted 3
Counted 4
break! Exiting the loop!
Loop is over !<jupyter_text>Note `After the break` is _not_ shown.  Jumping with `continue`We can bring the execution immediately to the next iteration by calling `continue`, which directly jumps to the condition check without executing the instructions after the `continue`. **WARNING:** `continue` **instructions if used carelessly can cause infinite loops !**   When using `continue` ensure it doesn't jump the instriction which modifies the variable used in the termination condition (or it doesn't jump a `break` needed for exiting the cycle)!     To avoid problems here we incremented `i` before the `if` with a `continue`:<jupyter_code>i = 1
while i < 5:     
    print('Counted', i)
    
    i += 1
    
    if i % 2 == 1:
        print('continue, jumping to condition check')
        continue
        print('After the continue')
    
    print('arrived till the end')
    
print('Loop is over !')<jupyter_output>Counted 1
arrived till the end
Counted 2
continue, jumping to condition check
Counted 3
arrived till the end
Counted 4
continue, jumping to condition check
Loop is over !<jupyter_text>Let's try combining `break` and `continue`, and  see what happens in Python Tutor:<jupyter_code>i = 1
while i < 5:     
    print('Counted', i)
    if i > 3:        
        print('break! Exiting the cycle!')
        break    
        print('After the break')
    i += 1    
    if i % 2 == 1:
        print('continue, jumping to next condition check')
        continue
        print('After the continue')
    print('arrived till the end')
    
print('Loop is over !')

jupman.pytut()<jupyter_output>Counted 1
arrived till the end
Counted 2
continue, jumping to next condition check
Counted 3
arrived till the end
Counted 4
break! Exiting the cycle!
Loop is over !<jupyter_text>Questions about `break`  and  `continue` **QUESTION**: Look at the following code fragments , and for each try guessing the result it produces (or if it gives an error):1.  ```python    i = 1    while i < 4:        print('Counted', i)        i += 1        continue    print('Loop is over !')    ```1.  ```python    i = 1    while i < 4:        print('Counted', i)        continue                i += 1            print('Loop is over !')    ```1.  ```python    i = 3    while i > 0:        print('Counted', i)        if i == 2:            print('continue, jumping to condition check')            continue            i -= 1        print('arrived till the end')            print('Loop is over !')    ```  1.  ```python    i = 0    while True:        i += 1        print(i)        if i > 3:                        break            print('BONG')    ```1.  ```python    i = 0    while True:        if i < 3:            continue        else:            break        i += 1    print('ZONG')    ```1.  ```python    i = 0    while True:        i += 1        if i < 3:            continue        else:            break    print('ZANG')    ```      Questions - Are they equivalent?Look at the following code fragments: each contains two parts, A and B. For each value of the variables they depend on, try guessing whether part A will print exactly the same result printed by code in part B* **FIRST** think about the answer and  **write down the expected output*** **THEN** try executing with each of the values of suggested variables  Are they equivalent? - BORG```pythonprint('A:')while True:    print('BORG')    breakprint('\nB:')while False:    passprint('BORG')```  Are they equivalent? - until 3```pythonprint('A:')x = 0while x < 3:    print(x)    x += 1    print('\nB:')x = 1while x <= 3:    print(x-1)    x += 1```      Are they equivalent? - by chanceRemember `randint(a, b)` gives back a random integer `N` such that `a <= N <= b````pythonprint('A:')x = 0while x < 3:    x += 1print(x)  print('\nB:')x = 0import randomwhile x != 3:    x = random.randint(1,5)print(x)    ```   Are they equivalent? - until six```pythonprint('A:')i = 0while i < 3:    print(i)    i += 1while i < 6:    print(i)    i += 1 print('\nB:')i = 0while i < 6:    print(i)    i += 1 ```  Are they equivalent? - countdown 1```pythonprint('A:')i = 2print(i)while i > 0:    i -= 1    print(i)print('\nB:')i = 2while i > 0:    print(i)    i -= 1  ```  Are they equivalent? - countdown 2```pythonprint('A:')i = 2print(i)while i > 0:    i -= 1    print(i)print('\nB:')i = 2while i > 0:    print(i)    i -= 1  print(i)```<jupyter_code>print('A:')
i = 2
print(i)
while i > 0:
    i -= 1
    print(i)

print('\nB:')
i = 2
while i > 0:
    print(i)
    i -= 1  
print(i)<jupyter_output>A:
2
1
0

B:
2
1
0<jupyter_text>Are they equivalent? - sorcery```pythonprint('A:')s = 'sorcery'i = 0while s[i] != 'e':    i += 1print(s[i:])    print('B:')    s = 'sorcery'i = len(s)while s[i] != 'e':    i -= 1print(s[i:]) ```  Are they equivalent?  - ping pong```pythonprint('A:')ping,pong = 0,3while ping  0:    print(ping,pong)    ping += 1    pong -= 1    print('\nB:')    ping,pong = 0,3while not(ping >= 3 and pong <= 0):    print(ping,pong)    ping += 1    pong -= 1```  Are they equivalent? - zanna```pythonprint('A:')n,i,s = 0,0,'zanna'while i < len(s):    if s[i] == 'n':        n += 1    i += 1print(n)print('\nB:')n,i,s = 0,0,'zanna'while i < len(s):    i += 1    if s[i-1] == 'n':        n += 1    print(n)```  Are they equivalent? - pasticcio```pythonprint('A:')c,i,s = 0,0,'pasticcio'while i < len(s):    if s[i] == 'c':        c += 1    i += 1print(c)print('\nB:')no,k,s = 0,0,'pasticcio'while k < len(s):    if s[k] != 'c':        no += 1    else:        k += 1print(len(s) - no)```      Exercises - counters  Exercise - don't break 1✪ Look at the following code, and write in the following cell some code which produces the same result with a `while` and **without using** `break`<jupyter_code>x = 3
while True:
    print(x)
    if x == 0:
        break
    x -= 1
#jupman-purge-output
x = 3

# write here

while x >= 0:
    print(x)    
    x -= 1<jupyter_output>3
2
1
0<jupyter_text>Exercise - don't break 2✪ Look at the following code, and write in the following cell some code which produces the same result with a `while` and **without using** `break`<jupyter_code>la = [2,3,7,5,6]
k = 7   # 2 3 7
#k = 5  # 2 3 7 5 6
#k = 13 # 2 3 7 5 6

i = 0
while True:    
    print(la[i])
    if i >= len(la)-1 or la[i] == k:        
        break
    else:
        i += 1
#jupman-purge-output
la = [2,3,7,5,6]
k = 7   # 2 3 7
#k = 6  # 2 3 7 5 6
#k = 13 # 2 3 7 5 6

i = 0

# write here

while i < len(la) and la[i] != k:
    print(la[i])
    i += 1
if i < len(la) and la[i] == k:
    print(la[i])<jupyter_output>2
3
7<jupyter_text>Exercise - Give me a break✪ Look at the following code, and write in the next cell some code which produces the same result with a `while` **this time using a** `break`<jupyter_code>x,y = 1,5    # (1,5)  (2,4)
#x,y = 2,8   # (2, 8) (3, 7) (4, 6)

while x < y or x == 4:
    print((x,y))
    x += 1 
    y -= 1
#jupman-purge-output
x,y = 1,5    # (1,5)  (2,4)
#x,y = 2,8   # (2, 8) (3, 7) (4, 6)

# write here
while True:
    
    if x >= y or x == 4:
        break
    else:
        print((x,y))
        x += 1 
        y -= 1
        
if x < y or x == 4:
    print((x,y))<jupyter_output>(1, 5)
(2, 4)<jupyter_text>Exercise - paperboard✪ Prints integer numbers from `0` to `k` INCLUDED using a `while`, and for each number prints to its side one among the strings `'PA'`, `'PER'` and `'BOARD'` alternating themEx - for `k=8` prints```0 PA1 PER2 BOARD3 PA4 PER5 BOARD6 PA7 PER8 BOARD```<jupyter_code>#jupman-purge-output
k = 8

# write here
x = 0
while x <= k:
    if x % 3 == 0:
        print(x, 'PA')
    elif x % 3 == 1:
        print(x, 'PER')
    else:
        print(x, 'BOARD')
    x += 1<jupyter_output>0 PA
1 PER
2 BOARD
3 PA
4 PER
5 BOARD
6 PA
7 PER
8 BOARD<jupyter_text>Exercise - until ten✪ Given two numbers `x` and `y`, write some code with a `while` which prints  and  increments the numbers, stopping as soon as one of them reaches ten.```pythonx,y = 5,7```after your code it must result:```5 76 87 98 10```<jupyter_code>#jupman-purge-output
x,y = 5,7
#x,y = 8,4

# write here
while x <= 10 and y <= 10:
    print(x,y)
    x += 1
    y += 1<jupyter_output>5 7
6 8
7 9
8 10<jupyter_text>Exercise - cccc✪ Write some code using a `while` which given a number `y`, prints `y` rows containing the character `c` as many times as the row number.Example - given:```pythony = 4``` Prints:```cccccccccc```<jupyter_code>#jupman-purge-output
y = 4

# write here
x = 0
while x <= y:
    print('c'*x)
    x += 1<jupyter_output>c
cc
ccc
cccc<jupyter_text>Exercise - converge✪ Given two numbers `x` and `k`, using a `while` modify and print `x` until it reaches `k` included* **NOTE**: `k` can either be greater or lesser than `x`, you must handle both casesExample 1 - given:```pythonx,k = 3,5    ```prints:```345```Example 2 - given:```pythonx,k = 6,2```prints:```65432```<jupyter_code>#jupman-purge-output
x,k = 3,5    # 3 4 5
#x,k = 6,2   # 6 5 4 3 2
#x,k = 4,4   # 4

# write here

while x != k:
    print(x)
    if x < k:
        x += 1
    else:
        x -= 1
print(x)<jupyter_output>3
4
5<jupyter_text>Searching a sequenceWe are at the airport, and we've been told to reach the gate of our trusted airline company _Turbulenz_. We don't remember exactly the gate, but we know we have to stop at the first _Turbulenz_ sign we find. If by mistake we went further, we might encounter other gates for international flights, and who knows where we would end up.If we have to perform searches in potentially long sequences, and we don't always need a complete visit, using a `while` loop is more convenient and efficient than a `for`.We could represent the example above as a list:<jupyter_code>#    0         1            2            3           4           5         6           7
airport = ['Flyall','PiercedWings','PigeonJet','Turbolenz', 'BoingBoing','Jettons','Turbulenz','BoingBoing']<jupyter_output><empty_output><jupyter_text>Once the element is found, we would like the program to print the position in which it was found, in this case `3`.Naturally, if you read well the [list search methods](https://en.softpython.org/lists/lists4-sol.html) you already know there is a handy method `.index('Turbulenz')`, but in this notebook we adopt the philosophy of 'do it yourself', and will try building our search algorithms from scratch. **QUESTION**: Can you think of some corner case where `index` method can also bring a problem? **ANSWER**: if the list does _not_ contain what we're looking for, calling `index` will raise an exception thus stopping the program.  What we needTo build our search, we will need:1. control variable2. stop condition3. control variable updateThe control variable in this case could be an index, the stop condition could evaluate whether we reached the end of the airport, and inside the cycle we will update the index to keep searching. But where should we evaluate whether or not we have found the gate? Furthermore, since we are expert programmers we believe in misfortune, and know horror scenarios could happen indeed, like Turbulenz company going bankrupt the very same day of our arrival! Thus, we also need to foresee the case our search may give no result, and decide what should happen in such situation.  How to checkThere are two ways to check a discovery:a) most direct way is to place an exit check inside the body of `while` itself: we could put an `if` statement which controls when the element is found, and in such case performs the execution of a `break` command. It is by no means elegant, yet it could be a first approach.b) a better option would be performing the check in the boolean condition of the `while`, but devising a program which works in all cases could be slightly trickier.Let's try them both in the following exercises.  Exercise - Turbolenz with a break✪✪ Write some code which uses a `while` to search the list `airport` for the FIRST occurrence of `company`: as soon as it is found, stops searching and PRINTS the index where it was found.- If the company is not found, PRINTS 'Not found'- **USE** a `break` to stop the search- **REMEMBER** to test your code with all the suggested airportsExample 1 - given:```pythoncompany='Turbolenz'             airport = ['Flyall','PiercedWings','PigeonJet','Turbolenz', 'BoingBoing','Jettons','Turbulenz','BoingBoing']```after your code, it must print:```Found the first Turbolenz at index 3```Example 2 - given:```pythoncompany = 'FlapFlap'airport = ['PiercedWings','BoingBoing','Turbolenz','PigeonJet']```it must print:```FlapFlap was not found```<jupyter_code>#jupman-purge-output


company = 'Turbolenz'                                 
airport = ['Flyall','PiercedWings','PigeonJet','Turbolenz', 'BoingBoing','Jettons','Turbulenz','BoingBoing']

#company = 'FlapFlap'
#airport = ['PiercedWings','BoingBoing','Turbolenz','PigeonJet']
#airport = []        
#airport = ['FlapFlap']
#airport = ['Turbolenz', 'FlapFlap']

# write here
i = 0
while i < len(airport):
    if airport[i] == company:
        print("Found the first", company, "at index", i)
        break
    i += 1
if i == len(airport):
    print(company, 'was not found')<jupyter_output>Found the first Turbolenz at index 3<jupyter_text>Exercise - Turbulenz without break✪✪ Try now to rewrite the previous program **without** using `break` nor `continue`: to verify the finding, you will need to enrich the termination condition.<jupyter_code>#jupman-purge-output

company = 'Turbolenz'                                 
airport = ['Flyall','PiercedWings','PigeonJet','Turbolenz', 'BoingBoing','Jettons','Turbulenz','BoingBoing']

#company = 'FlapFlap'
airport = ['PiercedWings','BoingBoing','Turbolenz','PigeonJet']
#airport = []        
#airport = ['FlapFlap']
#airport = ['Turbolenz', 'FlapFlap']

# write here

i = 0
while i < len(airport) and airport[i] != company:
    i += 1
    
if i == len(airport):
    print(company, 'was not found')
else:
    print("Found the first", company, "at index", i)<jupyter_output>Found the first Turbolenz at index 2<jupyter_text>**QUESTION**: you probably used two conditions in the `while`. By exchanging the order of the conditions in the proposed solution, would the program work fine? If not, in which cases could it fail?* **HINT**: If you have doubts try reading the chapter [booleans - evaluation order](https://en.softpython.org/basics/basics2-bools-sol.htmlEvaluation-order) **ANSWER**: the comparison between the index with the airport length must be done first, because when it gives `False` the evaluation of the `and` expression stops immediately without proceeding with the dangerous `airport[i] != company` which in an airport without `FlapFlap` company would become `airport[4] != company` and thus produce an index error:```pythoncompany = 'FlapFlap'                 0            1            2           3airport = ['PiercedWings','BoingBoing','Turbolenz','PigeonJet'] write herei = 0 WARNING: WRONG ORDER!while airport[i] != company and i < len(airport):    i += 1    if i == len(airport):    print(company, 'was not found')else:    print("Found the first", company, "at index", i)```      Exercise - hangar✪✪ Our plane just landed but now it must reach the hangar, dodging all the extraneous objects  on the track!Write some code which given a string `track` with a certain number of non-alphanumeric characters at the beginning, PRINTS the word which follows these characters.Example - given:```pythontrack = '★★🏳🏳♦🏳♦🏳🏳hangar★★★'  ```your code must print:`hangar★★★`* **YOU CAN'T**  know beforehand which extra characters you will find in the string* **DO NOT** write characters like ★🏳♦-_ in the code**HINT**: to determine if you have found alphanumerical characters or numbers, use `.isalpha()` and `.isdigit()` methods<jupyter_code>#jupman-purge-output
track = '★★🏳🏳♦🏳♦🏳🏳hangar★★★'   # hangar★★★
#track = '🏳🏳twinengine'         # twinengine
#track = '-★♦--♦--747-🏳'        # 747-🏳
#track = 'glider'               # glider
#track = '__♦__🏳__♦_'           # prints nothing

# write here

i = 0
while i < len(track) and not (track[i].isalpha() or track[i].isdigit()):
    i += 1
print(track[i:])<jupyter_output>hangar★★★<jupyter_text>Exercise - Wild West✪✪ The two outlaws Carson and Butch agreed to bury a treasure in the jolly town of Tombstone, ma now each of them wants to take back the treasure without sharing anything with the partner.- there is a `road` from `Santa Fe` until `Tombstone` to arrive to the treasure, which we represent as a list of strings- we use two indexes `butch` and `carson` to represent where the outlaws are on the road- each outlaw starts from a different town- at each turn Carson moves of **one** city- at each turn Butch moves of **two** cities, because he has a fast Mustang horseWrite some code which prints the run and terminates as soon as one them arrives to the last city, telling who got the treasure.* In the case both outlaws arrive to the last city at the same time, prints `Final duel in Tombstone!`- your code must work for _any_ `road` and initial position `carson` and `butch`Example - 1 given:```python             0         1          2           3            4               5road = ['Santa Fe','Denver','Dodge City', 'Silverton', 'Agua Caliente', 'Tombstone']carson,butch  = 3, 0   ```it must print:```Carson starts from SilvertonButch starts from Santa FeCarson reaches Agua CalienteButch reaches Dodge CityCarson reaches TombstoneButch reaches Agua CalienteCarson takes the treasure in  Tombstone !```Example 2 - given:```python            0         1          2           3              4               5road = ['Santa Fe','Denver','Dodge City', 'Silverton', 'Agua Caliente', 'Tombstone']carson,butch  = 3, 2    ```it must print:```Carson starts from SilvertonButch starts from Dodge CityCarson reaches Agua CalienteButch reaches Agua CalienteCarson reaches TombstoneButch reaches TombstoneFinal duel in  Tombstone !```<jupyter_code>#jupman-purge-output
#           0          1         2              3              4              5 
road = ['Santa Fe','Denver','Dodge City', 'Silverton', 'Agua Caliente', 'Tombstone']

carson,butch  = 3, 0    #  Carson takes the treasure in Tombstone !
#carson,butch  = 0, 0   #  Butch takes the treasure in Tombstone !
#carson,butch  = 3, 2   #  Final duel in Tombstone !

# write here

print('Carson starts from', road[carson])
print('Butch starts from', road[butch])

while carson < len(road)-1 and butch < len(road)-1:
    carson = min(len(road)-1, carson + 1)
    butch = min(len(road)-1, butch + 2)
    print('Carson reaches', road[carson])
    print('Butch reaches', road[butch])
    
    
print()
if carson == len(road)-1 and butch == len(road)-1:
    print('Final duel in ', road[-1], '!')
elif carson == len(road)-1:
    print('Carson takes the treasure in ', road[-1], '!')
else: 
    print('Butch takes the treasure in ', road[-1], '!')<jupyter_output>Carson starts from Silverton
Butch starts from Santa Fe
Carson reaches Agua Caliente
Butch reaches Dodge City
Carson reaches Tombstone
Butch reaches Agua Caliente

Carson takes the treasure in  Tombstone !<jupyter_text>Exercise - The Balance of Language✪✪ In the sacred writings of Zamfir the Prophet, it is predicted that when all Earth inhabitants speak a language with all the words of same length, universal harmony will be reached among human people. This event is probably far in time and by that epoch the vocabulary of humans will be so wide and varied that checking all the words will certainly require powerful calculations: you are asked to program the underwater servers of Atlantis to perform a check in the centuries to come.Given a string of words `language`, write some code which prints `True` if all the words have the same length, `False` otherwise.To have an efficient algorithm, you must use a `while`:- stop the loop as soon you can determine with certainty the program result- **DO NOT** use `break` nor `continue`<jupyter_code>#jupman-purge-output

language =  "eternal harmony forever"  # True
#language = "war and violence"      # False
#language = "vi rt uo si ty"        # True
#language = "deceit bullying"       # False
#language = "harmony crashed today" # False
#language = "peace"                 # True
#language = ""                      # True

# write here
li = language.split()

n = len(li[0]) if len(li) > 0 else 0

all_equal = True
i = 1
while i < len(li) and all_equal:
    if n != len(li[i]):
        all_equal = False        
    i += 1  

print(all_equal)<jupyter_output>True<jupyter_text>Exercise - the tree shaker✪✪✪ Giustino the farmer decides to radically improve his farm productivity with high-tech devices, and asks you to develop a 'tree shaker' (so he calls it..) to perturbate the trees and harvest the exotic fruits he planted in his highlands (thanks to climate change...)The `plantation` is a sequence of fruit trees, elements of the landscape (stones, gravel, etc) and signs `S`. The beginning and end of a subsequence of trees is always marked by a sign. The vehicle to design has a `cargo_bed` of **capacity 7** where it can store the harvest.Write some code to scan the `plantation` and harvests in `cargo_bed` the fruits as they are found.- **USE** a `while`, **stopping** as soon as the `cargo_bed` is full- **DO NOT** use `break` nor `continue`- **DO NOT** write fruit names or landscape elements (no `bananas` nor `rocks` ..). You can still write `'S'`, though. Example - given:<jupyter_code>plantation=['rocks','stones',  'S',   'bananas','oranges','mangos','S',      'sand',    'stones','stones',
            'S',    'avocados','S',   'weeds',  'S',      'kiwi',  'mangos', 'S',       'S',     'S',
            'rocks','S',       'lime','S',      'pebbles','S',     'oranges','coconuts','S',     'gravel']<jupyter_output><empty_output><jupyter_text>after your code, it must result:```>>> print(cargo_bed)['bananas', 'oranges', 'mangos', 'avocados', 'kiwi', 'mangos', 'lime']```<jupyter_code>#  0       1          2      3          4        5        6         7         8        9
plantation=['rocks','stones',  'S',   'bananas','oranges','mangos','S',      'sand',   'stones','stones',
           # 10      11         12     13        14        15       16        17        18       19 
            'S',    'avocados','S',   'weeds',  'S',      'kiwi',  'mangos', 'S',      'S',     'S',
           # 20      21         22     23        24        25       26        27        28       29
            'rocks','S',       'lime','S',      'pebbles','S',     'oranges','coconuts','S',    'gravel']

#plantation = ['S','S']   # []
#plantation = ['S','lemons','S']   # ['lemons']
#plantation = ['sand','S','lemons','S']   # ['lemons']
#plantation = ['oranges']   # []
#plantation = ['S','1','2','3','4','5','6','7', '8','S']   # ['1','2','3','4','5','6','7']  
#plantation = ['S','1','2','S','x','S','3','4','5','6','7','8','S','9']   # ['1','2','3','4','5','6','7']


cargo_bed = []

# write here

harvesting = False
i = 0
while i < len(plantation) and len(cargo_bed) < 7:
    if plantation[i] == 'S':
        harvesting = not harvesting
    else:
        if harvesting: cargo_bed.append(plantation[i])
    i += 1

print(cargo_bed)<jupyter_output>['bananas', 'oranges', 'mangos', 'avocados', 'kiwi', 'mangos', 'lime']<jupyter_text>Exercise - the ghost castle✪✪✪ Given a `string` and two characters `char1` and `char2`, write some code which PRINTS `True` if all occurrences of `char1` in `string` are **always** followed by `char2`Example - given:```pythonstring,char1,char2 = 'fantastic story of the ghost castle', 's','t'```prints `True` because all the occurrences of `s` are followed by `t````pythonstring,char1,char2 = "enthusiastic dadaist", 's','t'```prints `False`, because the sequence `si` is found, where `s` is not followed by `t`- **USE** a `while`, try to make it efficient by stopping as soon as possible.- **DO NOT** use **break**- **DO NOT** use any search method (no `index`, `find`, `replace`, `count`...)<jupyter_code>#jupman-purge-output
string,char1,char2 = 'fantastic story of the ghost castle', 's','t' # True
#string,char1,char2 = "enthusiastic dadaist", 's','t'    # False
#string,char1,char2 = "beetroots", 'r','o'           # True
#string,char1,char2 = "beetroots", 'e','o'           # False
#string,char1,char2 = "a", 'a','b'                      # False
#string,char1,char2 = "ab", 'a','b'                     # True
#string,char1,char2 = "aa", 'a','b'                     # False


# write here
i = 0

res = True

if len(string) == 1:
    res = False

while i + 1 < len(string) and res:
    if string[i] == char1 and string[i+1] != char2:
        res = False
    i += 1
    
res<jupyter_output><empty_output><jupyter_text>Modifying sequencesIn the tutorial on `for` loops we've seen an important warning we repeat here:[X COMMANDMENT](https://en.softpython.org/commandments.htmlX-COMMANDMENT): **You shall never ever add or remove elements from a sequence you are iterating with a** `for` **!**Falling into such temptations **would produce totally unpredictable behaviours** (do you know the expression _pulling the rug out from under your feet ?_ )**If you really need to remove elements from a sequence you are iterating**, use a while cycle or duplicate first a copy of the original sequence.    **Note the advice is only about** `for` **cycles**. In case of necessity, at the end suggests to adopt `while` loops. Let's see when and how ot use them.  Stack - Drawing from a card deckSuppose having a deck of cards which we represent as a list of strings, and we want to draw all the cards, reading them one by one.We can write a `while` that as long as the deck contains cards, keeps removing cards from the top with the [pop method](https://en.softpython.org/lists/lists3-sol.htmlpop-method) and prints their name. Remember `pop` MODIFIES the list by removing the last element AND gives back the element as call result, which we can save in a variable we will call `card`:<jupyter_code>deck = ['3 hearts',   # <---- bottom
        '2 spades',
        '9 hearts',
        '5 diamonds',
        '8 clubs']    # <---- top

while len(deck) > 0:
    card = deck.pop()      
    print('Drawn', card)

print('No more cards!')

jupman.pytut()<jupyter_output>Drawn 8 clubs
Drawn 5 diamonds
Drawn 9 hearts
Drawn 2 spades
Drawn 3 hearts
No more cards!<jupyter_text>Looking at the code, we can notice that:1. the variable `deck` is initialized2. we verify that `deck` dimension is greater than zero3. at each step the list `deck` is MODIFIED by reducing its dimension3. it returns to step 2The first three points are the conditions which guarantee the `while` loop will sooner or later actually terminate.  Stack - Drawing until condition Suppose now to continue drawing cards until we find a heart suit.The situation is more complicated, because now the cycle can terminate in two ways:1. we find hearts, and interrupt the search2. there aren't heart cards, and the deck is exhaustedIn any case, in the end we must tell the user a result. To do so, it's convenient  initializing `card` at the beginning  like an empty string for handling the case when no hearts cards are found (or the deck is empty).Let's try a first implementation which uses an internal `if`  to verify whether we have found hearts, and in that case exits with a `break` command.* Try executing the code by uncomment the second deck which has no hearts cards, and look at the different execution.<jupyter_code>deck = ['3 hearts','2 spades','9 hearts','5 diamonds','8 clubs']
#deck = ['8 spades','2 spades','5 diamonds','4 clubs']   # no hearts!

card = ''
while len(deck) > 0:
    card = deck.pop()      
    print('Drawn', card)
    if 'hearts' in card:
        break
        
if 'hearts' in card:
    print('Found hearts!')
else:
    print("Didn't find hearts!")

jupman.pytut()<jupyter_output>Drawn 8 clubs
Drawn 5 diamonds
Drawn 9 hearts
Found hearts!<jupyter_text>Exercise - Don't break my heart✪ Write some code which solves the same previous problem:* this time **DO NOT** use `break`* ensure the code works with a deck without hearts, and also with an empty deck* **HINT**: put a multiple condition in the `while`<jupyter_code>#jupman-purge-output
deck = ['3 hearts','2 spades','9 hearts','5 diamonds','8 clubs']
#deck = ['8 spades','2 spades','5 diamonds','4 clubs']   # no hearts!
#deck = []  #  no hearts !

card = ''

# write here

while len(deck) > 0 and 'hearts' not in card:
    card = deck.pop()      
    print('Drawn', card)

if 'hearts' in card: 
    print("Found hearts!")
else:
    print("Didn't find hearts!")<jupyter_output>Drawn 8 clubs
Drawn 5 diamonds
Drawn 9 hearts
Found hearts!<jupyter_text>Questions - what happens?**QUESTION**: Look at the following code fragments , and for each try guessing the result it produces (or if it gives an error):1.  ```python    while []:        print('z')    print('BIG')    ```    1.  ```python    while ['a']:        print('z')    print('BUG')    ```1.  ```python    la = []    while len(la) < 3:        la.append('x')    print(la)    ```1.  ```python    la = ['x','y','z']    while len(la) > 0:        print(la.pop())    ```1.  ```python    la = ['x','y','z']    while la:        print(la.pop(0))        ```1.  ```python    la = [4,5,8,10]    while la.pop() % 2 == 0:        print(la)    ```  Questions - are they equivalent?Look at the following code fragments: each contains two parts, A and B. For each value of the variables they depend on, try guessing whether part A will print exactly the same result printed by code in part B* **FIRST** think about the answer* **THEN** try executing with each of the values of suggested variables  Are they equivalent? - train```pythonprint('A:')la = ['t','r','a','i','n']while len(la) > 0:    print(la.pop())    print('\nB:')la = ['t','r','a','i','n']la.reverse()while len(la) > 0:    print(la.pop(0))```  Are they equivalent? - append nx```pythonprint('A:')x,n,la = 2,0,[]while x not in la:    la.append(n)    n += 1print(la)print('\nB:')x,la = 2,[]while len(la) < 3:    la.append(x)    x += 1print(la)```  Exercises - stack  Exercise - break sum✪ Look at the following code, and rewrite it in the following cell as `while`* this time **use command** `break`<jupyter_code>lst = []
i = 0
k = 10
while sum(lst) < k:
    lst.append(i)
    i += 1
    print(lst)
#jupman-purge-output
lst = []
i = 0

# write here

while True:    
    if sum(lst) >= k:
        break
    else:        
        lst.append(i)
        i += 1
        print(lst)<jupyter_output>[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]<jupyter_text>Exercise - travelbook✪✪ Suppose you visited the attic and found a stack of books, which we represent as a list of strings. Each string is prefixed by a label of one character indicating the category (D for Detective story, T for Travel, H for History)```pythonstack = ['H-Middle Ages',    <---- bottom         'T-Australia',                 'T-Scotland',                 'D-Suspects',         'T-Caribbean']     <---- top```Since we are passionate about travel books, we want to examine `stack` one book at a time to transfer books into another pile we call `ŧravel`, which at the beginning is empty. We start from the top book in `stack`, and transfer into  `travel` only the books starting with the label `T` like (`'T-Australia'`)```pythontravel = []```Write some code that produces the following print:```At the beginning:    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland', 'D-Suspects', 'T-Caribbean']    travel: []Taken T-Caribbean    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland', 'D-Suspects']    travel: ['T-Caribbean']Discarded D-Suspects    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland']    travel: ['T-Caribbean']Taken T-Scotland    stack:   ['H-Middle Ages', 'T-Australia']    travel: ['T-Caribbean', 'T-Scotland']Taken T-Australia    stack:   ['H-Middle Ages']    travel: ['T-Caribbean', 'T-Scotland', 'T-Australia']Discarded H-Middle Ages    stack:   []    travel: ['T-Caribbean', 'T-Scotland', 'T-Australia']```* The non-travel books are not interesting and must be discarded* Your code must work with _any_  `stack` list<jupyter_code>#jupman-purge-output
stack = ['H-Middle Ages',   # <---- bottom
         'T-Australia',        
         'T-Scotland',        
         'D-Suspects',
         'T-Caribbean']    # <---- top


travel = []

# write here
print("At the beginning:")
print('    stack:  ', stack)
print('    travel:', travel)

while len(stack) > 0:
    book = stack.pop() 
    if book.startswith('T'):
        print('Taken',book)    
        travel.append(book)
    else:
        print('Discarded', book)
    print('    stack:  ', stack)
    print('    travel:', travel)<jupyter_output>At the beginning:
    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland', 'D-Suspects', 'T-Caribbean']
    travel: []
Taken T-Caribbean
    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland', 'D-Suspects']
    travel: ['T-Caribbean']
Discarded D-Suspects
    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland']
    travel: ['T-Caribbean']
Taken T-Scotland
    stack:   ['H-Middle Ages', 'T-Australia']
    travel: ['T-Caribbean', 'T-Scotland']
Taken T-Australia
    stack:   ['H-Middle Ages']
    travel: ['T-Caribbean', 'T-Scotland', 'T-Australia']
Discarded H-Middle Ages
    stack:   []
    travel: ['T-Caribbean', 'T-Scotland', 'T-Australia']<jupyter_text>Exercise - BANG !✪✪ There are two stacks of objects `right_stack` and `left_stack` which we represent as lists of strings. As a pastime, a cowboy decides to shoot the objects at the top of the stacks, alternating the stack at each shoot. The cowboy is skilled and always hits the target, so each shot decreases a stack.- Suppose the objects on top are the ones at the end of the list- To keep track of which stack to hit, use a variable `shoot` holding either `'R'` or `'L'` character- After each shot the cowboy if possible changes the stack , otherwise keeps shooting at the same stack until it's empty.- your code must work for _any_ stack and initial shotExample - given:```pythonleft_stack = ['box','boot','horseshoe','bucket']right_stack = ['bin','saddle','tin can']shoot = 'R'```after your code, it must print:```Ready?   left_stack: ['box', 'boot', 'horseshoe', 'bucket']  right_stack: ['bin', 'saddle', 'tin can']BANG! right:  tin can   left_stack: ['box', 'boot', 'horseshoe', 'bucket']  right_stack: ['bin', 'saddle']BANG! left:   bucket   left_stack: ['box', 'boot', 'horseshoe']  right_stack: ['bin', 'saddle']BANG! right:  saddle   left_stack: ['box', 'boot', 'horseshoe']  right_stack: ['bin']BANG! left:   horseshoe   left_stack: ['box', 'boot']  right_stack: ['bin']BANG! right:  bin   left_stack: ['box', 'boot']  right_stack: []BANG! left:   boot   left_stack: ['box']  right_stack: []Nothing to shoot on the right!   left_stack: ['box']  right_stack: []BANG! left:   box   left_stack: []  right_stack: []```<jupyter_code>#jupman-purge-output
left_stack = ['box','boot','horseshoe','bucket']
right_stack = ['bin','saddle','tin can']
shoot = 'R'
#shoot = 'L'
#left_stack = ['bucket', 'box']

# write here

print('Ready?')
print('   left_stack:', left_stack)
print('  right_stack:', right_stack)
while len(right_stack) > 0 or len(left_stack) > 0:
    if shoot == 'R':
        if len(right_stack) > 0:
            print('BANG! right: ', right_stack.pop()) 
        else:
            print('Nothing to shoot on the right!')
        shoot = 'L'
    else:
        if len(left_stack) > 0:
            print('BANG! left:  ', left_stack.pop())
        else:
            print('Nothing to shoot on the left!')
        shoot = 'R'

    print('   left_stack:', left_stack)
    print('  right_stack:', right_stack)<jupyter_output>Ready?
   left_stack: ['box', 'boot', 'horseshoe', 'bucket']
  right_stack: ['bin', 'saddle', 'tin can']
BANG! right:  tin can
   left_stack: ['box', 'boot', 'horseshoe', 'bucket']
  right_stack: ['bin', 'saddle']
BANG! left:   bucket
   left_stack: ['box', 'boot', 'horseshoe']
  right_stack: ['bin', 'saddle']
BANG! right:  saddle
   left_stack: ['box', 'boot', 'horseshoe']
  right_stack: ['bin']
BANG! left:   horseshoe
   left_stack: ['box', 'boot']
  right_stack: ['bin']
BANG! right:  bin
   left_stack: ['box', 'boot']
  right_stack: []
BANG! left:   boot
   left_stack: ['box']
  right_stack: []
Nothing to shoot on the right!
   left_stack: ['box']
  right_stack: []
BANG! left:   box
   left_stack: []
  right_stack: []<jupyter_text>Exercise - Growing or degrowing?✪✪ Write some code which given a list `la`, keeps MODIFYING the list according to this procedure:* if the last element is odd (i.e. `7`), attaches a new number at the end of the list obtained by multiplying by two the last element (i.e. attaches `14`)* if the last element is even, removes the last two elements* **DO NOT** create a new list (so no rows starting with `la =`)* **WARNING**: when we want both grow and degrow the sequence we are considering in a cycle, we must convince ourselves that sooner or later the termination condition will happen, it's easy to make mistakes and end up with an infinite cycle!* **HINT**: to degrow the list, you can use the [pop method](https://en.softpython.org/lists/lists3-sol.htmlpop-method)Example - given:```pythonla = [3,5,6,7]```Executing the code, it must print:``` Odd: attaching 14      la becomes [3, 5, 6, 7, 14]Even: removing 14      removing 7      la becomes [3, 5, 6]Even: removing 6      removing 5      la becomes [3] Odd: attaching 6      la becomes [3, 6]Even: removing 6      removing 3      la becomes []Done! la is []```<jupyter_code>#jupman-purge-output
la = [3,5,6,7]

# write here

i = 0
while len(la) > 0:
    if la[-1] % 2 == 1:
        new = la[-1]*2
        la.append(new)
        print(' Odd: attaching', new)
    else:        
        print('Even: removing',la.pop())        
        print('      removing',la.pop())
    print('      la becomes', la)
    i += 1
print('Done! la is', la)<jupyter_output>Odd: attaching 14
      la becomes [3, 5, 6, 7, 14]
Even: removing 14
      removing 7
      la becomes [3, 5, 6]
Even: removing 6
      removing 5
      la becomes [3]
 Odd: attaching 6
      la becomes [3, 6]
Even: removing 6
      removing 3
      la becomes []
Done! la is []
{'fraction_non_alphanumeric': 0.13020573046809927, 'fraction_numerical': 0.01803265034149592, 'mean_word_length': 3.223834652594547, 'pattern_counts': {'":': 0, '<': 168, '<?xml version=': 0, '>': 135, 'https://': 7, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '31', 'dir': 'jupyter-structured-clean-dedup', 'id': '457080', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 15972, 'n_tokens_neox': 15069, 'n_words': 6072, 'path': 'while/while1-sol.ipynb', 'repo_name': 'simoneb1x/softpython-en', 'size': '48024'}