<jupyter_start><jupyter_text>Pre-Exercises Create a program by growing a rabbit population exponentially, similar to the VO script. The starting population is 100, the growth is 20 percent. Simulate 20 time steps.<jupyter_code># importing matplotlib.pyplot allows us to generate graphs
import matplotlib.pyplot as plt

rabbit_population = 100
RABBIT_GROWTH = 0.2 # 20 %
TIMESTEPS = 20

rabbit_recorder = [rabbit_population]
for it in range(TIMESTEPS):
    rabbits_born = rabbit_population * RABBIT_GROWTH
    rabbit_population = rabbit_population + rabbits_born
    
    rabbit_recorder.append(
            rabbit_population
    )
    
print(rabbit_recorder)
plt.plot(rabbit_recorder)
plt.title("Rabbit population chart")
plt.xlabel("Timesteps")
plt.ylabel("Population")<jupyter_output>[100, 120.0, 144.0, 172.8, 207.36, 248.83200000000002, 298.5984, 358.31808, 429.981696, 515.9780352, 619.17364224, 743.008370688, 891.6100448256, 1069.93205379072, 1283.918464548864, 1540.7021574586367, 1848.8425889503642, 2218.611106740437, 2662.3333280885245, 3194.7999937062295, 3833.7599924474753]<jupyter_text>Add an if-clause that causes the growth to start only after time step 5. Attention: Only the growth itself should be inside the if-statement. Saving the rabbit count to the list should happen at each time step.<jupyter_code>rabbit_population = 100
RABBIT_GROWTH = 0.2 # 20 %
TIMESTEPS = 20

rabbit_recorder = [rabbit_population]
for steps in range(TIMESTEPS):
    if steps >= 5:
        rabbit_population = rabbit_population + rabbit_population * RABBIT_GROWTH
    rabbit_recorder.append(rabbit_population)
    
print(rabbit_recorder)
plt.plot(rabbit_recorder)
plt.title("Rabbit population chart")
plt.xlabel("Timesteps")
plt.ylabel("Population")<jupyter_output>[100, 100, 100, 100, 100, 100, 120.0, 144.0, 172.8, 207.36, 248.83200000000002, 298.5984, 358.31808, 429.981696, 515.9780352, 619.17364224, 743.008370688, 891.6100448256, 1069.93205379072, 1283.918464548864, 1540.7021574586367]<jupyter_text>Add another if-clause that allows the growth only when there are less than 200 rabbits.<jupyter_code>rabbit_population = 100
RABBIT_GROWTH = 0.2 # 20 %
TIMESTEPS = 20

rabbit_recorder = [rabbit_population]
for steps in range(TIMESTEPS):
    if steps >= 5: # nested if statements can query multiple predicates
        if rabbit_population < 200:
            rabbit_population = rabbit_population + rabbit_population * RABBIT_GROWTH
    rabbit_recorder.append(rabbit_population)
    
print(rabbit_recorder)
plt.plot(rabbit_recorder)
plt.title("Rabbit population chart")
plt.xlabel("Timesteps")
plt.ylabel("Population")<jupyter_output>[100, 100, 100, 100, 100, 100, 120.0, 144.0, 172.8, 207.36, 207.36, 207.36, 207.36, 207.36, 207.36, 207.36, 207.36, 207.36, 207.36, 207.36, 207.36]<jupyter_text>Rewrite the if-statement from the last preliminary exercise: Not the current number of rabbits should be decisive, but the number of rabbits in the previous step. For this you will need a list.<jupyter_code>rabbit_population = 100
RABBIT_GROWTH = 0.2 # 20 %
TIMESTEPS = 20

rabbit_recorder = [rabbit_population]
for steps in range(TIMESTEPS):
    if steps >= 5:
        # one - off errors are sometimes hard to track down
        # both, indexing starting with 0 and the time we append
        # to the list (before or after our operations) can alter
        # just where in the list we find the _correct_ number
        # of rabbits we want to find.
        # For now you can use the "print" function to check
        # if your assumptions are met.
        prev_rabbit_population = rabbit_recorder[ steps-1 ]
        if prev_rabbit_population < 200:
            rabbits_born = rabbit_population * RABBIT_GROWTH
            rabbit_population = rabbit_population + rabbits_born
    rabbit_recorder.append(rabbit_population)
    
