FOR GRADERS

I combined my notes, challenges, and homework completion from both lessons into this one document, so it's pretty big and bulky. Here is what I completed (and you can verify by finding these things on the blog's table of contents):

Basic Expectations

Libraries (3.14):

  • Fill-in-the-blank notes
  • Additional notes
  • Challenges 1-3 fully completed (see each in the TOC for proof)
  • Homework "Option 1" (draws a shape with a given random number of sides with Turtle)
  • Homework "Option 2" (finds the difference between two dates, at least one random)

Random Values (3.15):

  • Additional notes
  • Fill-in-the-blank random examples list
  • Challenge 1 (coin flip function)
  • Binary homework

Extras

  • Fully incorporated user input for Libraries Homework "Option 1" and "Option 2"
  • Working failsafe code on Libraries Homework "Option 2"
  • Random Values Challenge 1 "EXTRA": Card Generator and Royal Flush Detector
  • Random Values Homework "EXTRA": Decimal-to-Hexadecimal Converter

Libraries

Okay, so we've learned a lot of code, and all of you now can boast that you can code at least some basic programs in python. But, what about more advanced stuff? What if there's a more advanced program you don't know how to make? Do you need to make it yourself? Well, not always.

You've already learned about functions that you can write to reuse in your code in previous lessons. But,there are many others who code in python just like you. So why would you do again what someone has already done, and is available for any python user?

Packages allow a python user to import methods from a library, and use the methods in their code. Most libraries come with documentation on the different methods they entail and how to use them, and they can be found with a quick Google search. methods are used with the following:

Note: a method from a package can only be used after the import statement.

Some libraries are always installed, such as those with the list methods which we have previously discussed. But others require a special python keyword called `import`. We will learn different ways to import in Challenge 1.

Sometimes we only need to import a single method from the package. We can do that with the word "from", followed by the package name, then the word "import", then the method. This will alllow you to use the method without mentioning the package's name, unlike what we did before, however other methods from that package cannot be used. To get the best of both worlds you can use "*".

To import a method as an easier name, just do what we did first, add the word "as", and write the name you would like to use that package as.

Additional Notes

Here are some extra notes I took for the sake of completion.

  • Some libraries need to be installed before use. Some, however, are innate.
  • Some libraries require the features of other libraries. For example, Turtle relies on Tkinter features to open a window for a canvas.
  • Importing with the format from [library] import * negates the need to specify [library].function() each time.

Challenge 1: Basic Libraries

  1. Find a Python package on the internet and import it
  2. Choose a method from the package and import only the method
  3. import the package as a more convenient name.
from time import *
from IPython.display import clear_output as clr
#i used them to make an ASCII animation
def base():
    print(" | | ")
    print("-----")

def startpos():
    print("  O  ")
    print(" /|\ ")

def waveup():
    print("  O /")
    print(" /|  ")

def wavemid():
    print("  O|  ")
    print(" /|  ")

i = 0
while i < 30:
    clr(wait=True)
    if i == 0:
        startpos()
        base()
    else:
        if i % 2 == 0:
            wavemid()
            base()
        else:
            waveup()
            base()
    i += 1
    sleep(.2)
  O /
 /|  
 | | 
-----

For this challenge, I imported the whole time module using *, which allowed me to call sleep() rather than time.sleep(). I also imported clear_output and renamed it "clr" for simplicity. Try copying and running this yourself for a little animation.

Challenge 2: Turtle

Turtle is a Python drawing package which allows you to draw all kinds of different shapes. It's ofter used to teach beginning python learners, but is really cool to use anywhere. Turtle employs a graphics package to display what you've done, but unfortunately it's kind of annoying to make work with VSCode.

My Image

This is what I created with Turtle. I'm no artist, but I tried to at least show I could use the program from a code perspective.

Didn't load :(
A smiley face and a little star with Christmas colors

Here's the code I used for it. See the code comments for where I satisfied the expectations of this challenge.

import turtle

t = turtle.Turtle()
ts = t.getscreen()
# vvv FOUND THIS ONE MYSELF vvv
ts.bgcolor('pink') #here's me changing a canvas function
t.pensize(5) #here's me changing the pen settings
t.speed('fastest') #more pen/canvas settings
t.color('yellow')
# vvv FOUND THIS ONE MYSELF vvv
t.circle(65) #here's a unique function i used
t.left(90)
t.color('pink')
t.forward(90)
t.left(90)
t.forward(10)
t.left(90)
t.color('black')
t.forward(20)
t.color('pink')
t.left(90)
t.forward(20)
t.left(90)
t.color('black')
t.forward(20)
t.color('pink')
t.left(90)
t.forward(10)
t.left(90)
t.forward(70)
t.color('black')
t.left(90)
i = 0
while i < 50:
    t.forward(1)
    t.left(1)
    i += 1
t.color('pink')
t.setpos(20, -100) #trying out more functions
i = 0
t.color('green', 'red')
# vvv FOUND THIS ONE MYSELF vvv
t.begin_fill()
while i < 25:
    t.forward(150)
    t.right(130)
    i += 1
