Chapters 4-6
Case study: Turtle
def petal(t, r, angle):
for i in range(2):
arc(t, r, angle)
lt(t, 180 - angle)
def flower(t, n, r, angle):
for i in range(n):
petal(t, r, angle)
lt(t, 360.0 / n)
flower(bob, 7, 60.0, 60.0)
def isosceles(t, r, angle):
y = r * math.sin(angle * math.pi / 180)
rt(t, angle)
fd(t, r)
lt(t, 90+angle)
fd(t, 2*y)
lt(t, 90+angle)
fd(t, r)
lt(t, 180-angle)
def polypie(t, n, r):
angle = 360.0 / n
for i in range(n):
isosceles(t, r, angle/2)
lt(t, angle)
polypie(bob, 5, 40)
This one is big! Go look at the solution: letters.py
Conditionals and recursion
Division:
quotient = 7 / 3
print quotient # 2
Modulus:
remainder = 7 % 3
print remainder # 1
Practical example! Modulus can be used to check even/odd numbers, like so:
some_number = 5
even = some_number % 2 == 0
print even # False
and
, or
and not
.
print True and False # False
print True or False # True
print not True # False
Use these to combine statements to create logic.
all_humans_are_mortal = True
socrates_is_a_human = is_a_human("socrates")
socrates_is_mortal = all_humans_are_mortal and socrates_is_a_human
Only run some code if a condition is met (IE True
)
if all_humans_are_mortal and socrates_is_a_human:
print "Yep, Socrates is mortal."
Something to run only if the condition is not True. Use else
.
if all_humans_are_mortal and socrates_is_a_human:
print "Yep, Socrates is mortal."
else:
print "Socrates is either not mortal or not a human."
Run a series of "if..else" in a nicer form with elif
:
if favorite_color == "red":
print "Red like a rose"
elif favorite_color == "yellow":
print "Yellow as the sun"
else:
print "Not red or yellow? Shame!"
You can put a conditional inside another conditional.
if all_humans_are_mortal:
if socrates_is_a_human:
print "Yep, Socrates is mortal."
In this case, it's equivalent to our example from earlier:
if all_humans_are_mortal and socrates_is_a_human:
print "Yep, Socrates is mortal."
It's legal for a function to call itself
def countdown(n):
if n <= 0:
print "Blastoff!"
else:
print n
countdown(n - 1)
but not too much
def infinite():
infinite()
Get input from the user (at the command prompt)
def echo():
text = raw_input("Shout into the void: ")
print "You hear back:"
print text
print text
print text
ALWAYS use raw_input instead of input. Whatever you type into input is evaluated, and you want to control that logic.
Fermat’s Last Theorem says that there are no integers a, b, and c such that a^n + b^n = c^n for any values of n greater than 2.
def check_fermat(a, b, c, n):
if n > 2 and a ** n + b ** n == c ** n:
print "Holy smokes, Fermat was wrong!"
else:
print "No, that doesn't work."
def check_fermat_interactively():
a = int(raw_input("A: "))
b = int(raw_input("B: "))
c = int(raw_input("C: "))
n = int(raw_input("N: "))
check_fermat(a, b, c, n)
If you are given three sticks, you may or may not be able to arrange them in a triangle.
def is_triangle(a, b, c):
if a + b >= c or a + c >= b or b + c >= a:
print "Yes"
else:
print "No"
def is_triangle_interactively():
a = int(raw_input("side A: "))
b = int(raw_input("side B: "))
c = int(raw_input("side C: "))
is_triangle(a, b, c)
Of course, this doesn't work for negative numbers
What does this do?
def draw(t, length, n):
if n == 0:
return
angle = 50
fd(t, length*n)
lt(t, angle)
draw(t, length, n-1)
rt(t, 2*angle)
draw(t, length, n-1)
lt(t, angle)
bk(t, length*n)
draw(bob, 10, 5)
def koch(t, n):
if n<3:
fd(t, n)
return
m = n/3.0
koch(t, m)
lt(t, 60)
koch(t, m)
rt(t, 120)
koch(t, m)
lt(t, 60)
koch(t, m)
def snowflake(t, n):
"""Draws a snowflake (a triangle with a Koch curve for each side)."""
for i in range(3):
koch(t, n)
rt(t, 120)
Fruitful Functions
def square(n):
return n * n
def cube(n):
return n ** 3
a = square(2) # 4
b = cube(2) # 8
def absolute_value(x):
if x < 0:
return -x
else:
return x
def compare(x, y):
if x > y:
return 1
elif x == y:
return 0
else: # x < y
return 1
def is_divisible(a, b):
if a % b == 0:
return True
else:
return False
Since we're dealing with boolean values, this works better...
def is_divisible(a, b):
return a % b == 0
Rule of thumb: any time you're returning a boolean inside a conditional, check whether you can return the result of the computation directly.
def factorial (n):
if not isinstance(n, int):
print 'Factorial is only defined for integers.'
return None
elif n < 0:
print 'Factorial is not defined for negative integers.'
return None
elif n == 0:
return 1
else:
return n * factorial(n-1)
leads to...
>>> factorial('fred')
Factorial is only defined for integers.
None
>>> factorial(-2)
Factorial is not defined for negative integers.
None
def ackermann(m, n):
if m == 0:
return n+1
if n == 0:
return ackermann(m-1, 1)
return ackermann(m-1, ackermann(m, n-1))
print ackermann(3, 4)
Technically, this is an Ackermann–Péter function.
def first(word):
return word[0]
def last(word):
return word[-1]
def middle(word):
return word[1:-1]
def is_palindrome(word):
if len(word) <= 1:
return True
if first(word) != last(word):
return False
return is_palindrome(middle(word))
is_palindrome("racecar") # True
# 0: word = "racecar" (first and last are "r", recurse)
# 1: word = "aceca" (first and last are "a", recurse)
# 2: word = "cec" (first and last are "c", recurse)
# 3: word = "e" (the length is 1, return True)
is_palindrome("ehorse") # False
# 0: word = "ehorse" (first and last letters are "e", recurse)
# 1: word = "hors" (first and last letters are not equal, return False)
Note that this breaks the rule of thumb discussed earlier, but for good reasons!
A number, 'a', is a power of 'b' if it is divisible by 'b' and 'a/b' is a power of 'b'.
def is_power(a, b):
print "Checking %d and %d" % (a, b)
if a == b:
return True
elif a % b == 0:
return is_power(a/b, b)
else:
return False
From the book: "One way to find the GCD of two numbers is Euclid’s algorithm, which is based on the observation that if 'r' is the remainder when 'a' is divided by 'b', then 'gcd(a, b) = gcd(b, r)'. As a base case, we can consider 'gcd(a, 0) = a'."
def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
# 0: checking 55 and 10 (recurse to gcd(10, 5))
# 1: checking 10 and 5 (recurse to gcd(5, 0))
# 2: checking 5 and 0 (return 5)