print(rabbit_recorder)
plt.plot(rabbit_recorder)
plt.title("Rabbit population chart")
plt.xlabel("Timesteps")
plt.ylabel("Population")<jupyter_output>[100, 100, 100, 100, 100, 100, 120.0, 144.0, 172.8, 207.36, 248.83200000000002, 248.83200000000002, 248.83200000000002, 248.83200000000002, 248.83200000000002, 248.83200000000002, 248.83200000000002, 248.83200000000002, 248.83200000000002, 248.83200000000002, 248.83200000000002]<jupyter_text>Exercise Write a program in which you simulate the growth of a rabbit population. At the beginning there are 100 rabbits and in each time step 5% are added. After time step 10, however, the growth behavior should be different: Whenever there have been more than 1000 rabbits 5 steps before the current time step, half of the rabbits migrate to another habitat (and are thus removed from this system). In this case (instead of growth) the number of rabbits should be halved. Simulate 100 time steps.<jupyter_code>rabbit_pop = 100
GROWTH = 0.05 # 5 %
TIMESTEPS = 100
# We can pull out some values and store them in CONSTANT variables.
# That way we can store those *parameters* in one place
# and easily change them throughout the programm quickly.
LIMIT_10 = 10
LOOK_BACK = 5
LIMIT_RABBITS = 1000

recorder = [rabbit_pop]
for step in range(TIMESTEPS):
    rabbits_born = rabbit_pop * GROWTH
    
    if step >= LIMIT_10:
        rabbits_past = recorder[ step - LOOK_BACK ]
        if rabbits_past > LIMIT_RABBITS:
            rabbit_pop = rabbit_pop / 2
        else: # only if the limit was not reached we want the population to grow
            rabbit_pop = rabbit_pop + rabbits_born
    else: # in case the temporal limit was not met yet there's just normal growth
        rabbit_pop = rabbit_pop + rabbits_born
    
    recorder.append(rabbit_pop)
    
print(recorder)
plt.plot(recorder)
plt.title("Big rabbit population chart")
plt.xlabel("Timesteps")
plt.ylabel("Rabbits")<jupyter_output>[100, 105.0, 110.25, 115.7625, 121.550625, 127.62815624999999, 134.00956406249998, 140.71004226562496, 147.7455443789062, 155.13282159785152, 162.8894626777441, 171.0339358116313, 179.58563260221285, 188.5649142323235, 197.99315994393967, 207.89281794113666, 218.2874588381935, 229.20183178010316, 240.6619233691083, 252.69501953756372, 265.3297705144419, 278.596259040164, 292.5260719921722, 307.1523755917808, 322.5099943713698, 338.63549408993833, 355.5672687944352, 373.345632234157, 392.01291384586483, 411.6135595381581, 432.194237515066, 453.8039493908193, 476.4941468603603, 500.3188542033783, 525.3347969135472, 551.6015367592245, 579.1816135971857, 608.140694277045, 638.5477289908972, 670.4751154404421, 703.9988712124642, 739.1988147730874, 776.1587555117418, 814.9666932873289, 855.7150279516953, 898.5007793492802, 943.4258183167442, 990.5971092325814, 1040.1269646942105, 1092.133312928921, 1146.739978575367, 1204.0769775041354, 1264.2808263793422, 1327.4948676983092, 663.74743384915[...]<jupyter_text>Helpful stuffYou can use the `dir()` function to retrieve short information methods and attributes of objects. Try it!Inside of Jupyter you can use the `TAB` key to view options or even autocomplete.<jupyter_code>dir("Some string")
help("Some string".find)
list(). # try using the TAB key - maybe you need to press it twice<jupyter_output><empty_output><jupyter_text>Interesting Stuff Abbreviate mutation of variable values by using **inplace operators** (also called _assignment operators_):<jupyter_code>i = 0
i = i + 1
rabbit_population += 10
print(i)
i = 0
i += 1 # i = i + 1
i<jupyter_output><empty_output><jupyter_text>We can also use this with other operators e.g. for substraction with `-=`:<jupyter_code>i = 0
i -= 1 # i = i - 1
i<jupyter_output><empty_output><jupyter_text>Pretty much any operator in Python can be used as an inplace operator. Here we use multiplication and division on a new `i = 4`:<jupyter_code>i = 4
i *= 2 # i = i * 2
i /= 3 # i = i / 3
i<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0890745501285347, 'fraction_numerical': 0.21439588688946015, 'mean_word_length': 4.712922173274596, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 13, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '260133', 'license': 'MIT', 'n_tokens_mistral': 3950, 'n_tokens_neox': 2626, 'n_words': 766, 'path': 'jupyter/Exercises_03.ipynb', 'repo_name': 'pinselimo/CompBasicsWS21', 'size': '7780'}