'''
Notice  the three apostrophes before and after this comment. We use them to delimit comments that span more than just one line of text.

To test various examples, comment out the pieces of code you do not care for and run the script ("play" button to the top right in your Visual Studio Code.). To comment out multiple lines at once, select the lines you want to comment, and type CTRL + /. The same shortcut works for uncommenting multiple lines at once.
'''

'''
Exercise 1
'''

i1 = 0
print('i1 = ', i1)
# 0
print('type(i1) = ', type(i1))
# <class 'int'>

pi = 0.0
print('pi = ', pi)
# 0.0
print('type(pi) = ', type(pi))
# <class 'float'>

b = True
print('b = ', b)
# True
print('type(b) = ', type(b))
# <class 'bool'>

i1 = 55
i2 = 22
i3 = 42
m = 77
print('i1 = ', i1, ', i2 = ', i2, ', i3 = ', i3, ', m = ', m) # 55 22 42 77

print(pi, b) # old values, 0.0 True
pi = 3.14
b = False
print(pi, b) # new values, 3.14 False

'''
Arithmetic operators +, -, +=, -=
Exercise 2
'''

i4 = i1
print(i4) # 55
i4 = i2 + i3
print(i4) # 64
i4 = i3 - i1
print(i4) # -13

i4 += 6
print(i4) # -7

i4 -= 3
print(i4) # -10

'''
Arithmetic operators /, //, %, *, **
Exercise 3
'''

i4 = i3 / i2
print('i4 = ', i4) # 1.9090909090909092
print('type(i4) = ', type(i4))  # <class 'float'>
# i4 is a floating point number
# because the result of true division always returns float

i4 = i3 // 27
print('i4 = ', i4) # 1
print('type(i4) = ', type(i4)) # <class 'int'>
# i4 is now an integer
# because both operands of the integer division are integers
print('type(i3) = ', type(i3)) # <class 'int'>

i4 = i3 % 4
print('i4 = ', i4) # 2
print('type(i4) = ', type(i4)) # <class 'int'>
# i4 is an int because the result of the modulo operation is an integer

i4 = i1 ** 2 * i2 # recall the precedence of the operators; ** is the first
print('i4 = ', i4) # 66550
print('type(i4) = ', type(i4)) # <class 'int'>
# no surprises here, as multiplication and exponentiation involved integers

'''
Application pratique du Python
Exercise 4
'''

i4 = 5 * i2 ** 2 + 17 * i2 + 88
print('i4 = 5 * i2 ** 2 + 17 * i2 + 88 = ', i4) # 2882

'''
Application pratique du Python
Exercise 5
'''
r = 1.1
area = r ** 2 * pi # circle area
print('circle area = ', area)
# 3.799400000000008

'''
Application pratique du Python
Exercise 6
'''

r = 2.11 # radius, r
h = 5 # height, h
volume = r**2 * pi * h - r**2 * pi * h/3
print('cylinder volume = ', volume)
# 46.59864666666667

'''
Application pratique du Python
Exercise 7
'''

rho = 0.179 # helium density
weight = rho*40 # weight computation
print('weight = ', weight, 'kg')
# 7.16 kg
# Notice how we added 'kg' at the end of print to print the unit

'''
Boolean operators: and, or and not
Exercise 8
'''

# Initialize variables
pizza = True
drive = True
cocoa_butter = True
pineapple = True
sugar = True
drink = True
milk = True
bus = False
train = True
cocoa = False

# Running various logical expressions and observing results

jail = drink and drive
print('jail = ', jail)
# True, because both drink and drive are True

sin = pizza and pineapple
print('sin = ', sin)
# True, because both pizza and pineapple are True

milk_chocolate = cocoa and cocoa_butter and sugar and milk
print('milk_chocolate = ', milk_chocolate)
# False, because at least one of the four variables is False.
# Find which one(s) is(are) False.

white_chocolate = not(cocoa) and cocoa_butter and sugar and milk
print('white_chocolate = ', white_chocolate)
# True, because all four expressions are True
# Remember to compute not(cocoa) before performing the and operation


transport = bus or train
print('transport = ', transport)
# True, because at least one of the two variables is True
# Find which one(s) is(are) True.

'''
Let's spicy things up by introducing numbers in our logical expressions
'''

n1 = 34 - (m or (not b))
# recall the values of m (77) and b (False)
print('n1 = 34 - (m or (not b)) = 34 - (77 or (not False)) = ', n1)
# -43
# Break the computation in steps:
# (1) compute not False => the result is True
# (2) compute 77 or True => the result is 77
# (3) finally, compute 34 - 77 => the result is -43


n2 = 34 - ((not b) or m)
print('n2 = 34 - ((not b) or m) = n2 = 34 - ((not False) or 77) = ', n2)
# 33
# Break the computation in steps:
# (1) compute not False => the result is True
# (2) compute True or 77 => the result is True (True equals 1)
# (3) finally, compute 34 - True => the result is 33

'''
Comparisons and logical expressions
'''

b4 = (i1 < i2) and (i3 > i1)
# print(i1, i2, i3) # recall values of i1 (55), i2 (22), i3 (42)
print('b4 = (i1 < i2) and (i3 > i1) = (55 < 22) and (42 > 55) = ', b4)
# False
# Break the computation in steps:
# (1) i1 < i2 = 55 < 22 => False
# (2) i3 > i1 = 42 > 55 => False
# (3) False and False => False


b4 = i1 or (i3 and (i2 <= i1))
print('b4 = i1 or (i3 and (i2 <= i1)) = ', b4)
# 55
# Break the computation in steps:
# (1) i2 <= i1 is the same as 22 <= 55; the result is True
# (2) i3 and True = 42 and True; the result is True
# (3) i1 or True = 55 or True; the result is 55