# vvv FOUND THIS ONE MYSELF vvv
t.end_fill()

Challenge 3: Math

The math package allows for some really cool mathematical methods!

Methods Action
ceil(x) rounds to the largest integer greater than or equal to x
floor(x) rounds to largest integer less than or equal to x
factorial(x) takes the factorial of x
gcd(x,y) returns the greatest common denominator of x and y
lcm(x,y) returns the least common multiple of x and y

Challenge: Create a program which asks for a user input of two numbers, and returns the following:

  • each number rounded up
  • each number rounded down
  • the lcm of the rounded down numbers
  • the gcf of the rounded up numbers
  • the factorial of each number
  • something else using the math package!

I decided to use sqrt.

from math import *

def smorgas(x, y):
    info = []
    for num in [x, y]:
        info.append(ceil(num)) #rounding x and y up
        info.append(floor(num)) #rounding x and y down
    info.append(lcm(floor(x), floor(y))) #the lcm of x and y rounded down
    info.append(gcd(ceil(x), ceil(y))) #the gcd of x and y rounded up
    info.append(factorial(x)) #same as x factorial
    info.append(factorial(y)) #same as y factorial
    info.append(floor(sqrt(x))) #extra: finding and rounding the square root of x
    info.append(floor(sqrt(y))) #extra: square root of y
    return info #returned as list to be called later
i1 = 3
i2 = 5
info = smorgas(i1, i2)
print(i1, "rounded up:", info[0])
print(i1, "rounded down:", info[1])
print(i2, "rounded up:", info[2])
print(i2, "rounded down:", info[3])
print("Least common multiple of", i1, "and", str(i2) + ":", info[4])
print("Greatest common denominator of", i1, "and", str(i2) + ":", info[5])
print("Factorial of", str(i1) + ":", info[6])
print("Factorial of", str(i2) + ":", info[7])
print("Rounded square root of", str(i1) + ":", info[8])
print("Rounded square root of", str(i2) + ":", info[9])
3 rounded up: 3
3 rounded down: 3
5 rounded up: 5
5 rounded down: 5
Least common multiple of 3 and 5: 15
Greatest common denominator of 3 and 5: 1
Factorial of 3: 6
Factorial of 5: 120
Rounded square root of 3: 1
Rounded square root of 5: 2

Homework

As you can see below, I completed both Option 1 and Option 2.

Option 1

Here is the Turtle program that generates a polygon with the number of sizes asked by the user.

Reload the site. There was a problem loading the image.
A very satisfying program to watch. Works for all numbers of sides.

Here is the isolated code:

import turtle

def userInp():
  print("How many sides do you want on the polygon?")
  rsp = input("Please input an integer.")
  rsp = int(rsp)
  return rsp

t = turtle.Turtle()
t.speed('fastest')

i = 0
sides = userInp()
while i < sides:
  angle = 180 - (((sides - 2) * 180) / sides)
  t.forward(360/sides)
  t.left(angle)
  i += 1

And here's code that makes a polygon for a random number of sides from 1 to 10. (1 is just a straight line.)

Reload the site. There was a problem loading the image.
This time, it generates a random number.

And here's the code again.

import turtle
from random import *

t = turtle.Turtle()
t.speed('fastest')

i = 0
sides = randint(1, 10)
print("Number of sides on polygon:", sides)
while i < sides:
  angle = 180 - (((sides - 2) * 180) / sides)
  t.forward(360/sides)
  t.left(angle)
  i += 1

Option 2 ("Libraries HW")

Here is the program that finds the distance between two dates using the datetime package. One set of instructions says to use a user input and a random date while the other says to use two completely random dates, so I made both.

Here's the one that takes one user input and then generates the second randomly:

from datetime import date
from random import *

days_dictionary = {1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31, 8: 31,
    9: 30,10: 31, 11: 30, 12: 31
}

def getUserDate(): #really long because of a bunch of failsafes
    yr = False
    mh = False
    dy = False
    while yr == False:
        print("What year do you want?")
        useryr = input("Input any year. Must be a positive integer.")
        try:
            useryr = abs(int(useryr))
            yr = True
        except:
            print('Please input a valid integer.')
    while mh == False:
        print("What month do you want?")
        usermh = input("Input a month. Must be an integer 1 through 12.")
        try:
            usermh = abs(int(usermh))
            if 1 <= usermh <= 12:
                mh = True
            else:
                print('Please input a valid integer within the range.')
        except:
            print('Please input a valid integer.')
    while dy == False:
        print("What day do you want?")
        userdy = input("Input a day. Must be within the amount of days per year (Feb. with 28).")
        try:
            userdy = abs(int(userdy))
            if 1 <= userdy <= days_dictionary[usermh]:
                dy = True
            else:
                print('Please input a valid day.')
        except:
            print('Please input a valid integer.')
    return date(useryr, usermh, userdy)

def randomDate():
    randyear = randint(1500, 3000) #only from the years 1500 to 3000
    randmonth = randint(1, 12) #limited to 1-12, January-December
    randday = randint(1, days_dictionary[randmonth])
    return date(randyear, randmonth, randday)

