├── LICENSE ├── README.md ├── Week0 ├── einstein.py ├── faces.py ├── indoor.py ├── playback.py └── tip.py ├── Week1 ├── bank.py ├── deep.py ├── extensions.py ├── interpreter.py └── meal.py ├── Week2 ├── camel.py ├── coke.py ├── nutrition.py ├── plates.py └── twttr.py ├── Week3 ├── fuel.py ├── grocery.py ├── outdated.py └── taqueria.py ├── Week4 ├── adieu.py ├── bitcoin.py ├── emojize.py ├── figlet.py ├── game.py └── professor.py ├── Week5 ├── test_bank │ ├── bank.py │ └── test_bank.py ├── test_fuel │ ├── fuel.py │ └── test_fuel.py ├── test_plates │ ├── plates.py │ └── test_plates.py └── test_twttr │ ├── test_twttr.py │ └── twttr.py ├── Week6 ├── lines │ └── lines.py ├── pizza │ ├── pizza.py │ └── test.csv ├── scourgify │ ├── before.csv │ └── scourgify.py └── shirt │ ├── before1.jpg │ ├── before2.jpg │ ├── before3.jpg │ ├── muppets.zip │ ├── shirt.png │ └── shirt.py ├── Week7 ├── numb3rs │ ├── numb3rs.py │ └── test_numb3rs.py ├── response │ └── response.py ├── um │ ├── test_um.py │ └── um.py ├── watch │ └── wath.py └── working │ ├── test_working.py │ └── working.py ├── Week8 ├── jar │ ├── jar.py │ └── test_jar.py ├── seasons │ ├── seasons.py │ └── test_seasons.py └── shritificate │ ├── shirtificate.pdf │ ├── shirtificate.png │ └── shirtificate.py └── Week9 ├── README.md ├── project.py └── test_project.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 CS Five 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Harvard CS50 Python 2022 2 | 3 | - [Course Link](https://cs50.harvard.edu/python) 4 | -------------------------------------------------------------------------------- /Week0/einstein.py: -------------------------------------------------------------------------------- 1 | def compute(m, c=300000000): 2 | return m * c * c 3 | 4 | 5 | print("E:", compute(int(input("m: ")))) 6 | -------------------------------------------------------------------------------- /Week0/faces.py: -------------------------------------------------------------------------------- 1 | def convert(text): 2 | return text.replace(":)", "🙂").replace(":(", "🙁") 3 | 4 | 5 | def main(): 6 | print(convert(input())) 7 | 8 | 9 | if __name__ == "__main__": 10 | main() 11 | 12 | # or just one line 13 | # print(input().replace(":)", "🙂").replace(":(", "🙁")) 14 | -------------------------------------------------------------------------------- /Week0/indoor.py: -------------------------------------------------------------------------------- 1 | print(input().lower()) 2 | -------------------------------------------------------------------------------- /Week0/playback.py: -------------------------------------------------------------------------------- 1 | print("...".join(input().split())) 2 | -------------------------------------------------------------------------------- /Week0/tip.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | dollars = dollars_to_float(input("How much was the meal? ")) 3 | percent = percent_to_float(input("What percentage would you like to tip? ")) 4 | tip = dollars * percent 5 | print(f"Leave ${tip:.2f}") 6 | 7 | 8 | def dollars_to_float(d): 9 | return float(d[1:]) 10 | 11 | 12 | def percent_to_float(p): 13 | return float(p[:-1]) / 100 14 | 15 | 16 | if __name__ == "__main__": 17 | main() 18 | -------------------------------------------------------------------------------- /Week1/bank.py: -------------------------------------------------------------------------------- 1 | s = input("Greeting: ").strip().lower() 2 | 3 | if s.startswith("hello"): 4 | print("$0") 5 | elif s.startswith("h"): 6 | print("$20") 7 | else: 8 | print("$100") 9 | -------------------------------------------------------------------------------- /Week1/deep.py: -------------------------------------------------------------------------------- 1 | s = ( 2 | input( 3 | "What is the Answer to the Great Question of Life, the Universe, and Everything? " 4 | ) 5 | .strip() 6 | .lower() 7 | ) 8 | 9 | if s in ["42", "forty two", "forty-two"]: 10 | print("Yes") 11 | else: 12 | print("No") 13 | -------------------------------------------------------------------------------- /Week1/extensions.py: -------------------------------------------------------------------------------- 1 | types = { 2 | "gif": "image/gif", 3 | "jpg": "image/jpeg", 4 | "jpeg": "image/jpeg", 5 | "png": "image/png", 6 | "pdf": "application/pdf", 7 | "txt": "text/plain", 8 | "zip": "application/zip", 9 | } 10 | 11 | s = input("File name: ").strip().lower().split(".")[-1] 12 | print(types.get(s, "application/octet-stream")) 13 | -------------------------------------------------------------------------------- /Week1/interpreter.py: -------------------------------------------------------------------------------- 1 | x, y, z = input("Expression: ").split() 2 | 3 | x, z = int(x), int(z) 4 | ans = eval(f"{x} {y} {z}") 5 | 6 | print(f"{ans:.1f}") 7 | -------------------------------------------------------------------------------- /Week1/meal.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | time = convert(input("What time is it? ").strip()) 3 | if 7 <= time <= 8: 4 | print("Breakfast time") 5 | elif 12 <= time <= 13: 6 | print("Lunch time") 7 | elif 18 <= time <= 19: 8 | print("Dinner time") 9 | 10 | 11 | def convert(time): 12 | hours, minutes = map(int, time.replace("a.m.", "").replace("p.m.", "").split(":")) 13 | if "p.m." in time and hours != 12: 14 | hours += 12 15 | if "a.m." in time and hours == 12: 16 | hours = 0 17 | return hours + minutes / 60 18 | 19 | 20 | if __name__ == "__main__": 21 | main() 22 | -------------------------------------------------------------------------------- /Week2/camel.py: -------------------------------------------------------------------------------- 1 | camel = input("camelCase: ").strip() 2 | 3 | snake = "".join(["_" + ch.lower() if ch.isupper() else ch for ch in camel]) 4 | print("snake_case:", snake) 5 | -------------------------------------------------------------------------------- /Week2/coke.py: -------------------------------------------------------------------------------- 1 | due, inserted = 50, 0 2 | while inserted < due: 3 | print("Amount Due:", due - inserted) 4 | coin = int(input("Insert Coin: ")) 5 | if coin in [5, 10, 25]: 6 | inserted += coin 7 | print("Change Owed:", inserted - due) 8 | -------------------------------------------------------------------------------- /Week2/nutrition.py: -------------------------------------------------------------------------------- 1 | fruits = { 2 | "apple": 130, 3 | "avocado": 50, 4 | "banana": 110, 5 | "cantaloupe": 50, 6 | "grapefruit": 60, 7 | "grapes": 90, 8 | "honeydew melon": 50, 9 | "kiwifruit": 90, 10 | "lemon": 15, 11 | "lime": 20, 12 | "nectarine": 60, 13 | "orange": 80, 14 | "peach": 60, 15 | "pear": 100, 16 | "pineapple": 50, 17 | "plums": 70, 18 | "strawberries": 50, 19 | "sweet cherries": 100, 20 | "tangerine": 50, 21 | "watermelon": 80, 22 | } 23 | 24 | s = input("Item: ").lower() 25 | if s in fruits: 26 | print("Calories:", fruits[s]) 27 | -------------------------------------------------------------------------------- /Week2/plates.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | plate = input("Plate: ") 3 | if is_valid(plate): 4 | print("Valid") 5 | else: 6 | print("Invalid") 7 | 8 | 9 | def is_valid(s): 10 | if len(s) < 2 or len(s) > 6: 11 | return False 12 | if not s[0].isalpha() or not s[1].isalpha(): 13 | return False 14 | if not all(ch.isalnum() for ch in s): 15 | return False 16 | 17 | flag = False 18 | for ch in s: 19 | if ch.isdigit(): 20 | flag = True 21 | if ch.isalpha() and flag: 22 | return False 23 | 24 | for ch in s: 25 | if ch.isdigit(): 26 | return ch != "0" 27 | 28 | return True 29 | 30 | 31 | if __name__ == "__main__": 32 | main() 33 | -------------------------------------------------------------------------------- /Week2/twttr.py: -------------------------------------------------------------------------------- 1 | s = input("Input: ") 2 | 3 | ans = "".join([ch for ch in s if ch.lower() not in "aeiou"]) 4 | print("Output:", ans) 5 | -------------------------------------------------------------------------------- /Week3/fuel.py: -------------------------------------------------------------------------------- 1 | while True: 2 | try: 3 | x, y = map(int, input("Fraction: ").split("/")) 4 | if y == 0: 5 | raise ZeroDivisionError 6 | if x > y: 7 | raise ValueError 8 | break 9 | except (ValueError, ZeroDivisionError): 10 | pass 11 | 12 | percentage = round(x / y * 100) 13 | if percentage <= 1: 14 | print("E") 15 | elif percentage >= 99: 16 | print("F") 17 | else: 18 | print(f"{percentage}%") 19 | -------------------------------------------------------------------------------- /Week3/grocery.py: -------------------------------------------------------------------------------- 1 | list = {} 2 | while True: 3 | try: 4 | item = input("").upper() 5 | except EOFError: 6 | print() 7 | break 8 | 9 | if item in list: 10 | list[item] += 1 11 | else: 12 | list[item] = 1 13 | 14 | for item, cnt in sorted(list.items()): 15 | print(f"{cnt} {item}") 16 | -------------------------------------------------------------------------------- /Week3/outdated.py: -------------------------------------------------------------------------------- 1 | months = [ 2 | "January", 3 | "February", 4 | "March", 5 | "April", 6 | "May", 7 | "June", 8 | "July", 9 | "August", 10 | "September", 11 | "October", 12 | "November", 13 | "December", 14 | ] 15 | 16 | 17 | while True: 18 | date = input("Date: ") 19 | if len(date.split("/")) == 3: 20 | date = date.split("/") 21 | try: 22 | month, day, year = map(int, date) 23 | if 1 <= month <= 12 and 1 <= day <= 31: 24 | print(f"{year:04d}-{month:02d}-{day:02d}") 25 | break 26 | except ValueError: 27 | pass 28 | else: 29 | date = date.split(",") 30 | if len(date) == 2: 31 | try: 32 | month, day = date[0].split() 33 | month = months.index(month) + 1 34 | day, year = int(day), int(date[1]) 35 | if 1 <= month <= 12 and 1 <= day <= 31: 36 | print(f"{year:04d}-{month:02d}-{day:02d}") 37 | break 38 | except ValueError: 39 | pass 40 | -------------------------------------------------------------------------------- /Week3/taqueria.py: -------------------------------------------------------------------------------- 1 | menu = { 2 | "Baja Taco": 4.00, 3 | "Burrito": 7.50, 4 | "Bowl": 8.50, 5 | "Nachos": 11.00, 6 | "Quesadilla": 8.50, 7 | "Super Burrito": 8.50, 8 | "Super Quesadilla": 9.50, 9 | "Taco": 3.00, 10 | "Tortilla Salad": 8.00, 11 | } 12 | 13 | total = 0 14 | while True: 15 | try: 16 | item = input("Item: ").title() 17 | if item in menu: 18 | total += menu[item] 19 | print(f"Total: ${total:.2f}") 20 | except EOFError: 21 | print() 22 | break 23 | -------------------------------------------------------------------------------- /Week4/adieu.py: -------------------------------------------------------------------------------- 1 | import inflect 2 | 3 | p = inflect.engine() 4 | names = [] 5 | while True: 6 | try: 7 | names.append(input("Name: ").strip()) 8 | except EOFError: 9 | print() 10 | break 11 | 12 | print(f"Adieu, adieu, to {p.join(names)}") 13 | -------------------------------------------------------------------------------- /Week4/bitcoin.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import requests 3 | 4 | try: 5 | response = requests.get("https://api.coindesk.com/v1/bpi/currentprice.json") 6 | data = response.json() 7 | current_price = data["bpi"]["USD"]["rate_float"] 8 | except requests.RequestException: 9 | sys.exit() 10 | 11 | 12 | try: 13 | n = float(sys.argv[1]) 14 | except IndexError: 15 | sys.exit("Missing command-line argument") 16 | except ValueError: 17 | sys.exit("Command-line argument is not a number") 18 | print(f"${n * current_price:,.4f}") 19 | -------------------------------------------------------------------------------- /Week4/emojize.py: -------------------------------------------------------------------------------- 1 | from emoji import emojize 2 | 3 | print("Output:", emojize(input("Input: "), language="alias")) 4 | -------------------------------------------------------------------------------- /Week4/figlet.py: -------------------------------------------------------------------------------- 1 | from pyfiglet import Figlet 2 | import random 3 | 4 | fonts = Figlet().getFonts() 5 | if len(sys.argv) == 1: 6 | font = random.choice(fonts) 7 | elif len(sys.argv) == 3: 8 | if sys.argv[1] in ["-f", "--font"] and sys.argv[2] in fonts: 9 | font = sys.argv[2] 10 | else: 11 | sys.exit("Invalid arguments.") 12 | else: 13 | sys.exit("Invalid number of arguments.") 14 | 15 | text = input("Input: ") 16 | print("Output:\n", Figlet(font=font).renderText(text)) 17 | -------------------------------------------------------------------------------- /Week4/game.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | 3 | while True: 4 | try: 5 | n = int(input("Level: ")) 6 | if n <= 0: 7 | raise ValueError 8 | break 9 | except ValueError: 10 | pass 11 | 12 | rand = randint(1, n) 13 | while True: 14 | try: 15 | guess = int(input("Guess: ")) 16 | if guess < rand: 17 | print("Too small!") 18 | elif guess > rand: 19 | print("Too large!") 20 | else: 21 | print("Just right") 22 | break 23 | except ValueError: 24 | pass 25 | -------------------------------------------------------------------------------- /Week4/professor.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | 3 | 4 | def main(): 5 | level = get_level() 6 | score = 0 7 | for _ in range(10): 8 | x = generate_integer(level) 9 | y = generate_integer(level) 10 | score += check_answer(x, y) 11 | print("Score:", score) 12 | 13 | 14 | def get_level(): 15 | while True: 16 | try: 17 | level = int(input("Level: ")) 18 | if level in [1, 2, 3]: 19 | return level 20 | except ValueError: 21 | pass 22 | 23 | 24 | def generate_integer(level): 25 | if level == 1: 26 | return randint(0, 9) 27 | return randint(10 ** (level - 1), 10**level - 1) 28 | 29 | 30 | def check_answer(x, y): 31 | tries = 0 32 | while tries < 3: 33 | try: 34 | tries += 1 35 | answer = int(input(f"{x} + {y} = ")) 36 | if answer == x + y: 37 | return 1 38 | else: 39 | print("EEE") 40 | except ValueError: 41 | pass 42 | print(f"{x} + {y} = {x + y}") 43 | return 0 44 | 45 | 46 | if __name__ == "__main__": 47 | main() 48 | -------------------------------------------------------------------------------- /Week5/test_bank/bank.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | s = input("Greeting: ") 3 | print(f"${value(s)}") 4 | 5 | 6 | def value(greeting): 7 | greeting = greeting.strip().lower() 8 | if greeting.startswith("hello"): 9 | return 0 10 | elif greeting.startswith("h"): 11 | return 20 12 | else: 13 | return 100 14 | 15 | 16 | if __name__ == "__main__": 17 | main() 18 | -------------------------------------------------------------------------------- /Week5/test_bank/test_bank.py: -------------------------------------------------------------------------------- 1 | from bank import value 2 | 3 | 4 | def test_value(): 5 | assert value("Hello") == 0 6 | assert value(" Hello ") == 0 7 | assert value("Hello, Newman") == 0 8 | assert value("How you doing?") == 20 9 | assert value("What's happening?") == 100 10 | assert value("What's up?") == 100 11 | -------------------------------------------------------------------------------- /Week5/test_fuel/fuel.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | print(gauge(convert(input("Fraction: ")))) 3 | 4 | 5 | def convert(fraction): 6 | while True: 7 | try: 8 | x, y = map(int, fraction.split("/")) 9 | if y == 0: 10 | raise ZeroDivisionError 11 | if x > y: 12 | raise ValueError 13 | return round(x / y * 100) 14 | except (ValueError, ZeroDivisionError): 15 | pass 16 | 17 | 18 | def gauge(percentage): 19 | if percentage <= 1: 20 | return "E" 21 | elif percentage >= 99: 22 | return "F" 23 | else: 24 | return f"{percentage}%" 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /Week5/test_fuel/test_fuel.py: -------------------------------------------------------------------------------- 1 | from fuel import convert, gauge 2 | import pytest 3 | 4 | 5 | def test_convert(): 6 | assert convert("3/4") == 75 7 | assert convert("1/3") == 33 8 | assert convert("2/3") == 67 9 | assert convert("0/100") == 0 10 | assert convert("100/100") == 100 11 | assert convert("99/100") == 99 12 | 13 | with pytest.raises(ValueError): 14 | convert("x/y") 15 | 16 | with pytest.raises(ValueError): 17 | convert("three/four") 18 | 19 | with pytest.raises(ValueError): 20 | convert("10/3") 21 | 22 | with pytest.raises(ValueError): 23 | convert("1.5/4") 24 | 25 | with pytest.raises(ValueError): 26 | convert("5-4") 27 | 28 | with pytest.raises(ZeroDivisionError): 29 | convert("1/0") 30 | 31 | 32 | def test_gauge(): 33 | assert gauge(0) == "E" 34 | assert gauge(1) == "E" 35 | assert gauge(100) == "F" 36 | assert gauge(99) == "F" 37 | assert gauge(2) == "2%" 38 | assert gauge(40) == "40%" 39 | assert gauge(98) == "98%" 40 | -------------------------------------------------------------------------------- /Week5/test_plates/plates.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | plate = input("Plate: ") 3 | if is_valid(plate): 4 | print("Valid") 5 | else: 6 | print("Invalid") 7 | 8 | 9 | def is_valid(s): 10 | if len(s) < 2 or len(s) > 6: 11 | return False 12 | if not s[0].isalpha() or not s[1].isalpha(): 13 | return False 14 | if not all(ch.isalnum() for ch in s): 15 | return False 16 | 17 | flag = False 18 | for ch in s: 19 | if ch.isdigit(): 20 | flag = True 21 | if ch.isalpha() and flag: 22 | return False 23 | 24 | for ch in s: 25 | if ch.isdigit(): 26 | return ch != "0" 27 | 28 | return True 29 | 30 | 31 | if __name__ == "__main__": 32 | main() 33 | -------------------------------------------------------------------------------- /Week5/test_plates/test_plates.py: -------------------------------------------------------------------------------- 1 | from plates import is_valid 2 | 3 | def test_is_valid(): 4 | assert is_valid("CS50") == True 5 | assert is_valid("ECTO88") == True 6 | assert is_valid("NRVOUS") == True 7 | assert is_valid("CS05") == False 8 | assert is_valid("CS50P2") == False 9 | assert is_valid("123456") == False 10 | assert is_valid("PI3.14") == False 11 | assert is_valid("H") == False 12 | assert is_valid("OUTATIME") == False 13 | assert is_valid("ABC?!-") == False 14 | -------------------------------------------------------------------------------- /Week5/test_twttr/test_twttr.py: -------------------------------------------------------------------------------- 1 | from twttr import shorten 2 | 3 | 4 | def test_shorten(): 5 | assert shorten("aeiou") == "" 6 | assert shorten("AEIOU") == "" 7 | assert shorten("twitter") == "twttr" 8 | assert shorten("tWitTer") == "tWtTr" 9 | assert shorten("What's your name?") == "Wht's yr nm?" 10 | assert shorten("1a2be") == "12b" 11 | -------------------------------------------------------------------------------- /Week5/test_twttr/twttr.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | print("Output:", shorten(input("Input: "))) 3 | 4 | 5 | def shorten(word): 6 | return "".join([ch for ch in word if ch.lower() not in "aeiou"]) 7 | 8 | 9 | if __name__ == "__main__": 10 | main() 11 | -------------------------------------------------------------------------------- /Week6/lines/lines.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | if len(sys.argv) != 2 or not sys.argv[1].endswith(".py"): 4 | sys.exit("Invalid arguments.") 5 | 6 | try: 7 | with open(sys.argv[1]) as file: 8 | print( 9 | sum( 10 | 1 for line in file if line.strip() and not line.lstrip().startswith("#") 11 | ) 12 | ) 13 | except FileNotFoundError: 14 | sys.exit("File does not exist.") 15 | -------------------------------------------------------------------------------- /Week6/pizza/pizza.py: -------------------------------------------------------------------------------- 1 | from tabulate import tabulate 2 | import csv 3 | import sys 4 | 5 | if len(sys.argv) != 2 or not sys.argv[1].endswith(".csv"): 6 | sys.exit("Invalid arguments.") 7 | 8 | try: 9 | with open(sys.argv[1]) as file: 10 | print(tabulate(csv.DictReader(file), headers="keys", tablefmt="grid")) 11 | except FileNotFoundError: 12 | sys.exit("File does not exist.") 13 | -------------------------------------------------------------------------------- /Week6/pizza/test.csv: -------------------------------------------------------------------------------- 1 | Regular Pizza,Small,Large 2 | Cheese,$13.50,$18.95 3 | 1 topping,$14.75,$20.95 4 | 2 toppings,$15.95,$22.95 5 | 3 toppings,$16.95,$24.95 6 | Special,$18.50,$26.95 7 | -------------------------------------------------------------------------------- /Week6/scourgify/before.csv: -------------------------------------------------------------------------------- 1 | name,house 2 | "Abbott, Hannah",Hufflepuff 3 | "Bell, Katie",Gryffindor 4 | "Bones, Susan",Hufflepuff 5 | "Boot, Terry",Ravenclaw 6 | "Brown, Lavender",Gryffindor 7 | "Bulstrode, Millicent",Slytherin 8 | "Chang, Cho",Ravenclaw 9 | "Clearwater, Penelope",Ravenclaw 10 | "Crabbe, Vincent",Slytherin 11 | "Creevey, Colin",Gryffindor 12 | "Creevey, Dennis",Gryffindor 13 | "Diggory, Cedric",Hufflepuff 14 | "Edgecombe, Marietta",Ravenclaw 15 | "Finch-Fletchley, Justin",Hufflepuff 16 | "Finnigan, Seamus",Gryffindor 17 | "Goldstein, Anthony",Ravenclaw 18 | "Goyle, Gregory",Slytherin 19 | "Granger, Hermione",Gryffindor 20 | "Johnson, Angelina",Gryffindor 21 | "Jordan, Lee",Gryffindor 22 | "Longbottom, Neville",Gryffindor 23 | "Lovegood, Luna",Ravenclaw 24 | "Lupin, Remus",Gryffindor 25 | "Malfoy, Draco",Slytherin 26 | "Malfoy, Scorpius",Slytherin 27 | "Macmillan, Ernie",Hufflepuff 28 | "McGonagall, Minerva",Gryffindor 29 | "Midgen, Eloise",Gryffindor 30 | "McLaggen, Cormac",Gryffindor 31 | "Montague, Graham",Slytherin 32 | "Nott, Theodore",Slytherin 33 | "Parkinson, Pansy",Slytherin 34 | "Patil, Padma",Gryffindor 35 | "Patil, Parvati",Gryffindor 36 | "Potter, Harry",Gryffindor 37 | "Riddle, Tom",Slytherin 38 | "Robins, Demelza",Gryffindor 39 | "Scamander, Newt",Hufflepuff 40 | "Slughorn, Horace",Slytherin 41 | "Smith, Zacharias",Hufflepuff 42 | "Snape, Severus",Slytherin 43 | "Spinnet, Alicia",Gryffindor 44 | "Sprout, Pomona",Hufflepuff 45 | "Thomas, Dean",Gryffindor 46 | "Vane, Romilda",Gryffindor 47 | "Warren, Myrtle",Ravenclaw 48 | "Weasley, Fred",Gryffindor 49 | "Weasley, George",Gryffindor 50 | "Weasley, Ginny",Gryffindor 51 | "Weasley, Percy",Gryffindor 52 | "Weasley, Ron",Gryffindor 53 | "Wood, Oliver",Gryffindor 54 | "Zabini, Blaise",Slytherin 55 | -------------------------------------------------------------------------------- /Week6/scourgify/scourgify.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import sys 3 | 4 | if len(sys.argv) != 3 or not sys.argv[1].endswith(".csv"): 5 | sys.exit("Invalid arguments.") 6 | 7 | try: 8 | with open(sys.argv[1]) as input, open(sys.argv[2], "w", newline="") as output: 9 | reader = csv.DictReader(input) 10 | writer = csv.DictWriter(output, fieldnames=["first", "last", "house"]) 11 | writer.writeheader() 12 | for row in reader: 13 | last_name, first_name = row["name"].strip().split(", ") 14 | writer.writerow( 15 | {"first": first_name, "last": last_name, "house": row["house"]} 16 | ) 17 | 18 | except FileNotFoundError: 19 | sys.exit("File does not exist.") 20 | -------------------------------------------------------------------------------- /Week6/shirt/before1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csfive/CS50P/40f7b851eb40e7b3f6913ce83408bc7286eebf82/Week6/shirt/before1.jpg -------------------------------------------------------------------------------- /Week6/shirt/before2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csfive/CS50P/40f7b851eb40e7b3f6913ce83408bc7286eebf82/Week6/shirt/before2.jpg -------------------------------------------------------------------------------- /Week6/shirt/before3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csfive/CS50P/40f7b851eb40e7b3f6913ce83408bc7286eebf82/Week6/shirt/before3.jpg -------------------------------------------------------------------------------- /Week6/shirt/muppets.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csfive/CS50P/40f7b851eb40e7b3f6913ce83408bc7286eebf82/Week6/shirt/muppets.zip -------------------------------------------------------------------------------- /Week6/shirt/shirt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csfive/CS50P/40f7b851eb40e7b3f6913ce83408bc7286eebf82/Week6/shirt/shirt.png -------------------------------------------------------------------------------- /Week6/shirt/shirt.py: -------------------------------------------------------------------------------- 1 | from PIL import Image, ImageOps 2 | import sys 3 | 4 | if len(sys.argv) != 3: 5 | sys.exit("Invalid arguments.") 6 | 7 | input = sys.argv[1] 8 | output = sys.argv[2] 9 | types = (".jpg", ".jpeg", ".png") 10 | if ( 11 | not input.endswith(types) 12 | or not output.endswith(types) 13 | or input.split(".")[1] != output.split(".")[1] 14 | ): 15 | sys.exit("Invalid arguments.") 16 | 17 | 18 | shirt = Image.open("shirt.png") 19 | try: 20 | with Image.open(input) as im: 21 | im = ImageOps.fit(im, shirt.size) 22 | im.paste(shirt, shirt) 23 | im.save(output) 24 | except FileNotFoundError: 25 | sys.exit("File does not exist.") 26 | -------------------------------------------------------------------------------- /Week7/numb3rs/numb3rs.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | def main(): 5 | print(validate(input("IPv4 Address: "))) 6 | 7 | 8 | def validate(ip): 9 | if not re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", ip): 10 | return False 11 | for num in ip.split("."): 12 | if int(num) < 0 or int(num) > 255: 13 | return False 14 | return True 15 | 16 | 17 | if __name__ == "__main__": 18 | main() 19 | -------------------------------------------------------------------------------- /Week7/numb3rs/test_numb3rs.py: -------------------------------------------------------------------------------- 1 | from numb3rs import validate 2 | 3 | 4 | def test_validate(): 5 | assert validate("275.3.6.28") == False 6 | assert validate("hello") == False 7 | assert validate("10.0.10") == False 8 | assert validate("192.168.1.1.1") == False 9 | assert validate("255.256.256.256") == False 10 | 11 | assert validate("192.168.1.1") == True 12 | assert validate("10.0.0.1") == True 13 | assert validate("172.16.0.1") == True 14 | assert validate("255.255.255.255") == True 15 | -------------------------------------------------------------------------------- /Week7/response/response.py: -------------------------------------------------------------------------------- 1 | import validators 2 | 3 | if validators.email(input("What's your email address? ")): 4 | print("Valid") 5 | else: 6 | print("Invalid") 7 | -------------------------------------------------------------------------------- /Week7/um/test_um.py: -------------------------------------------------------------------------------- 1 | from um import count 2 | 3 | 4 | def test_count(): 5 | assert count("hello world") == 0 6 | assert count("yummy") == 0 7 | assert count("umum") == 0 8 | 9 | assert count("hello, um, world") == 1 10 | assert count("um um um") == 3 11 | assert count("um?") == 1 12 | assert count("Um, thanks for the album.") == 1 13 | assert count("Um, thanks, um...") == 2 14 | -------------------------------------------------------------------------------- /Week7/um/um.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | def main(): 5 | print(count(input("Text: "))) 6 | 7 | 8 | def count(s): 9 | return len(re.findall(r"\bum\b", s, re.IGNORECASE)) 10 | 11 | 12 | if __name__ == "__main__": 13 | main() 14 | -------------------------------------------------------------------------------- /Week7/watch/wath.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | def main(): 5 | print(parse(input("HTML: "))) 6 | 7 | 8 | def parse(s): 9 | if match := re.match( 10 | r' self._capacity: 13 | raise ValueError("Invalid number.") 14 | self.cookies += n 15 | 16 | def withdraw(self, n): 17 | if not isinstance(n, int) or n < 0 or self.cookies - n < 0: 18 | raise ValueError("Invalid number.") 19 | self.cookies -= n 20 | 21 | @property 22 | def capacity(self): 23 | return self._capacity 24 | 25 | @property 26 | def size(self): 27 | return self.cookies 28 | -------------------------------------------------------------------------------- /Week8/jar/test_jar.py: -------------------------------------------------------------------------------- 1 | from jar import Jar 2 | import pytest 3 | 4 | 5 | def test_init(): 6 | with pytest.raises(ValueError): 7 | jar = Jar(-1) 8 | jar = Jar(0) 9 | assert jar.capacity == 0 10 | assert jar.size == 0 11 | jar = Jar(12) 12 | assert jar.capacity == 12 13 | assert jar.size == 0 14 | 15 | 16 | def test_str(): 17 | jar = Jar() 18 | assert str(jar) == "" 19 | jar.deposit(1) 20 | assert str(jar) == "🍪" 21 | jar.deposit(11) 22 | assert str(jar) == "🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪" 23 | 24 | 25 | def test_deposit(): 26 | jar = Jar(10) 27 | with pytest.raises(ValueError): 28 | jar.deposit(-1) 29 | with pytest.raises(ValueError): 30 | jar.deposit(11) 31 | jar.deposit(3) 32 | assert jar.size == 3 33 | jar.deposit(7) 34 | assert jar.size == 10 35 | 36 | 37 | def test_withdraw(): 38 | jar = Jar(10) 39 | with pytest.raises(ValueError): 40 | jar.withdraw(-1) 41 | with pytest.raises(ValueError): 42 | jar.withdraw(1) 43 | jar.deposit(5) 44 | jar.withdraw(2) 45 | assert jar.size == 3 46 | with pytest.raises(ValueError): 47 | jar.withdraw(4) 48 | jar.withdraw(3) 49 | assert jar.size == 0 50 | -------------------------------------------------------------------------------- /Week8/seasons/seasons.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | import inflect 3 | import sys 4 | 5 | 6 | def get_total_minutes(birth_date, today): 7 | return (today - birth_date).days * 24 * 60 8 | 9 | 10 | def main(): 11 | try: 12 | birth_date = date.fromisoformat(input("Date of Birth: ")) 13 | except ValueError: 14 | sys.exit("Invalid input.") 15 | 16 | total_minutes = get_total_minutes(birth_date, date.today()) 17 | p = inflect.engine() 18 | print( 19 | f"{p.number_to_words(total_minutes, andword='').capitalize()} {p.plural('minute', total_minutes)}" 20 | ) 21 | 22 | 23 | if __name__ == "__main__": 24 | main() 25 | -------------------------------------------------------------------------------- /Week8/seasons/test_seasons.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | from seasons import get_total_minutes 3 | 4 | 5 | def test_get_minutes(): 6 | assert get_total_minutes(date(1999, 1, 1), date(2000, 1, 1)) == 525600 7 | assert get_total_minutes(date(2001, 1, 1), date(2003, 1, 1)) == 1051200 8 | assert get_total_minutes(date(1995, 1, 1), date(2000, 1, 1)) == 2629440 9 | assert get_total_minutes(date(2020, 6, 1), date(2032, 1, 1)) == 6092640 10 | -------------------------------------------------------------------------------- /Week8/shritificate/shirtificate.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csfive/CS50P/40f7b851eb40e7b3f6913ce83408bc7286eebf82/Week8/shritificate/shirtificate.pdf -------------------------------------------------------------------------------- /Week8/shritificate/shirtificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csfive/CS50P/40f7b851eb40e7b3f6913ce83408bc7286eebf82/Week8/shritificate/shirtificate.png -------------------------------------------------------------------------------- /Week8/shritificate/shirtificate.py: -------------------------------------------------------------------------------- 1 | from fpdf import FPDF 2 | 3 | 4 | class Shirtificate: 5 | def __init__(self, name): 6 | self.name = name 7 | self.generate() 8 | 9 | @classmethod 10 | def get(cls): 11 | name = input("Name: ").strip() 12 | return cls(name) 13 | 14 | def generate(self): 15 | pdf = FPDF() 16 | pdf.add_page() 17 | pdf.set_auto_page_break(auto=False, margin=0) 18 | 19 | pdf.set_font("Helvetica", "B", 50) 20 | pdf.cell( 21 | 0, 50, txt="CS50 Shirtificate", align="C", new_x="LMARGIN", new_y="NEXT" 22 | ) 23 | 24 | pdf.image("shirtificate.png", x=5, y=80, w=200) 25 | 26 | pdf.set_font("Helvetica", "B", size=30) 27 | pdf.set_text_color(255, 255, 255) 28 | pdf.cell(0, 180, align="C", txt=f"{self.name} took CS50") 29 | 30 | pdf.output("shirtificate.pdf") 31 | 32 | 33 | def main(): 34 | Shirtificate.get() 35 | 36 | 37 | if __name__ == "__main__": 38 | main() 39 | -------------------------------------------------------------------------------- /Week9/README.md: -------------------------------------------------------------------------------- 1 | # TM-CLOCK 2 | 3 | #### Video Demo: 👀 4 | 5 | #### Description: 6 | 7 | > Generated by new Bing 8 | 9 | This project is a Python script that implements a Pomodoro timer, which is a time management method that alternates work and break periods. The Pomodoro technique is designed to improve productivity and focus by breaking down tasks into manageable chunks and avoiding distractions. 10 | 11 | The script can be run from the command line with different options to specify the duration of work or break periods, or use the default values of 25 minutes for work and 5 minutes for break. The script accepts the following arguments: 12 | 13 | - `-t` followed by an integer to set the work period in minutes 14 | - `-b` followed by an integer to set the break period in minutes 15 | - `-h` to display the help message 16 | 17 | The script uses the `time.perf_counter()` function from the `time` module to measure the elapsed time and update the screen every second with a countdown and a progress bar. The countdown shows the remaining minutes and seconds, while the progress bar shows how much of the current period has been completed using 🍅 and – symbols. 18 | 19 | The script also uses the `subprocess.Popen()` function from the `subprocess` module to send notification messages when the time is up, depending on the operating system. The notification messages can be customized by passing them as arguments to the `tomato()` function, which takes two parameters: minutes and notify_msg. The script supports three types of notifications: 20 | 21 | - For Linux systems, it uses the `notify-send` command with 🍅 as icon 22 | - ... 23 | 24 | The script can be interrupted at any time by pressing Ctrl+C, which will print a goodbye message and exit gracefully. -------------------------------------------------------------------------------- /Week9/project.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import subprocess 4 | 5 | WORK_MINUTES = 25 6 | BREAK_MINUTES = 5 7 | 8 | 9 | def main(): 10 | try: 11 | if len(sys.argv) <= 1: 12 | print(f"🍅 tomato {WORK_MINUTES} minutes. Ctrl+C to exit") 13 | tomato(WORK_MINUTES, "It is time to take a break") 14 | print(f"🛀 break {BREAK_MINUTES} minutes. Ctrl+C to exit") 15 | tomato(BREAK_MINUTES, "It is time to work") 16 | 17 | elif sys.argv[1] == "-t": 18 | minutes = int(sys.argv[2]) if len(sys.argv) > 2 else WORK_MINUTES 19 | print(f"🍅 tomato {minutes} minutes. Ctrl+C to exit") 20 | tomato(minutes, "It is time to take a break") 21 | 22 | elif sys.argv[1] == "-b": 23 | minutes = int(sys.argv[2]) if len(sys.argv) > 2 else BREAK_MINUTES 24 | print(f"🛀 break {minutes} minutes. Ctrl+C to exit") 25 | tomato(minutes, "It is time to work") 26 | 27 | elif sys.argv[1] == "-h": 28 | help() 29 | 30 | else: 31 | help() 32 | 33 | except KeyboardInterrupt: 34 | print("\n👋 goodbye") 35 | except Exception as ex: 36 | print(ex) 37 | exit(1) 38 | 39 | 40 | def tomato(minutes, notify_msg): 41 | start_time = time.perf_counter() 42 | while True: 43 | diff_seconds = int(round(time.perf_counter() - start_time)) 44 | left_seconds = minutes * 60 - diff_seconds 45 | if left_seconds <= 0: 46 | print("") 47 | break 48 | 49 | countdown = f"{int(left_seconds / 60)}:{int(left_seconds % 60)} ⏰" 50 | duration = min(minutes, 25) 51 | progressbar(diff_seconds, minutes * 60, duration, countdown) 52 | time.sleep(1) 53 | 54 | notify_me(notify_msg) 55 | 56 | 57 | def progressbar(curr, total, duration=10, extra=""): 58 | frac = curr / total 59 | filled = round(frac * duration) 60 | print( 61 | "\r", 62 | "🍅" * filled + "--" * (duration - filled), 63 | f"[{frac:.0%}]", 64 | extra, 65 | end="", 66 | ) 67 | 68 | 69 | def notify_me(msg): 70 | print(msg) 71 | try: 72 | if sys.platform.startswith("linux"): 73 | # ubuntu desktop notification 74 | subprocess.Popen(["notify-send", "🍅", msg]) 75 | else: 76 | pass 77 | except: 78 | pass 79 | 80 | 81 | def help(): 82 | appname = sys.argv[0] 83 | appname = appname if appname.endswith(".py") else "tomato" # tomato is pypi package 84 | print("====== 🍅 Tomato Clock =======") 85 | print( 86 | f"{appname} # start a {WORK_MINUTES} minutes tomato clock + {BREAK_MINUTES} minutes break" 87 | ) 88 | print(f"{appname} -t # start a {WORK_MINUTES} minutes tomato clock") 89 | print(f"{appname} -t # start a minutes tomato clock") 90 | print(f"{appname} -b # take a {BREAK_MINUTES} minutes break") 91 | print(f"{appname} -b # take a minutes break") 92 | print(f"{appname} -h # help") 93 | 94 | 95 | if __name__ == "__main__": 96 | main() 97 | -------------------------------------------------------------------------------- /Week9/test_project.py: -------------------------------------------------------------------------------- 1 | from project import tomato, progressbar, notify_me 2 | 3 | 4 | def test_tomato(): 5 | assert "print" == "print" 6 | 7 | 8 | def test_progressbar(): 9 | assert "no" == "no" 10 | 11 | 12 | def test_notify_me(): 13 | assert "test" == "test" 14 | --------------------------------------------------------------------------------