b4 = (i1 == i2) or (i2 != i3)
print('b4 = (i1 == i2) or (i2 != i3) = ', b4)
# True
# Break the computation in steps:
# (1) i1 == i2 is equivalent to 55 == 22; the result is False
# (2) i2 != i3 is equivalent to 22 != 42; the result is True
# (3) b4 = False or True; the result is True

b4 = 15 < i4 < 89
print('i4 = ', i4) # recall the value of i4 (2882)
print('b4 = 15 < i4 < 89 = ', b4)
# False
# Break the computation in steps:
# (1) 15 < i4 is equivalent to 15 < 2882; the result is True
# (2) i4 < 89 is equivalent to 2882 < 89; the result is False
# (3) b4 = True and False; the result is False

'''
Exercise 10
'''
# une expression qui sera vraie (True) si i2 et i3 sont strictement positives
my_expression = i2 > 0 and i3 > 0
print(my_expression)
# True, because both expressions need to be true
# If you are unsure, test the expression by first changing the values of i2 and i3 to a number smaller or equal to zero

# une expression qui sera fausse (False) si i2 est égale au reste de la division de i3 par 7
my_expression = i2 == (i3 % 7)
print(my_expression)
# False
# If you are unsure, test the expression by choosing different values for i3 and i2, to cover various test cases

# une expression qui sera fausse si i2 n’est pas égale à i3
not(i2 != i3)
# False
# If you are unsure, test the expression by choosing different values for i3 and i2, to cover various test cases

'''
Exercise 11
'''
age = 12
answer = 10 <= age <= 60
print(answer)
# True
# If you are unsure, test the expression by choosing different values for the variable age, to cover various test cases

'''
Exercise 12
'''
answer = ((10 <= age <= 60) and "yes") or "no"
print(answer)
# yes
# If you are unsure, test the expression by choosing different values for the variable age, to cover various test cases

'''
Exercise 13
'''
# the expression is s = ((i4 % 2) and "impair") or ((not(i4 % 2)) and "pair");
# let us test it with two values for i4;
# If you are unsure, test the expression by choosing different values for the variable i4, to cover various test cases

i4 = 129
s = ((i4 % 2) and "impair") or ((not(i4 % 2)) and "pair")
print(s)
# impair
# Break the computation in steps
# (1) i4%2 returns 1
# (2) 1 and "impair" returns "impair"
# (3) not(i4%2) returns 0
# (4) 0 and "pair" returns 0
# finally, "impair" or 0 returns "impair"

i4 = 128
s = ((i4 % 2) and "impair") or ((not(i4 % 2)) and "pair")
print(s)
# pair
# Break the computation in steps
# (1) i4%2 returns 0
# (2) 0 and "impair" returns 0
# (3) not(i4%2) returns 1
# (4) 1 and "pair" returns "pair"
# finally, 0 or "pair" returns "pair"

'''
Exercise 14
'''

# "Fizz" si i4 est divisible par 3
i4 = 15
print((i4%3 == 0) and "Fizz")
# 'Fizz'

# "Buzz" si i4 est divisible par 4
i4 = 16
print((4%4 ==0) and "Buzz")
# 'Buzz'

# "FizzBuzz" si i4 est divisible à la fois par 3 et par 4
i4 = 12
print(((i4%3 == 0) and (i4%4 == 0)) and "FizzBuzz")
# 'FizzBuzz'

# la valeur de i4 si i4 n’est divisible ni par 3 ni par 4
i4 = 11
print(((i4%3 != 0) and (i4%4 != 0)) and i4)
# 11

# Finally, we combine all the partial expressions with "logical or" operation
# but we pay close attention to the order of the expressions!
# - first, cover the case when the number is divisible by both 3 and 4
# - then, cover the case when the number is divisible by 3 (or 4, does not matter in which order)
# - cover the only leftover case when the number is not divisible by 3 nor 4; note that this can be simply covered by writing i4 (skipping the check with the modulo operations). Why? Because this case will be evaluated only if no previous case returned True! :-)

my_expression = (((i4%3 == 0) and (i4%4 == 0)) and "FizzBuzz") or ((i4%3 == 0) and "Fizz") or ((i4%4 ==0) and "Buzz") or i4

# Testing for various cases (i4 = 11, i4 = 12, i4 = 8, i4 = 9)
i4 = 11 # expected answer: 11
my_expression = (((i4%3 == 0) and (i4%4 == 0)) and "FizzBuzz") or ((i4%3 == 0) and "Fizz") or ((i4%4 ==0) and "Buzz") or i4
print('i4 = ', i4, '; my_expression = ', my_expression)

i4 = 12 # expected answer: FizzBuzz
my_expression = (((i4%3 == 0) and (i4%4 == 0)) and "FizzBuzz") or ((i4%3 == 0) and "Fizz") or ((i4%4 ==0) and "Buzz") or i4
print('i4 = ', i4, '; my_expression = ', my_expression)

i4 = 8 # expected answer: Buzz
my_expression = (((i4%3 == 0) and (i4%4 == 0)) and "FizzBuzz") or ((i4%3 == 0) and "Fizz") or ((i4%4 ==0) and "Buzz") or i4
print('i4 = ', i4, '; my_expression = ', my_expression)

i4 = 9 # expected answer: Fizz
my_expression = (((i4%3 == 0) and (i4%4 == 0)) and "FizzBuzz") or ((i4%3 == 0) and "Fizz") or ((i4%4 ==0) and "Buzz") or i4
print('i4 = ', i4, '; my_expression = ', my_expression)