Preparing git repo for final project
8
problems/prepare.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/bash
|
||||
this_script_directory=$(cd "$(dirname "${0}")" && pwd);
|
||||
read -r -p "Enter the name of the next challenge " challengeName;
|
||||
cd "$this_script_directory";
|
||||
mkdir "$challengeName";
|
||||
cd "$challengeName";
|
||||
code "$challengeName".py
|
||||
code "test_$challengeName".py
|
16
problems/pset0/einstein/einstein.py
Normal file
@ -0,0 +1,16 @@
|
||||
c = 300000000
|
||||
|
||||
|
||||
def compute_energy():
|
||||
mass = None
|
||||
while not isinstance(mass, int):
|
||||
input_string = input("Enter a mass:\t\t")
|
||||
try:
|
||||
mass = int(input_string)
|
||||
except (ValueError, TypeError):
|
||||
mass = None
|
||||
print(mass*(c**2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
compute_energy()
|
9
problems/pset0/faces/faces.py
Normal file
@ -0,0 +1,9 @@
|
||||
def replace_emoticons_with_emojis():
|
||||
input_string = input("Say something quickly and I will repeat it slowly!\t\t")
|
||||
for emoticon, emoji in {':)': '🙂', ':(': '🙁'}.items():
|
||||
input_string = input_string.replace(emoticon, emoji)
|
||||
print(input_string)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
replace_emoticons_with_emojis()
|
7
problems/pset0/indoor/indoor.py
Normal file
@ -0,0 +1,7 @@
|
||||
def prompt_user_and_echo_lowercase():
|
||||
input_string = input("Shout me something and I will repeat it with indoor voice!\t\t")
|
||||
print(input_string.lower())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
prompt_user_and_echo_lowercase()
|
7
problems/pset0/playback/playback.py
Normal file
@ -0,0 +1,7 @@
|
||||
def prompt_user_and_echo_lowercase():
|
||||
input_string = input("Say something quickly and I will repeat it slowly!\t\t")
|
||||
print(input_string.replace(' ', '...'))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
prompt_user_and_echo_lowercase()
|
17
problems/pset0/tip/tip.py
Normal file
@ -0,0 +1,17 @@
|
||||
def main():
|
||||
dollars = dollars_to_float(input("How much was the meal? "))
|
||||
percent = percent_to_float(input("What percentage would you like to tip? "))
|
||||
tip = dollars * percent
|
||||
print(f"Leave ${tip:.2f}")
|
||||
|
||||
|
||||
def dollars_to_float(d):
|
||||
return float(d[1:])
|
||||
|
||||
|
||||
def percent_to_float(p):
|
||||
return float(p[:-1])/100
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
12
problems/pset1/bank/bank.py
Normal file
@ -0,0 +1,12 @@
|
||||
def main():
|
||||
greeting = input("Greeting:\t\t").lower().strip()
|
||||
if greeting.startswith("hello"):
|
||||
print("$0")
|
||||
elif greeting.startswith("h"):
|
||||
print("$20")
|
||||
else:
|
||||
print("$100")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
28
problems/pset1/deep/deep.py
Normal file
@ -0,0 +1,28 @@
|
||||
import re
|
||||
answer_regex = re.compile(r"\s*(42|forty[ -]?two)\s*", re.IGNORECASE)
|
||||
|
||||
def ifelse_answer():
|
||||
answer = input("What is the Answer to the Great Question of Life, the Universe, and Everything?\t\t")
|
||||
answer = answer.strip()
|
||||
answer = answer.replace('-', '')
|
||||
answer = answer.replace(' ', '')
|
||||
answer = answer.lower()
|
||||
if answer in ('42', 'fortytwo'):
|
||||
print("Yes")
|
||||
else:
|
||||
print("No")
|
||||
|
||||
|
||||
def regex_answer():
|
||||
print('Yes'
|
||||
if answer_regex.match(
|
||||
input("What is the Answer to the Great Question of Life, the Universe, and Everything?\t\t"))
|
||||
else 'No')
|
||||
|
||||
|
||||
def oneliner():
|
||||
print({True: 'Yes', False: 'No'}[input("What is the Answer to the Great Question of Life, the Universe, and Everything?\t\t").lower().strip() in ('42', 'fortytwo', 'forty two', 'forty-two')])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
regex_answer()
|
22
problems/pset1/extensions/extensions.py
Normal file
@ -0,0 +1,22 @@
|
||||
extensions = {
|
||||
".gif": "image/gif",
|
||||
".jpg": "image/jpeg",
|
||||
".jpeg": "image/jpeg",
|
||||
".png": "image/png",
|
||||
".pdf": "application/pdf",
|
||||
".txt": "text/plain",
|
||||
".zip": "application/zip"
|
||||
}
|
||||
|
||||
def main():
|
||||
file_name = input("Enter file name:\t\t").lower().strip()
|
||||
for extension, mime in extensions.items():
|
||||
if file_name.endswith(extension):
|
||||
print(mime)
|
||||
break
|
||||
else:
|
||||
print("application/octet-stream")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
17
problems/pset1/interpreter/interpreter.py
Normal file
@ -0,0 +1,17 @@
|
||||
def main():
|
||||
expression = input("Enter an arithmetic expression:\t\t")
|
||||
x, y, z = expression.split()
|
||||
result = 0.0
|
||||
if y == '+':
|
||||
result = int(x) + int(z)
|
||||
elif y == '-':
|
||||
result = int(x) - int(z)
|
||||
elif y == '*':
|
||||
result = int(x) * int(z)
|
||||
elif y == '/':
|
||||
result = int(x) / int(z)
|
||||
print(round(float(result), 1))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
17
problems/pset1/meal/meal.py
Normal file
@ -0,0 +1,17 @@
|
||||
def main():
|
||||
t = convert(input("What time is it?\t\t"))
|
||||
if 7 <= t <= 8:
|
||||
print("breakfast time")
|
||||
elif 12 <= t <= 13:
|
||||
print("lunch time")
|
||||
elif 18 <= t <= 19:
|
||||
print("dinner time")
|
||||
|
||||
|
||||
def convert(time):
|
||||
h ,m = map(int, time.split(":"))
|
||||
return float(h + m / 60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
16
problems/pset2/camel/camel.py
Normal file
@ -0,0 +1,16 @@
|
||||
def main():
|
||||
camel_string = input("camelCase:\t\t")
|
||||
print(f"snake_case:\t\t{convert_to_snake_case(camel_string)}")
|
||||
|
||||
|
||||
def convert_to_snake_case(s: str):
|
||||
result = ''
|
||||
for char in s:
|
||||
if char == char.upper():
|
||||
result += '_'
|
||||
result += char.lower()
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
15
problems/pset2/coke/coke.py
Normal file
@ -0,0 +1,15 @@
|
||||
def main():
|
||||
total_coins = 0
|
||||
while total_coins < 50:
|
||||
print(f"Amount Due: {50 - total_coins}")
|
||||
new_coin = input("Insert coin:\t\t")
|
||||
if new_coin not in ('5', '10', '25'):
|
||||
new_coin = 0
|
||||
else:
|
||||
new_coin = int(new_coin)
|
||||
total_coins += new_coin
|
||||
print(f"Change Owed: {total_coins - 50}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
14
problems/pset2/nutrition/nutrition.py
Normal file
@ -0,0 +1,14 @@
|
||||
fruits = {'apple': '130', 'avocado': '50', 'banana': '110', 'cantaloupe': '50',
|
||||
'grapefruit': '60', 'grapes': '90', 'honeydew melon': '50', 'kiwifruit': '90', 'lemon': '15', 'lime': '20',
|
||||
'nectarine': '60', 'orange': '80', 'peach': '60', 'pear': '100', 'pineapple': '50', 'plums': '70', 'strawberries': '50',
|
||||
'sweet cherries': '100', 'tangerine': '50', 'watermelon': '80'}
|
||||
|
||||
|
||||
def main():
|
||||
fruit = input("Item:\t\t").lower()
|
||||
if fruit in fruits:
|
||||
print(f"Calories:\t\t{fruits[fruit]}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
39
problems/pset2/plates/plates.py
Normal file
@ -0,0 +1,39 @@
|
||||
import re
|
||||
|
||||
|
||||
def main():
|
||||
plate = input("Plate: ")
|
||||
if is_valid(plate):
|
||||
print("Valid")
|
||||
else:
|
||||
print("Invalid")
|
||||
|
||||
|
||||
def is_valid(s):
|
||||
if len(s) < 2 or len(s) > 6:
|
||||
return False
|
||||
return re.match(r"^[A-Z]{2,}([1-9]\d+)?(?![A-Z])$", s)
|
||||
|
||||
|
||||
def loopy_is_valid(s):
|
||||
length = 0
|
||||
has_digits = False
|
||||
for n, c in enumerate(s):
|
||||
if n > 6:
|
||||
return False
|
||||
if not c.isalnum():
|
||||
return False
|
||||
if n < 2 and not c.isalpha():
|
||||
return False
|
||||
if c.isdigit():
|
||||
if not has_digits and c == '0':
|
||||
return False
|
||||
has_digits = True
|
||||
elif has_digits:
|
||||
return False
|
||||
length += 1
|
||||
return length >= 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
11
problems/pset2/twttr/twttr.py
Normal file
@ -0,0 +1,11 @@
|
||||
def main():
|
||||
tweet = input("Input: \t\t")
|
||||
result = ''
|
||||
for c in tweet:
|
||||
if c.lower() not in ('a', 'e', 'i', 'o', 'u'):
|
||||
result += c
|
||||
print(f"Output: {result}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
21
problems/pset3/fuel/fuel.py
Normal file
@ -0,0 +1,21 @@
|
||||
def main():
|
||||
while True:
|
||||
fuel = input("Fraction:\t\t")
|
||||
try:
|
||||
x, y = map(int, fuel.split('/'))
|
||||
if x > y:
|
||||
continue
|
||||
result = x / y
|
||||
break
|
||||
except (ValueError, ZeroDivisionError):
|
||||
continue
|
||||
if result <= 0.01:
|
||||
print("E")
|
||||
elif result >= 0.99:
|
||||
print("F")
|
||||
else:
|
||||
print(f"{int(round(result*100, 0))}%")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
16
problems/pset3/grocery/grocery.py
Normal file
@ -0,0 +1,16 @@
|
||||
def main():
|
||||
shopping_list = {}
|
||||
while True:
|
||||
try:
|
||||
item = input("").upper()
|
||||
except EOFError:
|
||||
break
|
||||
if item not in shopping_list:
|
||||
shopping_list[item] = 0
|
||||
shopping_list[item] += 1
|
||||
for item, quantity in sorted(shopping_list.items(), key=lambda x: x[0]):
|
||||
print(f"{quantity} {item}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
41
problems/pset3/outdated/outdated.py
Normal file
@ -0,0 +1,41 @@
|
||||
import re
|
||||
|
||||
months = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December"
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
while True:
|
||||
try:
|
||||
entered_date = input("Date: ").strip()
|
||||
except Exception:
|
||||
continue
|
||||
if re.match(r"\d+/\d+/\d+", entered_date):
|
||||
month, day, year = map(int, entered_date.split('/'))
|
||||
elif re.match(r"\w+ \d{1,2}, \d{4}", entered_date):
|
||||
entered_date = entered_date.replace(",", "")
|
||||
month, day, year = entered_date.split(' ')
|
||||
month = months.index(month) + 1
|
||||
day, year = map(int, (day, year))
|
||||
else:
|
||||
continue
|
||||
if month > 12 or day > 31:
|
||||
continue
|
||||
break
|
||||
print(f"{year:04d}-{month:02d}-{day:02d}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
27
problems/pset3/taqueria/taqueria.py
Normal file
@ -0,0 +1,27 @@
|
||||
menu = {
|
||||
"Baja Taco": 4.00,
|
||||
"Burrito": 7.50,
|
||||
"Bowl": 8.50,
|
||||
"Nachos": 11.00,
|
||||
"Quesadilla": 8.50,
|
||||
"Super Burrito": 8.50,
|
||||
"Super Quesadilla": 9.50,
|
||||
"Taco": 3.00,
|
||||
"Tortilla Salad": 8.00
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
total = 0.0
|
||||
while True:
|
||||
try:
|
||||
dish = input("Item: :\t\t").title()
|
||||
except EOFError:
|
||||
break
|
||||
if dish in menu:
|
||||
total += menu[dish]
|
||||
print(f"Total: ${total:.2f}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
25
problems/pset4/adieu/adieu.py
Normal file
@ -0,0 +1,25 @@
|
||||
def main():
|
||||
names = []
|
||||
while True:
|
||||
try:
|
||||
name = input("Name: ")
|
||||
names.append(name)
|
||||
except EOFError:
|
||||
break
|
||||
if len(names) == 0:
|
||||
return
|
||||
result = "Adieu, adieu, to "
|
||||
for n, name in enumerate(names):
|
||||
if n == 0:
|
||||
result += name
|
||||
elif n == 1 and len(names) == 2:
|
||||
result += f" and {name}"
|
||||
elif n == len(names) - 1:
|
||||
result += f", and {name}"
|
||||
else:
|
||||
result += f", {name}"
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
24
problems/pset4/bitcoin/bitcoin.py
Normal file
@ -0,0 +1,24 @@
|
||||
import json
|
||||
import requests
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
n = float(sys.argv[1])
|
||||
except IndexError:
|
||||
sys.exit("Missing command-line argument")
|
||||
except (ValueError, TypeError):
|
||||
sys.exit("Command-line argument is not a number")
|
||||
try:
|
||||
response = requests.get("https://api.coindesk.com/v1/bpi/currentprice.json")
|
||||
data = response.json()
|
||||
conversion_rate = float(data['bpi']['USD']['rate'].replace(',', ''))
|
||||
except requests.RequestException:
|
||||
pass
|
||||
print(f"${n * conversion_rate:,.4f}")
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
10
problems/pset4/emojize/emojize.py
Normal file
@ -0,0 +1,10 @@
|
||||
import emoji
|
||||
|
||||
|
||||
def main():
|
||||
input_text = input("Input: ").strip()
|
||||
print(emoji.emojize(emoji.emojize(input_text, language='alias'), language='en'))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
24
problems/pset4/figlet/figlet.py
Normal file
@ -0,0 +1,24 @@
|
||||
import sys
|
||||
|
||||
from pyfiglet import Figlet
|
||||
|
||||
figlet = Figlet()
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) > 1:
|
||||
if len(sys.argv) != 3:
|
||||
sys.exit("This script takes 2 or no command-line arguments")
|
||||
if sys.argv[1] not in ('-f', '--font'):
|
||||
sys.exit(f"Unknown option `{sys.argv[1]}`")
|
||||
available_fonts = figlet.getFonts()
|
||||
font = sys.argv[2]
|
||||
if font not in available_fonts:
|
||||
sys.exit(f"Unknown font `{sys.argv[2]}`")
|
||||
figlet.setFont(font=font)
|
||||
input_text = input("Input: ")
|
||||
print(figlet.renderText(input_text))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
28
problems/pset4/game/game.py
Normal file
@ -0,0 +1,28 @@
|
||||
import random
|
||||
|
||||
|
||||
def main():
|
||||
n = -1
|
||||
while n < 1:
|
||||
try:
|
||||
n = int(input("Level: "))
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
random.seed()
|
||||
n_to_guess = random.randint(1, n)
|
||||
guess = -1
|
||||
while n_to_guess - guess != 0:
|
||||
try:
|
||||
guess = int(input("Guess: "))
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
if guess == n_to_guess:
|
||||
print("Just right!")
|
||||
if guess < n_to_guess:
|
||||
print("Too small!")
|
||||
if guess > n_to_guess:
|
||||
print("Too large!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
43
problems/pset4/professor/professor.py
Normal file
@ -0,0 +1,43 @@
|
||||
import random
|
||||
|
||||
|
||||
def main():
|
||||
# random.seed() # This breaks check50 😠
|
||||
score = 0
|
||||
level = get_level()
|
||||
for _ in range(10):
|
||||
x = generate_integer(level)
|
||||
y = generate_integer(level)
|
||||
for _ in range(3):
|
||||
try:
|
||||
answer = int(input(f"{x} + {y} ="))
|
||||
except (ValueError, TypeError):
|
||||
answer = -1
|
||||
if answer == x + y:
|
||||
score += 1
|
||||
break
|
||||
else:
|
||||
print("EEE")
|
||||
else:
|
||||
print(f"{x} + {y} = {x + y}")
|
||||
print(f"Score: {score}")
|
||||
|
||||
|
||||
def get_level():
|
||||
level = 0
|
||||
while level not in (1, 2, 3):
|
||||
try:
|
||||
level = int(input("Level: "))
|
||||
except (ValueError, TypeError):
|
||||
level = 0
|
||||
return level
|
||||
|
||||
|
||||
def generate_integer(level):
|
||||
if level not in (1, 2, 3):
|
||||
raise ValueError
|
||||
return random.randint((10**(level - 1) if level > 1 else 0), 10**level - 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
17
problems/pset5/test_bank/bank.py
Normal file
@ -0,0 +1,17 @@
|
||||
def main():
|
||||
greeting = input("Greeting:\t\t")
|
||||
print(value(f"${greeting}"))
|
||||
|
||||
|
||||
def value(greeting: str) -> str:
|
||||
greeting = greeting.lower().strip()
|
||||
if greeting.startswith("hello"):
|
||||
return 0
|
||||
elif greeting.startswith("h"):
|
||||
return 20
|
||||
else:
|
||||
return 100
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
77
problems/pset5/test_bank/test_bank.py
Normal file
@ -0,0 +1,77 @@
|
||||
from bank import value
|
||||
|
||||
|
||||
def main():
|
||||
test_lower()
|
||||
test_upper()
|
||||
test_title_case()
|
||||
test_mixed_case()
|
||||
test_zero()
|
||||
test_twenty()
|
||||
test_empty()
|
||||
test_hundred()
|
||||
test_containing_hello()
|
||||
|
||||
|
||||
def test_lower():
|
||||
assert value('hello') == 0
|
||||
assert value('hey') == 20
|
||||
assert value('banana') == 100
|
||||
|
||||
|
||||
def test_upper():
|
||||
assert value('HELLO') == 0
|
||||
assert value('HEY') == 20
|
||||
assert value('BANANA') == 100
|
||||
|
||||
|
||||
def test_title_case():
|
||||
assert value('Hello') == 0
|
||||
assert value('Hey') == 20
|
||||
assert value('Banana') == 100
|
||||
|
||||
|
||||
def test_mixed_case():
|
||||
assert value('Hello') == 0
|
||||
assert value('Hey') == 20
|
||||
assert value('Banana') == 100
|
||||
|
||||
|
||||
def test_zero():
|
||||
assert value('Hello') == 0
|
||||
assert value('hello') == 0
|
||||
assert value('HELLO') == 0
|
||||
assert value('HeLlO') == 0
|
||||
assert value('hElLo') == 0
|
||||
|
||||
|
||||
def test_twenty():
|
||||
assert value('Hey') == 20
|
||||
assert value('hey') == 20
|
||||
assert value('HEY') == 20
|
||||
assert value('HeY') == 20
|
||||
assert value('hEy') == 20
|
||||
assert value('h') == 20
|
||||
assert value('h20') == 20
|
||||
|
||||
|
||||
def test_empty():
|
||||
assert value('') == 100
|
||||
|
||||
|
||||
def test_hundred():
|
||||
assert value('Banana') == 100
|
||||
assert value('banana') == 100
|
||||
assert value('BANANA') == 100
|
||||
assert value('12345678') == 100
|
||||
assert value('nothello') == 100
|
||||
|
||||
def test_containing_hello():
|
||||
assert value('aHello') == 100
|
||||
assert value('ahello') == 100
|
||||
assert value('aHELLO') == 100
|
||||
assert value('aHeLlO') == 100
|
||||
assert value('ahElLo') == 100
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
35
problems/pset5/test_fuel/fuel.py
Normal file
@ -0,0 +1,35 @@
|
||||
def main():
|
||||
while True:
|
||||
fuel = input("Fraction:\t\t")
|
||||
try:
|
||||
result = convert(fuel)
|
||||
break
|
||||
except (ValueError, ZeroDivisionError):
|
||||
continue
|
||||
print(gauge(result))
|
||||
|
||||
|
||||
|
||||
def convert(fraction: str) -> int:
|
||||
try:
|
||||
x, y = map(int, fraction.split('/'))
|
||||
except (ValueError, TypeError):
|
||||
raise ValueError
|
||||
if x > y:
|
||||
raise ValueError
|
||||
if y == 0:
|
||||
raise ZeroDivisionError
|
||||
return int(round(x / y*100, 0))
|
||||
|
||||
|
||||
def gauge(percentage):
|
||||
if percentage <= 1:
|
||||
return "E"
|
||||
elif percentage >= 99:
|
||||
return "F"
|
||||
else:
|
||||
return f"{percentage}%"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
41
problems/pset5/test_fuel/test_fuel.py
Normal file
@ -0,0 +1,41 @@
|
||||
from fuel import convert, gauge
|
||||
|
||||
def main():
|
||||
test_convert()
|
||||
test_gauge()
|
||||
test_value_error()
|
||||
test_zero_division_error()
|
||||
|
||||
def test_convert():
|
||||
assert convert("0/4") == 0
|
||||
assert convert("1/4") == 25
|
||||
assert convert("4/4") == 100
|
||||
|
||||
def test_value_error():
|
||||
try:
|
||||
convert("5/4")
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
raise Exception("ValueError not raised with y>x")
|
||||
|
||||
|
||||
def test_zero_division_error():
|
||||
try:
|
||||
convert("5/0")
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
else:
|
||||
raise Exception("ZeroDivisionError not raised with y = 0")
|
||||
|
||||
|
||||
def test_gauge():
|
||||
assert gauge(100) == 'F'
|
||||
assert gauge(99) == 'F'
|
||||
assert gauge(0) == 'E'
|
||||
assert gauge(1) == 'E'
|
||||
assert gauge(27) == '27%'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
39
problems/pset5/test_plates/plates.py
Normal file
@ -0,0 +1,39 @@
|
||||
import re
|
||||
|
||||
|
||||
def main():
|
||||
plate = input("Plate: ")
|
||||
if is_valid(plate):
|
||||
print("Valid")
|
||||
else:
|
||||
print("Invalid")
|
||||
|
||||
|
||||
def is_valid(s):
|
||||
if len(s) < 2 or len(s) > 6:
|
||||
return False
|
||||
return re.match(r"^[A-Z]{2,}([1-9]\d+)?(?![A-Z])$", s) is not None
|
||||
|
||||
|
||||
def loopy_is_valid(s):
|
||||
length = 0
|
||||
has_digits = False
|
||||
for n, c in enumerate(s):
|
||||
if n > 6:
|
||||
return False
|
||||
if not c.isalnum():
|
||||
return False
|
||||
if n < 2 and not c.isalpha():
|
||||
return False
|
||||
if c.isdigit():
|
||||
if not has_digits and c == '0':
|
||||
return False
|
||||
has_digits = True
|
||||
elif has_digits:
|
||||
return False
|
||||
length += 1
|
||||
return length >= 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
39
problems/pset5/test_plates/test_plates.py
Normal file
@ -0,0 +1,39 @@
|
||||
from plates import is_valid
|
||||
|
||||
|
||||
def main():
|
||||
test_incipit()
|
||||
test_length()
|
||||
test_digits()
|
||||
test_forbidden_characters()
|
||||
|
||||
|
||||
def test_incipit():
|
||||
assert is_valid('11AA11') == False
|
||||
assert is_valid('11AA') == False
|
||||
assert is_valid('1AA2') == False
|
||||
assert is_valid('2AAP') == False
|
||||
assert is_valid('A1111') == False
|
||||
assert is_valid('AA1111') == True
|
||||
|
||||
|
||||
def test_length():
|
||||
assert is_valid('') == False
|
||||
assert is_valid('A') == False
|
||||
assert is_valid('AAAAAA111111') == False
|
||||
|
||||
|
||||
def test_digits():
|
||||
assert is_valid('AA111A') == False
|
||||
assert is_valid('AA0111') == False
|
||||
|
||||
|
||||
def test_forbidden_characters():
|
||||
assert is_valid('AA1.1') == False
|
||||
assert is_valid('AA1,1') == False
|
||||
assert is_valid('AA1 1') == False
|
||||
assert is_valid('AA11!') == False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
33
problems/pset5/test_twttr/test_twttr.py
Normal file
@ -0,0 +1,33 @@
|
||||
from twttr import shorten
|
||||
|
||||
|
||||
def main():
|
||||
test_uppercase()
|
||||
test_lowercase()
|
||||
test_null()
|
||||
test_digits()
|
||||
test_punctuation()
|
||||
|
||||
|
||||
def test_uppercase():
|
||||
assert shorten('TWITTER') == 'TWTTR'
|
||||
|
||||
|
||||
def test_lowercase():
|
||||
assert shorten('twitter') == 'twttr'
|
||||
|
||||
|
||||
def test_null():
|
||||
assert shorten('') == ''
|
||||
|
||||
|
||||
def test_digits():
|
||||
assert shorten('abc123') == 'bc123'
|
||||
|
||||
|
||||
def test_punctuation():
|
||||
assert shorten('abc,') == 'bc,'
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
16
problems/pset5/test_twttr/twttr.py
Normal file
@ -0,0 +1,16 @@
|
||||
def main():
|
||||
tweet = input("Input: \t\t")
|
||||
result = shorten(tweet)
|
||||
print(f"Output: {result}")
|
||||
|
||||
|
||||
def shorten(word: str) -> str:
|
||||
result = ''
|
||||
for c in word:
|
||||
if c.lower() not in ('a', 'e', 'i', 'o', 'u'):
|
||||
result += c
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
33
problems/pset6/lines/lines.py
Normal file
@ -0,0 +1,33 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
file_name = sys.argv[1]
|
||||
except IndexError:
|
||||
print("Provide a file name from command line!")
|
||||
sys.exit(1)
|
||||
if len(sys.argv) > 2:
|
||||
print("Too many command-line arguments")
|
||||
sys.exit(1)
|
||||
if not os.path.isfile(file_name): # Or try opening and catch FileNotFoundError
|
||||
print(f"The file `{file_name}` does not exist!")
|
||||
sys.exit(1)
|
||||
if not file_name.endswith('.py'):
|
||||
print(f"The file `{file_name}` is not a python script (does not end with the proper suffix)!")
|
||||
sys.exit(1)
|
||||
line_count = count_lines(file_name)
|
||||
print(line_count)
|
||||
|
||||
|
||||
def count_lines(file_name: str) -> int:
|
||||
line_count = 0
|
||||
with open(file_name, 'r') as file_object:
|
||||
for line in file_object:
|
||||
if len(line.strip()) > 0 and not line.strip().startswith('#'):
|
||||
line_count += 1
|
||||
return line_count
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
13
problems/pset6/lines/test_lines.py
Normal file
@ -0,0 +1,13 @@
|
||||
from lines import count_lines
|
||||
|
||||
|
||||
def main():
|
||||
test_count_lines()
|
||||
|
||||
|
||||
def test_count_lines():
|
||||
assert count_lines('lines.py') == 28
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
39
problems/pset6/pizza/pizza.py
Normal file
@ -0,0 +1,39 @@
|
||||
import csv
|
||||
import os
|
||||
import sys
|
||||
|
||||
import tabulate
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
file_name = sys.argv[1]
|
||||
except IndexError:
|
||||
print("Too few command-line arguments")
|
||||
sys.exit(1)
|
||||
if len(sys.argv) > 2:
|
||||
print("Too many command-line arguments")
|
||||
sys.exit(1)
|
||||
if not os.path.isfile(file_name): # Or try opening and catch FileNotFoundError
|
||||
print(f"File does not exist")
|
||||
sys.exit(1)
|
||||
if not file_name.endswith('.csv'):
|
||||
print(f"Not a CSV file")
|
||||
sys.exit(1)
|
||||
grid = get_grid_from_csv(file_name)
|
||||
print(grid)
|
||||
|
||||
|
||||
def get_grid_from_csv(file_name: str) -> str:
|
||||
headers = None
|
||||
table = []
|
||||
with open(file_name, 'r') as file_object:
|
||||
reader = csv.DictReader(file_object)
|
||||
for row in reader:
|
||||
if headers is None:
|
||||
headers = list(row.keys())
|
||||
table.append(tuple(row[field] for field in row))
|
||||
return tabulate.tabulate(table, headers, tablefmt="grid")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
6
problems/pset6/pizza/regular.csv
Normal file
@ -0,0 +1,6 @@
|
||||
Regular Pizza,Small,Large
|
||||
Cheese,$13.50,$18.95
|
||||
1 topping,$14.75,$20.95
|
||||
2 toppings,$15.95,$22.95
|
||||
3 toppings,$16.95,$24.95
|
||||
Special,$18.50,$26.95
|
|
54
problems/pset6/scourgify/after.csv
Normal file
@ -0,0 +1,54 @@
|
||||
first,last,house
|
||||
Hannah,Abbott,Hufflepuff
|
||||
Katie,Bell,Gryffindor
|
||||
Susan,Bones,Hufflepuff
|
||||
Terry,Boot,Ravenclaw
|
||||
Lavender,Brown,Gryffindor
|
||||
Millicent,Bulstrode,Slytherin
|
||||
Cho,Chang,Ravenclaw
|
||||
Penelope,Clearwater,Ravenclaw
|
||||
Vincent,Crabbe,Slytherin
|
||||
Colin,Creevey,Gryffindor
|
||||
Dennis,Creevey,Gryffindor
|
||||
Cedric,Diggory,Hufflepuff
|
||||
Marietta,Edgecombe,Ravenclaw
|
||||
Justin,Finch-Fletchley,Hufflepuff
|
||||
Seamus,Finnigan,Gryffindor
|
||||
Anthony,Goldstein,Ravenclaw
|
||||
Gregory,Goyle,Slytherin
|
||||
Hermione,Granger,Gryffindor
|
||||
Angelina,Johnson,Gryffindor
|
||||
Lee,Jordan,Gryffindor
|
||||
Neville,Longbottom,Gryffindor
|
||||
Luna,Lovegood,Ravenclaw
|
||||
Remus,Lupin,Gryffindor
|
||||
Draco,Malfoy,Slytherin
|
||||
Scorpius,Malfoy,Slytherin
|
||||
Ernie,Macmillan,Hufflepuff
|
||||
Minerva,McGonagall,Gryffindor
|
||||
Eloise,Midgen,Gryffindor
|
||||
Cormac,McLaggen,Gryffindor
|
||||
Graham,Montague,Slytherin
|
||||
Theodore,Nott,Slytherin
|
||||
Pansy,Parkinson,Slytherin
|
||||
Padma,Patil,Gryffindor
|
||||
Parvati,Patil,Gryffindor
|
||||
Harry,Potter,Gryffindor
|
||||
Tom,Riddle,Slytherin
|
||||
Demelza,Robins,Gryffindor
|
||||
Newt,Scamander,Hufflepuff
|
||||
Horace,Slughorn,Slytherin
|
||||
Zacharias,Smith,Hufflepuff
|
||||
Severus,Snape,Slytherin
|
||||
Alicia,Spinnet,Gryffindor
|
||||
Pomona,Sprout,Hufflepuff
|
||||
Dean,Thomas,Gryffindor
|
||||
Romilda,Vane,Gryffindor
|
||||
Myrtle,Warren,Ravenclaw
|
||||
Fred,Weasley,Gryffindor
|
||||
George,Weasley,Gryffindor
|
||||
Ginny,Weasley,Gryffindor
|
||||
Percy,Weasley,Gryffindor
|
||||
Ron,Weasley,Gryffindor
|
||||
Oliver,Wood,Gryffindor
|
||||
Blaise,Zabini,Slytherin
|
|
54
problems/pset6/scourgify/before.csv
Normal file
@ -0,0 +1,54 @@
|
||||
name,house
|
||||
"Abbott, Hannah",Hufflepuff
|
||||
"Bell, Katie",Gryffindor
|
||||
"Bones, Susan",Hufflepuff
|
||||
"Boot, Terry",Ravenclaw
|
||||
"Brown, Lavender",Gryffindor
|
||||
"Bulstrode, Millicent",Slytherin
|
||||
"Chang, Cho",Ravenclaw
|
||||
"Clearwater, Penelope",Ravenclaw
|
||||
"Crabbe, Vincent",Slytherin
|
||||
"Creevey, Colin",Gryffindor
|
||||
"Creevey, Dennis",Gryffindor
|
||||
"Diggory, Cedric",Hufflepuff
|
||||
"Edgecombe, Marietta",Ravenclaw
|
||||
"Finch-Fletchley, Justin",Hufflepuff
|
||||
"Finnigan, Seamus",Gryffindor
|
||||
"Goldstein, Anthony",Ravenclaw
|
||||
"Goyle, Gregory",Slytherin
|
||||
"Granger, Hermione",Gryffindor
|
||||
"Johnson, Angelina",Gryffindor
|
||||
"Jordan, Lee",Gryffindor
|
||||
"Longbottom, Neville",Gryffindor
|
||||
"Lovegood, Luna",Ravenclaw
|
||||
"Lupin, Remus",Gryffindor
|
||||
"Malfoy, Draco",Slytherin
|
||||
"Malfoy, Scorpius",Slytherin
|
||||
"Macmillan, Ernie",Hufflepuff
|
||||
"McGonagall, Minerva",Gryffindor
|
||||
"Midgen, Eloise",Gryffindor
|
||||
"McLaggen, Cormac",Gryffindor
|
||||
"Montague, Graham",Slytherin
|
||||
"Nott, Theodore",Slytherin
|
||||
"Parkinson, Pansy",Slytherin
|
||||
"Patil, Padma",Gryffindor
|
||||
"Patil, Parvati",Gryffindor
|
||||
"Potter, Harry",Gryffindor
|
||||
"Riddle, Tom",Slytherin
|
||||
"Robins, Demelza",Gryffindor
|
||||
"Scamander, Newt",Hufflepuff
|
||||
"Slughorn, Horace",Slytherin
|
||||
"Smith, Zacharias",Hufflepuff
|
||||
"Snape, Severus",Slytherin
|
||||
"Spinnet, Alicia",Gryffindor
|
||||
"Sprout, Pomona",Hufflepuff
|
||||
"Thomas, Dean",Gryffindor
|
||||
"Vane, Romilda",Gryffindor
|
||||
"Warren, Myrtle",Ravenclaw
|
||||
"Weasley, Fred",Gryffindor
|
||||
"Weasley, George",Gryffindor
|
||||
"Weasley, Ginny",Gryffindor
|
||||
"Weasley, Percy",Gryffindor
|
||||
"Weasley, Ron",Gryffindor
|
||||
"Wood, Oliver",Gryffindor
|
||||
"Zabini, Blaise",Slytherin
|
|
7
problems/pset6/scourgify/in.csv
Normal file
@ -0,0 +1,7 @@
|
||||
name,house
|
||||
"Abbott, Hannah",Hufflepuff
|
||||
"Bell, Katie",Gryffindor
|
||||
"Bones, Susan",Hufflepuff
|
||||
"Boot, Terry",Ravenclaw
|
||||
"Brown, Lavender",Gryffindor
|
||||
"Bulstrode, Millicent",Slytherin
|
|
5
problems/pset6/scourgify/out.csv
Normal file
@ -0,0 +1,5 @@
|
||||
first,last,house
|
||||
Susan,Bones,Hufflepuff
|
||||
Terry,Boot,Ravenclaw
|
||||
Lavender,Brown,Gryffindor
|
||||
Millicent,Bulstrode,Slytherin
|
|
42
problems/pset6/scourgify/scourgify.py
Normal file
@ -0,0 +1,42 @@
|
||||
import csv
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
input_file_name, output_file_name = sys.argv[1:3]
|
||||
except IndexError:
|
||||
print("Too few command-line arguments")
|
||||
sys.exit(1)
|
||||
if len(sys.argv) > 3:
|
||||
print("Too many command-line arguments")
|
||||
sys.exit(1)
|
||||
if not os.path.isfile(input_file_name): # Or try opening and catch FileNotFoundError
|
||||
print(f"Could not read {input_file_name}")
|
||||
sys.exit(1)
|
||||
if not input_file_name.endswith('.csv'):
|
||||
print(f"Not a CSV file")
|
||||
sys.exit(1)
|
||||
write_names_to_csv_file(read_names_from_csv_file(input_file_name), output_file_name)
|
||||
|
||||
|
||||
def read_names_from_csv_file(input_file_name):
|
||||
with open(input_file_name, 'r') as input_file:
|
||||
reader = csv.DictReader(input_file)
|
||||
for row in reader:
|
||||
yield row
|
||||
|
||||
|
||||
def write_names_to_csv_file(input_data, output_file_name):
|
||||
with open(output_file_name, 'w') as output_file:
|
||||
writer = csv.DictWriter(output_file, fieldnames=['first', 'last', 'house'])
|
||||
writer.writeheader()
|
||||
for row in input_data:
|
||||
row['last'], row['first'] = row['name'].split(', ')
|
||||
del row['name']
|
||||
writer.writerow(row)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
BIN
problems/pset6/shirt/after1.jpg
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
problems/pset6/shirt/after2.jpg
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
problems/pset6/shirt/after3.jpg
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
problems/pset6/shirt/before1.jpg
Normal file
After Width: | Height: | Size: 980 KiB |
BIN
problems/pset6/shirt/before2.jpg
Normal file
After Width: | Height: | Size: 1.2 MiB |
BIN
problems/pset6/shirt/before3.jpg
Normal file
After Width: | Height: | Size: 1.2 MiB |
BIN
problems/pset6/shirt/shirt.png
Normal file
After Width: | Height: | Size: 64 KiB |
43
problems/pset6/shirt/shirt.py
Normal file
@ -0,0 +1,43 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
import PIL
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
input_file_name, output_file_name = sys.argv[1:3]
|
||||
except (IndexError, ValueError):
|
||||
print("Too few command-line arguments")
|
||||
sys.exit(1)
|
||||
if len(sys.argv) > 3:
|
||||
print("Too many command-line arguments")
|
||||
sys.exit(1)
|
||||
if not os.path.isfile(input_file_name): # Or try opening and catch FileNotFoundError
|
||||
print(f"Input does not exist")
|
||||
sys.exit(1)
|
||||
if not (any(input_file_name.lower().endswith(format) for format in (".jpg", ".jpeg", ".png")) and any(output_file_name.lower().endswith(format) for format in (".jpg", ".jpeg", ".png"))):
|
||||
print(f"Invalid input")
|
||||
sys.exit(1)
|
||||
if (input_file_name[-4] == '.' and input_file_name[-4:] != output_file_name[-4:]) or (input_file_name[-3] == '.' and input_file_name[-3:] != output_file_name[-3:]):
|
||||
print(f"Input and output have different extensions")
|
||||
sys.exit(1)
|
||||
overlap_t_shirt(input_file_name, output_file_name)
|
||||
"""Open the input with Image.open, per pillow.
|
||||
resize and crop the input with ImageOps.fit, per pillow.readthedocs.io/en/stable/reference/ImageOps.html#PIL.ImageOps.fit,
|
||||
using default values for method, bleed, and centering, overlay the shirt with Image.paste,
|
||||
per pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.paste,
|
||||
and save the result with Image.save, per pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.save."""
|
||||
|
||||
|
||||
def overlap_t_shirt(input_file_name, output_file_name):
|
||||
image = Image.open(input_file_name)
|
||||
shirt = Image.open('shirt.png')
|
||||
image = PIL.ImageOps.fit(image, size=shirt.size)
|
||||
image.paste(shirt, mask=shirt)
|
||||
image.save(output_file_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
19
problems/pset7/numb3rs/numb3rs.py
Normal file
@ -0,0 +1,19 @@
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
print(validate(input("IPv4 Address: ")))
|
||||
|
||||
|
||||
def validate(ip):
|
||||
if not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip):
|
||||
return False
|
||||
for n in map(int, ip.split('.')):
|
||||
if not 0 <= n <= 255:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
32
problems/pset7/numb3rs/test_numb3rs.py
Normal file
@ -0,0 +1,32 @@
|
||||
from numb3rs import validate
|
||||
|
||||
|
||||
def main():
|
||||
test_non_digits()
|
||||
test_negative_numbers()
|
||||
test_numbers_too_big()
|
||||
test_numbers_too_long()
|
||||
|
||||
|
||||
def test_non_digits():
|
||||
assert validate('aaa.bbb.ccc.ddd') == False
|
||||
assert validate('cat') == False
|
||||
|
||||
|
||||
def test_negative_numbers():
|
||||
assert validate('-11.111.-1.-1') == False
|
||||
|
||||
|
||||
def test_numbers_too_big():
|
||||
assert validate('257.200.1.1') == False
|
||||
assert validate('200.257.1.1') == False
|
||||
assert validate('200.1.257.1') == False
|
||||
assert validate('200.1.5.257') == False
|
||||
|
||||
|
||||
def test_numbers_too_long():
|
||||
assert validate('200.1.5.2.57') == False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
23
problems/pset7/response/response.py
Normal file
@ -0,0 +1,23 @@
|
||||
from validator_collection import validators
|
||||
|
||||
|
||||
def main():
|
||||
if validate_email(input("What's your email address?\t\t")):
|
||||
print("Valid")
|
||||
else:
|
||||
print("Invalid")
|
||||
|
||||
|
||||
def validate_email(email: str) -> bool:
|
||||
try:
|
||||
email_address = validators.email(email, allow_empty = True)
|
||||
except Exception as e:
|
||||
email_address = None
|
||||
if not email_address:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
16
problems/pset7/response/test_response.py
Normal file
@ -0,0 +1,16 @@
|
||||
from response import validate_email
|
||||
|
||||
|
||||
def main():
|
||||
test_cs50p()
|
||||
|
||||
|
||||
def test_cs50p():
|
||||
assert validate_email("malan@harvard.edu")== True
|
||||
assert validate_email("info@cheznadi.com")== True
|
||||
assert validate_email("malan@@@harvard.edu")== False
|
||||
assert validate_email("info@cheznadi..com")== False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
37
problems/pset7/um/test_um.py
Normal file
@ -0,0 +1,37 @@
|
||||
from um import count
|
||||
|
||||
def main():
|
||||
test_count_ums()
|
||||
test_words_containing_ums()
|
||||
test_punctuation()
|
||||
test_from_cs50p()
|
||||
|
||||
|
||||
def test_count_ums():
|
||||
assert count("Hello, um, world") == 1
|
||||
assert count("Hello um, um, world um") == 3
|
||||
assert count("Um Hello, um, world um") == 3
|
||||
|
||||
|
||||
def test_words_containing_ums():
|
||||
assert count("instrumentation") == 0
|
||||
assert count("umbrella") == 0
|
||||
assert count("momentum") == 0
|
||||
|
||||
|
||||
def test_punctuation():
|
||||
assert count("Hello um?") == 1
|
||||
assert count("Hello um!") == 1
|
||||
assert count("Hello um") == 1
|
||||
assert count("Hello um.") == 1
|
||||
|
||||
|
||||
def test_from_cs50p():
|
||||
assert count("um") == 1
|
||||
assert count("um?") == 1
|
||||
assert count("Um, thanks for the album.") == 1
|
||||
assert count("Um, thanks, um...") == 2
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
15
problems/pset7/um/um.py
Normal file
@ -0,0 +1,15 @@
|
||||
import re
|
||||
|
||||
um_regex = re.compile(r"\bum\b", re.IGNORECASE)
|
||||
|
||||
|
||||
def main():
|
||||
print(count(input("Text: ")))
|
||||
|
||||
|
||||
def count(s):
|
||||
return len(um_regex.findall(s))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
20
problems/pset7/watch/watch.py
Normal file
@ -0,0 +1,20 @@
|
||||
import re
|
||||
|
||||
youtube_regex = re.compile(r"<iframe.*https?://(?:www\.)?youtube\.com/embed/(\w+).*</iframe>")
|
||||
|
||||
|
||||
def main():
|
||||
print(parse(input("HTML: ")))
|
||||
|
||||
|
||||
def parse(s):
|
||||
video_id = youtube_regex.search(s)
|
||||
if video_id:
|
||||
video_id = video_id.groups()[0]
|
||||
else:
|
||||
return None
|
||||
return f"https://youtu.be/{video_id}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
102
problems/pset7/working/test_working.py
Normal file
@ -0,0 +1,102 @@
|
||||
import pytest
|
||||
|
||||
from working import convert
|
||||
|
||||
|
||||
def main():
|
||||
test_missing_to()
|
||||
test_out_of_range_times()
|
||||
test_exception()
|
||||
test_hours_off_by_one()
|
||||
|
||||
|
||||
def test_missing_to():
|
||||
try:
|
||||
convert('09:00 AM - 05:00 PM')
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
raise ValueError("Missing to")
|
||||
try:
|
||||
convert('09:00 AM 05:00 PM')
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
|
||||
|
||||
def test_out_of_range_times():
|
||||
try:
|
||||
convert('09:00 AM to 05:61 PM')
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
convert('31:00 AM to 05:00 PM')
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
convert('13:00 PM to 8:00 AM')
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
convert('13:00PM to 8:00 AM')
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
convert('13:00 to 8:00')
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
convert("09:00 AM - 17:00 PM")
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
convert("9:00 AM 5:00 PM")
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
convert("9:60 AM to 5:60 PM")
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
convert("9 AM - 5 PM")
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
convert("9 AM5 PM")
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
convert("9 AM 5 PM")
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
with pytest.raises(ValueError):
|
||||
convert("9:72 to 6:30")
|
||||
|
||||
|
||||
def test_exception():
|
||||
with pytest.raises(ValueError):
|
||||
convert("09:00 AM - 17:00 PM")
|
||||
with pytest.raises(ValueError):
|
||||
convert("9:00 AM 5:00 PM")
|
||||
with pytest.raises(ValueError):
|
||||
convert("9:60 AM to 5:60 PM")
|
||||
with pytest.raises(ValueError):
|
||||
convert("9 AM - 5 PM")
|
||||
with pytest.raises(ValueError):
|
||||
convert("9 AM5 PM")
|
||||
with pytest.raises(ValueError):
|
||||
convert("9 AM 5 PM")
|
||||
with pytest.raises(ValueError):
|
||||
convert("9:72 to 6:30")
|
||||
|
||||
|
||||
def test_hours_off_by_one():
|
||||
assert convert('12:00 AM to 12:00 PM') == "00:00 to 12:00"
|
||||
assert convert("9 AM to 5 PM") == "09:00 to 17:00"
|
||||
assert convert("8 PM to 8 AM") == "20:00 to 08:00"
|
||||
assert convert("8:00 PM to 8:00 AM") == "20:00 to 08:00"
|
||||
assert convert("12 AM to 12 PM") == "00:00 to 12:00"
|
||||
assert convert("12:00 AM to 12:00 PM") == "00:00 to 12:00"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
39
problems/pset7/working/working.py
Normal file
@ -0,0 +1,39 @@
|
||||
import re
|
||||
|
||||
|
||||
american_time_regex = re.compile(r"^\s*(\d+)(?:\:(\d{2}))? ([AP])M to (\d+)(?:\:(\d{2}))? ([AP])\s*M$")
|
||||
|
||||
|
||||
def main():
|
||||
print(convert(input("Hours: ")))
|
||||
|
||||
|
||||
def convert(s):
|
||||
time = american_time_regex.match(s)
|
||||
if time is None:
|
||||
raise ValueError("Invalid input time")
|
||||
if len(time.groups()) == 4:
|
||||
start_h, start_ampm, end_h, end_ampm = time.groups()
|
||||
start_m, end_m = 0, 0
|
||||
else:
|
||||
start_h, start_m, start_ampm, end_h, end_m, end_ampm = time.groups()
|
||||
start_m, end_m = map(lambda x: int(x) if x else 0, (start_m, end_m))
|
||||
start_h, end_h = map(int, (start_h, end_h))
|
||||
if start_h > 12 or end_h > 12:
|
||||
raise ValueError
|
||||
if (start_ampm == 'P' and start_h != 12) or (start_ampm == 'A' and start_h == 12):
|
||||
start_h += 12
|
||||
if (end_ampm == 'P' and end_h != 12) or (end_ampm == 'A' and end_h == 12):
|
||||
end_h += 12
|
||||
if start_h > 24 or end_h > 24 or start_m > 59 or end_m > 59:
|
||||
raise ValueError
|
||||
start_h = start_h % 24
|
||||
end_h = end_h % 24
|
||||
return f"{start_h:0>2}:{start_m:0>2} to {end_h:0>2}:{end_m:0>2}"
|
||||
|
||||
|
||||
...
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
26
problems/pset8/jar/jar.py
Normal file
@ -0,0 +1,26 @@
|
||||
class Jar:
|
||||
def __init__(self, capacity=12):
|
||||
if not isinstance(capacity, int) or capacity < 0:
|
||||
raise ValueError("Invalid capacity")
|
||||
self._capacity = capacity
|
||||
self._size = 0
|
||||
|
||||
def __str__(self):
|
||||
return '🍪' * self.size
|
||||
|
||||
def deposit(self, n):
|
||||
new_size = n + self.size
|
||||
if new_size > self.capacity or new_size < 0:
|
||||
raise ValueError("Exceeded capacity")
|
||||
self._size += n
|
||||
|
||||
def withdraw(self, n):
|
||||
return self.deposit(-n)
|
||||
|
||||
@property
|
||||
def capacity(self):
|
||||
return self._capacity
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return self._size
|
46
problems/pset8/jar/test_jar.py
Normal file
@ -0,0 +1,46 @@
|
||||
from jar import Jar
|
||||
|
||||
|
||||
def main():
|
||||
test_capacity()
|
||||
test_size()
|
||||
test_deposit()
|
||||
test_withdraw()
|
||||
|
||||
|
||||
def test_capacity():
|
||||
j = Jar(capacity=3)
|
||||
assert j.capacity == 3
|
||||
|
||||
|
||||
def test_size():
|
||||
j = Jar(capacity=5)
|
||||
assert j.size == 0
|
||||
j.deposit(3)
|
||||
j.withdraw(1)
|
||||
assert j.size == 2
|
||||
|
||||
|
||||
def test_deposit():
|
||||
j = Jar(capacity=5)
|
||||
j.deposit(3)
|
||||
try:
|
||||
j.deposit(3)
|
||||
raise Exception("Deposit n > capacity did not raise ValueError")
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
|
||||
|
||||
def test_withdraw():
|
||||
j = Jar(capacity=5)
|
||||
j.deposit(3)
|
||||
j.withdraw(2)
|
||||
try:
|
||||
j.withdraw(2)
|
||||
raise Exception("Withdraw n > size did not raise ValueError")
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
39
problems/pset8/seasons/seasons.py
Normal file
@ -0,0 +1,39 @@
|
||||
import datetime
|
||||
import re
|
||||
import sys
|
||||
|
||||
import inflect
|
||||
|
||||
date_regex = re.compile(r"\d{4}-\d{2}-\d{2}")
|
||||
p = inflect.engine()
|
||||
|
||||
|
||||
def main():
|
||||
today = datetime.date.today()
|
||||
users_date = input("Date of Birth: ")
|
||||
try:
|
||||
users_date = parse_date(users_date)
|
||||
except ValueError:
|
||||
sys.exit(1)
|
||||
minutes = get_minutes(users_date, today)
|
||||
print(format_minutes(minutes))
|
||||
|
||||
|
||||
def get_minutes(start_date, end_date):
|
||||
minutes = (end_date - start_date).total_seconds() / 60
|
||||
return int(round(minutes, 0))
|
||||
|
||||
|
||||
def format_minutes(minutes: int) -> str:
|
||||
stringed_number = p.number_to_words(minutes, andword="").capitalize()
|
||||
return f"{stringed_number} minute{'s' if minutes > 1 else ''}"
|
||||
|
||||
|
||||
def parse_date(date_string):
|
||||
if not date_regex.match(date_string): # Acutally not necessary: strptime would raise ValueError anyway
|
||||
raise ValueError
|
||||
return datetime.datetime.strptime(date_string, '%Y-%m-%d').date()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
44
problems/pset8/seasons/test_seasons.py
Normal file
@ -0,0 +1,44 @@
|
||||
from seasons import format_minutes, parse_date
|
||||
|
||||
|
||||
def main():
|
||||
test_format_minutes()
|
||||
test_invalid_dates()
|
||||
test_known_intervals()
|
||||
|
||||
|
||||
def test_format_minutes():
|
||||
assert format_minutes(1) == 'One minute'
|
||||
assert format_minutes(2) == 'Two minutes'
|
||||
|
||||
|
||||
def test_invalid_dates():
|
||||
try:
|
||||
parse_date('91-5-9')
|
||||
raise Exception
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
parse_date('cacao')
|
||||
raise Exception
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
parse_date('1991-13-09')
|
||||
raise Exception
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
try:
|
||||
parse_date('1991-11-40')
|
||||
raise Exception
|
||||
except Exception as e:
|
||||
assert isinstance(e, ValueError)
|
||||
|
||||
|
||||
def test_known_intervals():
|
||||
assert format_minutes(525600) == "Five hundred twenty-five thousand, six hundred minutes"
|
||||
assert format_minutes(1051200) == "One million, fifty-one thousand, two hundred minutes"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
BIN
problems/pset8/shirtificate/shirtificate.pdf
Normal file
BIN
problems/pset8/shirtificate/shirtificate.png
Normal file
After Width: | Height: | Size: 60 KiB |
22
problems/pset8/shirtificate/shirtificate.py
Normal file
@ -0,0 +1,22 @@
|
||||
from fpdf import FPDF
|
||||
|
||||
|
||||
def main():
|
||||
username = input("What's your name?\t\t")
|
||||
pdf = FPDF(orientation="P", unit="mm", format="A4")
|
||||
pdf.set_auto_page_break(False)
|
||||
pdf.add_page()
|
||||
pdf.set_font("helvetica", "B", 45)
|
||||
pdf.cell(0, 10, 'CS50 Shirtificate', new_x="LMARGIN", new_y="NEXT", align='C')
|
||||
page_width = pdf.w
|
||||
total_horizontal_margin = 0.2 * page_width
|
||||
image_width = pdf.w-total_horizontal_margin
|
||||
pdf.image("shirtificate.png", x=total_horizontal_margin/2, y=50, w=image_width)
|
||||
pdf.set_font("helvetica", "B", 32)
|
||||
pdf.set_text_color(255, 255, 255)
|
||||
pdf.cell(0, 230, f'{username} took CS50', new_x="LMARGIN", new_y="NEXT", align='C')
|
||||
pdf.output("shirtificate.pdf")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|