date1 = getUserDate()
date2 = randomDate()
delta = abs(date2 - date1)
diff = delta.days
print("User Date:", date1)
print("Random Date:", date2)
print('The number of days between these two dates is', diff, 'days.')
What year do you want?
What month do you want?
What day do you want?
User Date: 2022-12-12
Random Date: 1996-08-24
The number of days between these two dates is 9606 days.

And then here's the one that has two random dates:

date1 = randomDate()
date2 = randomDate()
delta = abs(date2 - date1)
diff = delta.days
print("Random Date 1:", date1)
print("Random Date 2:", date2)
print('The number of days between these two dates is', diff, 'days.')
Random Date 1: 2024-08-25
Random Date 2: 1978-02-26
The number of days between these two dates is 16982 days.

Random Values

This is the start of the 3.15 - Random Values notes section.

Additional Notes

  • Good for cryptography and games
  • Using the import statements we learned about in the last lesson, you can import Python's random module for various random packages
  • Later in the lesson, we can use random to check if a function works in all cases
  • There are multiple ways to use random: choose from a list, select an integer in a range, shuffle a list, etc.

What are Random Values?

Random Values are a number generated using a large set of numbers and a mathematical algorithm which gives equal probability to all number occuring.

Each result from randomization is equally likely to occur. Using random number generation in a program means each execution may produce a different result.

What are examples of (psuedo-)random outputs in the world? Add a few you can think of.

  • Marbles
  • Card game hands
  • Weather
  • APCSP teacher grades

Why Do We Need Random Values for Code?

Adding elements of randomness helps us to simulate these real-world "random" scenarios.

import random
random_number = random.randint(1,100)
print(random_number)
64
def randomlist():
    list = ["apple", "banana", "cherry", "blueberry"]
    element = random.choice(list)
    print(element)
randomlist()
banana

Here's a code version of a dice roll.

import random
for i in range(3):
    roll = random.randint(1,6)
    print("Roll " + str(i + 1) + ":", str(roll))
Roll 1: 4
Roll 2: 3
Roll 3: 5

Challenge 1

I made a function that simulates a coin flip and returns the outcome. You can put it within a print statement (see below) to announce the result.

def coinflip():
    result = random.choice(['heads', 'tails'])
    return result

print("The result was... " + coinflip() + "!")
print("The result was... " + coinflip() + "!")
The result was... tails!
The result was... heads!

Extra

Here's my extra credit function that generates a random hand, then determines if it's a Royal Flush. (Unfortunately, Royal Flushes are incredibly rare, so it's hard to show off what will happen when you get one.)

import random

#initializing
suits = ['Hearts', 'Spades', 'Clubs', 'Diamonds']
cards = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King', 'Ace']
deck = []
for suit in suits:
    for card in cards:
        info = ((card + ' of ' + suit), card, suit)
        deck.append(info)
random.shuffle(deck)

def flush():
    global deck
    flush = ['10', 'Jack', 'Queen', 'King', 'Ace'] #the card conditions for flush
    hand = [deck[0], deck[1], deck[2], deck[3], deck[4]] #already shuffled
    print('Your hand:', hand[0][0] + ",", hand[1][0]+ ",", hand[2][0]+ ",", hand[3][0]+ ",", hand[4][0])
    base = hand[0][2]
    for name, card, suit in hand:
        if suit == base: #if every card has the same suit
            if card in flush: #if the card is in a royal flush set
                pass
            else:
                print('Your hand is NOT a Royal Flush!')
                return
        else:
            print('Your hand is NOT a Royal Flush!')
            return
    print('Your hand is a Royal Flush!') #if all conditions pass, it's a flush
    return

flush()
Your hand: Jack of Diamonds, 3 of Diamonds, 8 of Spades, 3 of Clubs, 3 of Hearts
Your hand is NOT a Royal Flush!

Homework

I decided to do both binary conversion and the extra hexadecimal conversion.

Binary

This cell converts x, a random integer within the domain of 8-bit binary, into binary. Which number was selected is shown in the output.

def DecimalToBinary(num):
    i = 7
    binary = ""
    while i >= 0:
        if num % (2**i) == num:
            binary += "0"
            i -= 1
        else:
            binary += "1"
            num -= 2**i
            i -= 1
    return binary

x = random.randint(0, 255)
print("Initial decimal number:", x)
print("Binary conversion:", DecimalToBinary(x))
Initial decimal number: 47
Binary conversion: 00101111

Hexadecimal

I created a function that converts a random integer y within the domain of 6-bit hexadecimal to hexadecimal. I did it without the built in hex function.

def DecimalToHexa(num):
    hexalist = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
    hexa = []
    hexadec = ''
    while num > 0:
        num, ind = divmod(num, 16)
        hexa.append(hexalist[ind])
    i = (len(hexa) - 1)
    while i >= 0:
        hexadec += hexa[i]
        i -= 1
    return hexadec

y = random.randint(0, 16777215)
print("Initial decimal number:", y)
print("Hexadecimal conversion:", DecimalToHexa(y))
Initial decimal number: 11996363
Hexadecimal conversion: B70CCB