diff --git a/problems/prepare.sh b/problems/prepare.sh new file mode 100755 index 0000000..eb4696f --- /dev/null +++ b/problems/prepare.sh @@ -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 diff --git a/problems/pset0/einstein/einstein.py b/problems/pset0/einstein/einstein.py new file mode 100644 index 0000000..efd6209 --- /dev/null +++ b/problems/pset0/einstein/einstein.py @@ -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() diff --git a/problems/pset0/faces/faces.py b/problems/pset0/faces/faces.py new file mode 100644 index 0000000..053f6e5 --- /dev/null +++ b/problems/pset0/faces/faces.py @@ -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() diff --git a/problems/pset0/indoor/indoor.py b/problems/pset0/indoor/indoor.py new file mode 100644 index 0000000..db876c1 --- /dev/null +++ b/problems/pset0/indoor/indoor.py @@ -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() diff --git a/problems/pset0/playback/playback.py b/problems/pset0/playback/playback.py new file mode 100644 index 0000000..7f33e0b --- /dev/null +++ b/problems/pset0/playback/playback.py @@ -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() diff --git a/problems/pset0/tip/tip.py b/problems/pset0/tip/tip.py new file mode 100644 index 0000000..ba78dae --- /dev/null +++ b/problems/pset0/tip/tip.py @@ -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() diff --git a/problems/pset1/bank/bank.py b/problems/pset1/bank/bank.py new file mode 100644 index 0000000..e5ff536 --- /dev/null +++ b/problems/pset1/bank/bank.py @@ -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() diff --git a/problems/pset1/deep/deep.py b/problems/pset1/deep/deep.py new file mode 100644 index 0000000..96b997c --- /dev/null +++ b/problems/pset1/deep/deep.py @@ -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() diff --git a/problems/pset1/extensions/extensions.py b/problems/pset1/extensions/extensions.py new file mode 100644 index 0000000..099fbe5 --- /dev/null +++ b/problems/pset1/extensions/extensions.py @@ -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() diff --git a/problems/pset1/interpreter/interpreter.py b/problems/pset1/interpreter/interpreter.py new file mode 100644 index 0000000..ec2d169 --- /dev/null +++ b/problems/pset1/interpreter/interpreter.py @@ -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() diff --git a/problems/pset1/meal/meal.py b/problems/pset1/meal/meal.py new file mode 100644 index 0000000..69e5230 --- /dev/null +++ b/problems/pset1/meal/meal.py @@ -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() diff --git a/problems/pset2/camel/camel.py b/problems/pset2/camel/camel.py new file mode 100644 index 0000000..6ce1122 --- /dev/null +++ b/problems/pset2/camel/camel.py @@ -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() diff --git a/problems/pset2/coke/coke.py b/problems/pset2/coke/coke.py new file mode 100644 index 0000000..6b44759 --- /dev/null +++ b/problems/pset2/coke/coke.py @@ -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() diff --git a/problems/pset2/nutrition/nutrition.py b/problems/pset2/nutrition/nutrition.py new file mode 100644 index 0000000..e58ab08 --- /dev/null +++ b/problems/pset2/nutrition/nutrition.py @@ -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() diff --git a/problems/pset2/plates/plates.py b/problems/pset2/plates/plates.py new file mode 100644 index 0000000..b00164f --- /dev/null +++ b/problems/pset2/plates/plates.py @@ -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() diff --git a/problems/pset2/twttr/twttr.py b/problems/pset2/twttr/twttr.py new file mode 100644 index 0000000..91405cd --- /dev/null +++ b/problems/pset2/twttr/twttr.py @@ -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() diff --git a/problems/pset3/fuel/fuel.py b/problems/pset3/fuel/fuel.py new file mode 100644 index 0000000..9a2e6cb --- /dev/null +++ b/problems/pset3/fuel/fuel.py @@ -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() diff --git a/problems/pset3/grocery/grocery.py b/problems/pset3/grocery/grocery.py new file mode 100644 index 0000000..60d3c9a --- /dev/null +++ b/problems/pset3/grocery/grocery.py @@ -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() diff --git a/problems/pset3/outdated/outdated.py b/problems/pset3/outdated/outdated.py new file mode 100644 index 0000000..b09701f --- /dev/null +++ b/problems/pset3/outdated/outdated.py @@ -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() diff --git a/problems/pset3/taqueria/taqueria.py b/problems/pset3/taqueria/taqueria.py new file mode 100644 index 0000000..47a69b3 --- /dev/null +++ b/problems/pset3/taqueria/taqueria.py @@ -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() diff --git a/problems/pset4/adieu/adieu.py b/problems/pset4/adieu/adieu.py new file mode 100644 index 0000000..0ee79b4 --- /dev/null +++ b/problems/pset4/adieu/adieu.py @@ -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() diff --git a/problems/pset4/bitcoin/bitcoin.py b/problems/pset4/bitcoin/bitcoin.py new file mode 100644 index 0000000..37fca4e --- /dev/null +++ b/problems/pset4/bitcoin/bitcoin.py @@ -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() diff --git a/problems/pset4/emojize/emojize.py b/problems/pset4/emojize/emojize.py new file mode 100644 index 0000000..713c873 --- /dev/null +++ b/problems/pset4/emojize/emojize.py @@ -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() diff --git a/problems/pset4/figlet/figlet.py b/problems/pset4/figlet/figlet.py new file mode 100644 index 0000000..a76bb37 --- /dev/null +++ b/problems/pset4/figlet/figlet.py @@ -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() diff --git a/problems/pset4/game/game.py b/problems/pset4/game/game.py new file mode 100644 index 0000000..67134d6 --- /dev/null +++ b/problems/pset4/game/game.py @@ -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() diff --git a/problems/pset4/professor/professor.py b/problems/pset4/professor/professor.py new file mode 100644 index 0000000..cf619e0 --- /dev/null +++ b/problems/pset4/professor/professor.py @@ -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() diff --git a/problems/pset5/test_bank/bank.py b/problems/pset5/test_bank/bank.py new file mode 100644 index 0000000..65ed2ef --- /dev/null +++ b/problems/pset5/test_bank/bank.py @@ -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() diff --git a/problems/pset5/test_bank/test_bank.py b/problems/pset5/test_bank/test_bank.py new file mode 100644 index 0000000..45e0500 --- /dev/null +++ b/problems/pset5/test_bank/test_bank.py @@ -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() diff --git a/problems/pset5/test_fuel/fuel.py b/problems/pset5/test_fuel/fuel.py new file mode 100644 index 0000000..f2949ac --- /dev/null +++ b/problems/pset5/test_fuel/fuel.py @@ -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() diff --git a/problems/pset5/test_fuel/test_fuel.py b/problems/pset5/test_fuel/test_fuel.py new file mode 100644 index 0000000..e9a6336 --- /dev/null +++ b/problems/pset5/test_fuel/test_fuel.py @@ -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() diff --git a/problems/pset5/test_plates/plates.py b/problems/pset5/test_plates/plates.py new file mode 100644 index 0000000..c188cde --- /dev/null +++ b/problems/pset5/test_plates/plates.py @@ -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() diff --git a/problems/pset5/test_plates/test_plates.py b/problems/pset5/test_plates/test_plates.py new file mode 100644 index 0000000..811fa8e --- /dev/null +++ b/problems/pset5/test_plates/test_plates.py @@ -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() diff --git a/problems/pset5/test_twttr/test_twttr.py b/problems/pset5/test_twttr/test_twttr.py new file mode 100644 index 0000000..4eb4f5a --- /dev/null +++ b/problems/pset5/test_twttr/test_twttr.py @@ -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() diff --git a/problems/pset5/test_twttr/twttr.py b/problems/pset5/test_twttr/twttr.py new file mode 100644 index 0000000..a5da947 --- /dev/null +++ b/problems/pset5/test_twttr/twttr.py @@ -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() diff --git a/problems/pset6/lines/lines.py b/problems/pset6/lines/lines.py new file mode 100644 index 0000000..511592c --- /dev/null +++ b/problems/pset6/lines/lines.py @@ -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() diff --git a/problems/pset6/lines/test_lines.py b/problems/pset6/lines/test_lines.py new file mode 100644 index 0000000..89a0a7f --- /dev/null +++ b/problems/pset6/lines/test_lines.py @@ -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() diff --git a/problems/pset6/pizza/pizza.py b/problems/pset6/pizza/pizza.py new file mode 100644 index 0000000..c046ca9 --- /dev/null +++ b/problems/pset6/pizza/pizza.py @@ -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() diff --git a/problems/pset6/pizza/regular.csv b/problems/pset6/pizza/regular.csv new file mode 100644 index 0000000..0f13972 --- /dev/null +++ b/problems/pset6/pizza/regular.csv @@ -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 diff --git a/problems/pset6/scourgify/after.csv b/problems/pset6/scourgify/after.csv new file mode 100644 index 0000000..f1e5fdf --- /dev/null +++ b/problems/pset6/scourgify/after.csv @@ -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 diff --git a/problems/pset6/scourgify/before.csv b/problems/pset6/scourgify/before.csv new file mode 100644 index 0000000..258d683 --- /dev/null +++ b/problems/pset6/scourgify/before.csv @@ -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 diff --git a/problems/pset6/scourgify/in.csv b/problems/pset6/scourgify/in.csv new file mode 100644 index 0000000..d2d31ac --- /dev/null +++ b/problems/pset6/scourgify/in.csv @@ -0,0 +1,7 @@ +name,house +"Abbott, Hannah",Hufflepuff +"Bell, Katie",Gryffindor +"Bones, Susan",Hufflepuff +"Boot, Terry",Ravenclaw +"Brown, Lavender",Gryffindor +"Bulstrode, Millicent",Slytherin diff --git a/problems/pset6/scourgify/out.csv b/problems/pset6/scourgify/out.csv new file mode 100644 index 0000000..ae6676c --- /dev/null +++ b/problems/pset6/scourgify/out.csv @@ -0,0 +1,5 @@ +first,last,house +Susan,Bones,Hufflepuff +Terry,Boot,Ravenclaw +Lavender,Brown,Gryffindor +Millicent,Bulstrode,Slytherin diff --git a/problems/pset6/scourgify/scourgify.py b/problems/pset6/scourgify/scourgify.py new file mode 100644 index 0000000..11ac1b8 --- /dev/null +++ b/problems/pset6/scourgify/scourgify.py @@ -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() diff --git a/problems/pset6/shirt/after1.jpg b/problems/pset6/shirt/after1.jpg new file mode 100644 index 0000000..ffeb31c Binary files /dev/null and b/problems/pset6/shirt/after1.jpg differ diff --git a/problems/pset6/shirt/after2.jpg b/problems/pset6/shirt/after2.jpg new file mode 100644 index 0000000..6b15fa3 Binary files /dev/null and b/problems/pset6/shirt/after2.jpg differ diff --git a/problems/pset6/shirt/after3.jpg b/problems/pset6/shirt/after3.jpg new file mode 100644 index 0000000..09ad73b Binary files /dev/null and b/problems/pset6/shirt/after3.jpg differ diff --git a/problems/pset6/shirt/before1.jpg b/problems/pset6/shirt/before1.jpg new file mode 100644 index 0000000..d92eacc Binary files /dev/null and b/problems/pset6/shirt/before1.jpg differ diff --git a/problems/pset6/shirt/before2.jpg b/problems/pset6/shirt/before2.jpg new file mode 100644 index 0000000..ec8d66f Binary files /dev/null and b/problems/pset6/shirt/before2.jpg differ diff --git a/problems/pset6/shirt/before3.jpg b/problems/pset6/shirt/before3.jpg new file mode 100644 index 0000000..d964cd7 Binary files /dev/null and b/problems/pset6/shirt/before3.jpg differ diff --git a/problems/pset6/shirt/shirt.png b/problems/pset6/shirt/shirt.png new file mode 100644 index 0000000..716b412 Binary files /dev/null and b/problems/pset6/shirt/shirt.png differ diff --git a/problems/pset6/shirt/shirt.py b/problems/pset6/shirt/shirt.py new file mode 100644 index 0000000..4823da3 --- /dev/null +++ b/problems/pset6/shirt/shirt.py @@ -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() diff --git a/problems/pset7/numb3rs/numb3rs.py b/problems/pset7/numb3rs/numb3rs.py new file mode 100644 index 0000000..ea32b4b --- /dev/null +++ b/problems/pset7/numb3rs/numb3rs.py @@ -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() diff --git a/problems/pset7/numb3rs/test_numb3rs.py b/problems/pset7/numb3rs/test_numb3rs.py new file mode 100644 index 0000000..b75f47f --- /dev/null +++ b/problems/pset7/numb3rs/test_numb3rs.py @@ -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() diff --git a/problems/pset7/response/response.py b/problems/pset7/response/response.py new file mode 100644 index 0000000..7bac6a5 --- /dev/null +++ b/problems/pset7/response/response.py @@ -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() + diff --git a/problems/pset7/response/test_response.py b/problems/pset7/response/test_response.py new file mode 100644 index 0000000..2c67a0c --- /dev/null +++ b/problems/pset7/response/test_response.py @@ -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() diff --git a/problems/pset7/um/test_um.py b/problems/pset7/um/test_um.py new file mode 100644 index 0000000..7b88bb2 --- /dev/null +++ b/problems/pset7/um/test_um.py @@ -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() diff --git a/problems/pset7/um/um.py b/problems/pset7/um/um.py new file mode 100644 index 0000000..53942f9 --- /dev/null +++ b/problems/pset7/um/um.py @@ -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() diff --git a/problems/pset7/watch/watch.py b/problems/pset7/watch/watch.py new file mode 100644 index 0000000..dd86b85 --- /dev/null +++ b/problems/pset7/watch/watch.py @@ -0,0 +1,20 @@ +import re + +youtube_regex = re.compile(r"") + + +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() diff --git a/problems/pset7/working/test_working.py b/problems/pset7/working/test_working.py new file mode 100644 index 0000000..68df649 --- /dev/null +++ b/problems/pset7/working/test_working.py @@ -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() diff --git a/problems/pset7/working/working.py b/problems/pset7/working/working.py new file mode 100644 index 0000000..d276d1d --- /dev/null +++ b/problems/pset7/working/working.py @@ -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() diff --git a/problems/pset8/jar/jar.py b/problems/pset8/jar/jar.py new file mode 100644 index 0000000..e9f0bbe --- /dev/null +++ b/problems/pset8/jar/jar.py @@ -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 diff --git a/problems/pset8/jar/test_jar.py b/problems/pset8/jar/test_jar.py new file mode 100644 index 0000000..a5d6ae3 --- /dev/null +++ b/problems/pset8/jar/test_jar.py @@ -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() diff --git a/problems/pset8/seasons/seasons.py b/problems/pset8/seasons/seasons.py new file mode 100644 index 0000000..d147b25 --- /dev/null +++ b/problems/pset8/seasons/seasons.py @@ -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() diff --git a/problems/pset8/seasons/test_seasons.py b/problems/pset8/seasons/test_seasons.py new file mode 100644 index 0000000..ac08ddd --- /dev/null +++ b/problems/pset8/seasons/test_seasons.py @@ -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() diff --git a/problems/pset8/shirtificate/shirtificate.pdf b/problems/pset8/shirtificate/shirtificate.pdf new file mode 100644 index 0000000..c50ba21 Binary files /dev/null and b/problems/pset8/shirtificate/shirtificate.pdf differ diff --git a/problems/pset8/shirtificate/shirtificate.png b/problems/pset8/shirtificate/shirtificate.png new file mode 100644 index 0000000..a37ec5a Binary files /dev/null and b/problems/pset8/shirtificate/shirtificate.png differ diff --git a/problems/pset8/shirtificate/shirtificate.py b/problems/pset8/shirtificate/shirtificate.py new file mode 100644 index 0000000..b5e01d0 --- /dev/null +++ b/problems/pset8/shirtificate/shirtificate.py @@ -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()