{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "173bdfb9",
   "metadata": {},
   "source": [
    "# Python 3 Tutorial Notebook"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "068cbd92",
   "metadata": {},
   "source": [
    "We'll be using this notebook to follow the slides from the workshop. You can also use it to experiment with Python yourself! Simply add a cell wherever you want, type in some Python code, and see what happens!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "698d5cf0",
   "metadata": {},
   "source": [
    "##  Topic 1: Printing"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e98b3475",
   "metadata": {},
   "source": [
    "### 1.1 Printing Basics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "069d08f2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# When a line begins with a '#' character, it designates a comment. This means that it's not actually a line of code\n",
    "\n",
    "# Can you print 'hello world', as is customary for those new to a language?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "86f8d0be",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Can you make Python print the staircase below:\n",
    "#\n",
    "#                    ========\n",
    "#                    |      |\n",
    "#             ===============      \n",
    "#             |      |      |\n",
    "#      ======================"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "602dbdad",
   "metadata": {},
   "source": [
    "### 1.2 Some other useful printing tips/tricks"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f554f941",
   "metadata": {},
   "outputs": [],
   "source": [
    "# The print(...) function can accept as many arguments as you'd like. It prints the arguments\n",
    "# in order, separated by a space. For example...\n",
    "\n",
    "print('hello', 'world', 'i', 'go', 'to', 'princeton')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f2419de",
   "metadata": {},
   "outputs": [],
   "source": [
    "# You can change the delimiter that separates the comma-separated arguments by changing the 'sep' parameter:\n",
    "\n",
    "print('hello', 'world', 'i', 'go', 'to', 'princeton', sep=' --> ')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ae31ea63",
   "metadata": {},
   "outputs": [],
   "source": [
    "# By default, python adds a newline to the end of any statement you print. However, you can change this\n",
    "# by changing the 'end' parameter. For example...\n",
    "\n",
    "# Here we've told Python to print 'hello world' and then an empty string. This effectively \n",
    "# removes the newline that Python adds by default.\n",
    "print('hello prince', end='')\n",
    "\n",
    "# The next line that we print then begins immediately after the previous thing we printed.\n",
    "print('ton')\n",
    "\n",
    "# We can also end our lines with something more exotic\n",
    "print('ACM is so cool', end=' :)')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4dc24edf",
   "metadata": {},
   "source": [
    "## Topic 2: Variables, Basic Operators, and Data Types"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6124d137",
   "metadata": {},
   "source": [
    "### 2.1 Playing with Numbers"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a017b2b1",
   "metadata": {},
   "source": [
    "For a description of all the operators that exist in Python, you can visit https://www.tutorialspoint.com/python/python_basic_operators.htm."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0a3717cf",
   "metadata": {},
   "outputs": [],
   "source": [
    "# What does the following snippet of code do?\n",
    "\n",
    "day = 24\n",
    "month = 'September'\n",
    "year = '2021'\n",
    "dotw = 'Friday'\n",
    "\n",
    "print(month, day - 7, year, 'was a', dotw)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0daab14d",
   "metadata": {},
   "outputs": [],
   "source": [
    "age_in_weeks = 1057\n",
    "\n",
    "# What's the difference between the two statements below? Comment one of them out to check yourself!\n",
    "age_in_years = 1057 / 52\n",
    "age_in_years = 1057 // 52\n",
    "\n",
    "print(age_in_years)\n",
    "\n",
    "# Can you explain to the person next to you why there's a difference?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "20a42d86",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Try to calculate the following in your head and see if your answer matches what Python says.\n",
    "# The order of operations in Python is similar to what you learned in grade school: evaluate parentheses,\n",
    "# then exponents, then multiplication/division/modulo from left to right, then addition and subtraction\n",
    "# from left to right.\n",
    "\n",
    "mystery = 2 ** 4 * 3 ** 2 % 7 * (2 + 7)\n",
    "print(mystery)\n",
    "\n",
    "# Why is the answer what Python says it is? Explain the steps to the person next to you."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ec9fdcdf",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Write a function that converts a given temperature in Farenheit to Celsius and Kelvin\n",
    "# The relevant formulas are (degrees Celsius) = (degrees Farenheit - 32) * 5 / 9\n",
    "# and (Kelvin) = (degrees Celsius + 273)\n",
    "\n",
    "farenheit = 86 # Change the value here to test your solution\n",
    "celsius = ... # CHANGE THIS LINE OF CODE\n",
    "kelvin = ... # CHANGE THIS LINE OF CODE\n",
    "\n",
    "print(farenheit, 'degrees farenheit =', celsius, 'degrees celsius =', kelvin, 'kelvin')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dbff63fb",
   "metadata": {},
   "source": [
    "### 2.2 Playing with Strings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "595a5af6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# You are given the following string:\n",
    "a = 'Thomas Cruise'\n",
    "\n",
    "# Your job is to put the phrase 'Tom Cruise is 9 outta 10' into variable b using ONLY operations on string a.\n",
    "# You may not concatenate letters or strings of your own. HINT: You can use the str(...) function to convert\n",
    "# numerical values into strings so that you can concatenate it with another string\n",
    "b = ... # CHANGE THIS LINE OF CODE\n",
    "\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0dd726e7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Practice with string formatting with mad libs! For this, you'll need to know \n",
    "# how to receive input. It's really easy in Python:\n",
    "\n",
    "word_1 = input('Input first word:\\n') # This prompts the user with the phrase 'Input first word'\n",
    "                                      # and stores the result in the variable word_1\n",
    "word_2 = input('Input second word:\\n')\n",
    "word_3 = input('Input third word:\\n')\n",
    "word_4 = input('Input fourth word:\\n')\n",
    "\n",
    "# You want to print the following mad libs:\n",
    "#\n",
    "# Hi, my name is [first phrase]. \n",
    "# One thing that I love about Princeton is [second phrase].\n",
    "# One pet peeve I have about Princeton is [third phrase], but I can get over it because I have [fourth phrase].\n",
    "# \n",
    "# For the last sentence, use one print statement to print it!\n",
    "\n",
    "print('\\nYour mad libs is: ')\n",
    "\n",
    "# CHANGE THE FOLLOWING THREE LINES OF CODE. HINT: Use the format() function!\n",
    "print(...)\n",
    "print(...)\n",
    "print(...)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "656d0012",
   "metadata": {},
   "source": [
    "### 2.3 Playing with Booleans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "edf455a3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Your objective is to write a boolean formula in Python that takes three boolean variables (a, b, c)\n",
    "# and returns True if and only if exactly one of them is True. This is called the xor of the variables\n",
    "\n",
    "# Toggle these to test your formula\n",
    "a = False\n",
    "b = True\n",
    "c = False\n",
    "\n",
    "# Write your formula here\n",
    "xor = ... # CHANGE THIS LINE OF CODE\n",
    "\n",
    "print(xor)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4b1cdd9",
   "metadata": {},
   "source": [
    "### 2.4 Mixing Types"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a099e601",
   "metadata": {},
   "outputs": [],
   "source": [
    "# In Python, data types are divided into two categories: truthy and falsy. Falsy values include anything\n",
    "# (strings, lists, etc.) that is empty, the special value None, any zero number, and the boolean False. \n",
    "# You can use the bool(...) function to check whether a value is truthy or falsy:\n",
    "\n",
    "print('bool(3) =', bool(3))\n",
    "print('bool(0) =', bool(0))\n",
    "print('bool(\"\") =', bool(''))\n",
    "print('bool(\" \") =', bool(' '))\n",
    "print('bool(False) =', bool(False))\n",
    "print('bool(True) =', bool(True))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb5ff6db",
   "metadata": {},
   "source": [
    "## Topic 3: If Statements, Ranges, and Loops"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5708f62d",
   "metadata": {},
   "source": [
    "### 3.1 Practice with the Basics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "be4ef675",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 5\n",
    "\n",
    "# What is the difference between this snippet of code:\n",
    "\n",
    "if x % 2 == 0:\n",
    "    print(x, 'is even')\n",
    "if x % 5 == 0:\n",
    "    print(x, 'is divisible by 5')\n",
    "if x > 0:\n",
    "    print(x, 'is positive')\n",
    "    \n",
    "print()\n",
    "    \n",
    "# And this one:\n",
    "if x % 2 == 0:\n",
    "    print(x, 'is even')\n",
    "elif x % 5 == 0:\n",
    "    print(x, 'is divisible by 5')\n",
    "elif x > 0:\n",
    "    print(x, 'is positive')\n",
    "    \n",
    "# Explain to the person next to you what the difference is."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e1eea750",
   "metadata": {},
   "outputs": [],
   "source": [
    "# FizzBuzz is a very well-known programming challenge. It's quite easy, but it can trip up people\n",
    "# who are trying to look for shortcuts to solving the problem. The problem is as follows:\n",
    "# \n",
    "# For every number k in order from 1 to 50, print\n",
    "# - 'FizzBuzz' if the number is divisible by 3 and 5\n",
    "# - 'Fizz' if the number is only divisible by 3\n",
    "# - 'Buzz' if the number is only divisble by 5\n",
    "# - the value of k if none of the above options hold\n",
    "#\n",
    "# Your task is to write a snippet of code that solves FizzBuzz."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69800e1b",
   "metadata": {},
   "source": [
    "### 3.2 Ternary Statements in Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0127606b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# The following if statement construct is so common it has a name ('ternary statement'):\n",
    "#\n",
    "# if (condition): \n",
    "#    x = something1\n",
    "# elif (condition2):\n",
    "#    x = something2\n",
    "# else:\n",
    "#    x = something3\n",
    "#\n",
    "# In python, this can be shortened into a one-liner:\n",
    "#\n",
    "# x = something else something2 if (condition2) else something3\n",
    "#\n",
    "# And this works for an arbitrary number of elif statements in between the initial if and final else.\n",
    "\n",
    "# Can you convert the following block into a one-liner?\n",
    "budget = 3\n",
    "if budget > 50:\n",
    "    restaurant = 'Agricola'\n",
    "elif budget > 30:\n",
    "    restaurant = 'Mediterra'\n",
    "elif budget > 15:\n",
    "    restaurant = 'Thai Village'\n",
    "else:\n",
    "    retaurant = 'Wawa'\n",
    "    \n",
    "# Write your solution below:\n",
    "restaurant = ... # CHANGE THIS LINE OF CODE\n",
    "\n",
    "print(restaurant)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e738967e",
   "metadata": {},
   "source": [
    "### 3.3 Practice with While Loops"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2937bcc0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Your job is to create a 'guessing game' where the program thinks of an integer from 1 to 50\n",
    "# and will keep prompting you for a guess. It'll tell you each time whether your guess is\n",
    "# too high or too low until you find the number.\n",
    "\n",
    "# Don't touch these two lines of code; they choose a random number between 1 and 50\n",
    "# and store it in mystery_num\n",
    "from random import randint\n",
    "mystery_num = randint(1, 100)\n",
    "\n",
    "# Write your guessing game below:\n",
    "guess = int(input('Guess a number:\\n')) # First guess; don't forget to convert it to an int!\n",
    "\n",
    "# WRITE THE REST OF THE CODE FOR THE GUESSING GAME HERE\n",
    "\n",
    "# Follow-up: Using the best strategy, what's the worst-case number of guesses you should need?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b975834b",
   "metadata": {},
   "source": [
    "## Topic 4: Data Structures in Python"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6484f6cc",
   "metadata": {},
   "source": [
    "### 4.1 Sequences"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6ba8333",
   "metadata": {},
   "source": [
    "Strings, tuples, and lists are all considered *sequences* in Python, which is why there are many operations that work on all three of them."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6544a85",
   "metadata": {},
   "source": [
    "#### 4.1.1 Iterating"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "efc65628",
   "metadata": {},
   "outputs": [],
   "source": [
    "# When at the top of a loop, the 'in' keyword in Python will iterate through all of the sequence's \n",
    "# members in order. For strings, members are individual characters; for lists and tuples, they're \n",
    "# the items contained.\n",
    "\n",
    "# Task: Given a list of lowercase words, print whether the word has a vowel. Example: if the input is\n",
    "# ['rhythm', 'owl', 'hymn', 'aardvark'], you should output the following:\n",
    "# rhythm has no vowels\n",
    "# owl has a vowel\n",
    "# hymn has no vowels\n",
    "# aardvark has a vowel\n",
    "\n",
    "# HINT: The 'in' keyword can also test whether something is a member of another object.\n",
    "# Also, don't forget about break and continue!\n",
    "\n",
    "vowels = ['a', 'e', 'i', 'o', 'u']\n",
    "words = ['rhythm', 'owl', 'hymn', 'aardvark']\n",
    "\n",
    "# WRITE YOUR CODE HERE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e6306ebb",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Given a tuple, write a program to check if the value at index i is equal to the square of i.\n",
    "# Example: If the input is nums = (0, 2, 4, 6, 8), then the desired output is\n",
    "#\n",
    "# True\n",
    "# False\n",
    "# True\n",
    "# False\n",
    "# False\n",
    "#\n",
    "# Because nums[0] = 0^2 and nums[2] = 4 = 2^2. HINT: Use enumerate!\n",
    "\n",
    "nums = (0, 2, 4, 6, 8)\n",
    "\n",
    "# WRITE YOUR CODE HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d4ee6b0",
   "metadata": {},
   "source": [
    "#### 4.1.2 Slicing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "86f83d27",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Slicing is one of the operations that work on all of them.\n",
    "\n",
    "# Task 1: Given a string s whose length is odd and at least 5, can you print \n",
    "# the middle three characters of it? Try to do it in one line.\n",
    "# Example: if the input is 'PrInCeToN', the the output should be 'nCe'\n",
    "s = 'PrInCeToN'\n",
    "\n",
    "# WRITE YOUR CODE HERE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "126a2a79",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# Task 2: Given a tuple, return a tuple that includes only every other element, starting\n",
    "# from the first. Example: if the input is (4, 5, 'cow', True, 9.4), then the output should\n",
    "# be (4, 'cow', 9.4). Again, try to do it in one line — there's an easy way to do it with slicing.\n",
    "\n",
    "t = (4, 5, 'cow', True, 9.4)\n",
    "\n",
    "# WRITE YOUR CODE HERE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a2f2ce11",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Task 3: Do the same as task 2, except start from the last element and alternate backwards.\n",
    "# Example: if the input is (3, 9, 1, 0, True, 'Tiger'), output should be ('Tiger', 0, 9)\n",
    "\n",
    "t = (3, 9, 1, 0, True, 'Tiger')\n",
    "\n",
    "# WRITE YOUR CODE HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a8d29db",
   "metadata": {},
   "source": [
    "### 4.2 List Comprehension and Other Useful List Functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7ae3467e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Task 1: Given a list of names, return a new list where all the names which are more than 15\n",
    "# characters long are removed.\n",
    "\n",
    "names = ['Nalin Ranjan', 'Howard Yen', 'Sacheth Sathyanarayanan', 'Henry Tang', \\\n",
    "         'Austen Mazenko', 'Michael Tang', 'Dangely Canabal', 'Vicky Feng']\n",
    "\n",
    "# WRITE YOUR CODE HERE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4bad8b9e",
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "# Task 2: Given a list of strings, return a list which is the reverse of the original, with\n",
    "# all the strings reversed. Example: if the input is ['Its', 'nine', 'o-clock', 'on a', 'Saturday'],\n",
    "# then the output should be ['yadrutaS', 'a no', 'kcolc-o', 'enin', 'stI']. Try to do it in one line!\n",
    "\n",
    "# HINT: Use list comprehension and negative indices!\n",
    "\n",
    "l = ['Its', 'nine', 'o-clock', 'on a', 'Saturday']\n",
    "\n",
    "# WRITE YOUR CODE HERE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a17d31ed",
   "metadata": {},
   "outputs": [],
   "source": [
    "l1 = [5, 2, 6, 1, 8, 2, 4]\n",
    "l2 = [6, 1, 2, 4]\n",
    "\n",
    "# Python has a bunch of useful built-in list functions. Some of them are\n",
    "\n",
    "l1.append(3) # adds the element 3 to the end of the the list\n",
    "print(l1)\n",
    "\n",
    "l1.insert(1, 7) # adds the element 7 as the second element of the list\n",
    "print(l1)\n",
    "\n",
    "l1.remove(2) # Removes the first occurrence of 7 in the list (DOES NOT REMOVE ALL)\n",
    "print(l1)\n",
    "\n",
    "l1.pop(4) # Remove the fifth item of the list (since everything is zero-indexed)\n",
    "print(l1)\n",
    "\n",
    "l1.sort() # Sorts the list in increasing order\n",
    "print(l1)\n",
    "\n",
    "l1.sort(reverse=True) # Sorts the list in decreasing order\n",
    "print(l1)\n",
    "\n",
    "print(l1.count(2)) # Counts the number of occurrences of the number 2 in the list\n",
    "\n",
    "l1.extend(l2) # Appends all elements in l2 to the end of l1\n",
    "print(l1)\n",
    "\n",
    "# If the list is numeric, we can find the min, max, and sum easily:\n",
    "print('Sum:', sum(l1))\n",
    "print('Minimum:', min(l1))\n",
    "print('Maximum:', max(l1))\n",
    "\n",
    "# You can see all the list methods at https://www.w3schools.com/python/python_ref_list.asp"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "efdfe550",
   "metadata": {},
   "source": [
    "### 4.3 Sets and Dictionaries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "77a40840",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Task 1: In a dictionary, keys must be unique, but values need not be. Given a dictionary, write a script\n",
    "# that prints the set of all unique values in a dictionary. Example: if the dictionary is\n",
    "# {'Cap': 'bicker', 'Quad': 'sign-in', 'Colonial': 'sign-in', 'Tower': 'bicker', 'Charter': '???'}\n",
    "# The program should print {'sign-in', 'bicker', '???'}\n",
    "\n",
    "d = {'Cap': 'bicker', 'Quad': 'sign-in', 'Colonial': 'sign-in', 'Tower': 'bicker', 'Charter': '???'}\n",
    "\n",
    "# WRITE YOUR CODE HERE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "346a2d0e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Task 2: Given a passage of text (a string), analyze the frequency of each individual letter. Sort\n",
    "# the letters by their frequency in the passage. Does your distribution look reasonable for English?\n",
    "\n",
    "passage = \"\"\"it was the best of times, it was the worst of times, it was the age of wisdom, it was \n",
    "            the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was \n",
    "            the season of Light, it was the season of Darkness, it was the spring of hope, it was the \n",
    "            winter of despair, we had everything before us, we had nothing before us, we were all going \n",
    "            direct to Heaven, we were all going direct the other way -- in short, the period was so far \n",
    "            like the present period that some of its noisiest authorities insisted on its being received, \n",
    "            for good or for evil, in the superlative degree of comparison only\"\"\"\n",
    "\n",
    "# Here's the alphabet to help you out; it'll help you ignore other characters\n",
    "alphabet = \"abcdefghijklmnopqrstuvwxyz\"\n",
    "\n",
    "# WRITE YOUR CODE TO COLLECT THE DICTIONARY OF WORD FREQUENCIES HERE\n",
    "\n",
    "# Don't change the code below: it'll take your dictionary of frequencies and sort it from most frequent to least\n",
    "freqs = [(letter, d[letter]) for letter in d]\n",
    "freqs.sort(key = lambda x: x[1], reverse=True)\n",
    "\n",
    "print(freqs)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f290d66",
   "metadata": {},
   "source": [
    "## Topic 5: Functions in Python"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37b57d79",
   "metadata": {},
   "source": [
    "### 5.1 Practice with Basic Functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "af5153b4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Task 1: Write a function that returns the minimum of three numbers. Don't use the built-in min function\n",
    "\n",
    "def my_min(a, b, c):\n",
    "    # FILL IN THE FUNCTION DETAILS HERE (also delete the 'pass' keyword)\n",
    "    pass\n",
    "    \n",
    "# Test Cases\n",
    "print('Minimum of 6, 3, 7 is', my_min(6, 3, 7))\n",
    "print('Minimum of 0, 3.333, -52 is', my_min(0, -52, 3.333))\n",
    "print('Minimum of -3, -1, 3.14159 is', my_min(-3, -1, 3.14159))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c077fed4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Task 2: Write a function that checks if a given tuple of numbers is increasing (that is, each number\n",
    "# is at least the number before it)\n",
    "\n",
    "def my_increasing(t):\n",
    "    # FILL IN THE FUNCTION DETAILS HERE (also delete the 'pass' keyword)\n",
    "    pass\n",
    "\n",
    "# Test Cases\n",
    "print('(1, 2, 3, 4, 5, 7, 8) is increasing:', my_increasing((1, 2, 3, 4, 5, 7, 8)))\n",
    "print('(1, 2, 3, 2, 5, 7, 8) is increasing:', my_increasing((1, 2, 3, 2, 5, 7, 8)))\n",
    "print('(-1, 2, 3, 2.99, 5, 7, 8) is increasing:', my_increasing((1, 2, 3, 2, 5, 7, 8)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "44f7c217",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Task 3: Given a list of numbers that is guaranteed to contain all but one of the consecutive integers\n",
    "# 1 to N (for some N), find the one that is missing. For example, if the input is [2, 1, 5, 4], your function\n",
    "# should return 3, because that's the number missing from 1-5.\n",
    "\n",
    "def my_missing(l):\n",
    "    # FILL IN THE FUNCTION DETAILS HERE (also delete the 'pass' keyword)\n",
    "    pass\n",
    "\n",
    "print(my_missing([2, 1, 5, 4]))\n",
    "print(my_missing([3, 4, 6, 2, 5, 7, 9, 8]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4927ea14",
   "metadata": {},
   "source": [
    "### 5.2 Recursion"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1ead05cf",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Task: The sequence of Fibonacci numbers starts with the numbers 1 and 1 and every subsequent term\n",
    "# is the sum of the previous two terms. So the sequence is 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 87, 144, ...\n",
    "# Can you write a simple recursive function that calculates the nth Fibonacci number?\n",
    "\n",
    "# WARNING: Don't call your function for anything more than 35 or pass a non-integer parameter. \n",
    "# Your notebook might crash if you do.\n",
    "\n",
    "# WRITE YOUR CODE HERE\n",
    "\n",
    "print(fib(35)) # Should be 9227465"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3df824f1",
   "metadata": {},
   "source": [
    "### 5.3 Memoization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "132cbe1d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Part of the reason that we told you not to run your answer for 5.2 for large n is because the number of\n",
    "# function calls generated is exponentially large: for n = 35, the number of function calls you have is on\n",
    "# the order of 34 billion, which is a lot, even for a computer! If you did n = 75, the number of calls you\n",
    "# would make is approximately 37 sextillion, which is more than the number of seconds until the heat death\n",
    "# of the sun. \n",
    "\n",
    "# You can avert this issue, however, if you **memoize** your function, which is just a fancy way of saying\n",
    "# that you can remember values of your function instead of having to re-evaluate your function again. Python\n",
    "# has a handy memoization tool:\n",
    "\n",
    "from functools import lru_cache\n",
    "\n",
    "@lru_cache\n",
    "def fib(n):\n",
    "    # COPY THE CODE FROM THE PREVIOUS PROBLEM HERE\n",
    "\n",
    "print(fib(100)) # Works no problem! Should be 354224848179261915075\n",
    "\n",
    "# All we had to do was add the import statement and 'decorate' the function we wanted to remember\n",
    "# values from with the line @lru_cache"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45aa0659",
   "metadata": {},
   "source": [
    "## Topic 6: Classes in Python"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13a6a24f",
   "metadata": {},
   "source": [
    "### 6.1 Practice Writing Basic Classes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0aba78c6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Write a PrincetonStudent class, where a PrincetonStudent has a name, major, year,\n",
    "# set of clubs, and a preference ordering of dining halls. We want to have\n",
    "#\n",
    "# - a default constructor that initializes the PrincetonStudent with a name, major, PUID, year, no clubs,\n",
    "#   and a random preference ordering of dining halls\n",
    "# - a special constructor (class method) called detailed_student that initializes a PrincetonStudent \n",
    "#   with a name, major, year,\n",
    "#   a specific set of clubs, and a particular preference ordering of dining halls\n",
    "# - a __str__() method that prints all the data of the student\n",
    "# - a move_dhall_to_top() function that takes a dhall and moves it to the top\n",
    "#   of one's dining hall preference list\n",
    "# - a __lt__() method that returns true if and only if this student has a name that comes before\n",
    "#   the other's alphabetically\n",
    "# - an __eq__() method that returns true if and only if the PUIDs of students are equal \n",
    "\n",
    "# HINT: To generate a random dining hall preference order, you can take a particular preference order\n",
    "# and shuffle it using the random.shuffle(list) function\n",
    "\n",
    "from random import shuffle\n",
    "\n",
    "class PrincetonStudent():\n",
    "    # WRITE THE DETAILS OF YOUR CLASS HERE (also delete the 'pass keyword')\n",
    "    pass\n",
    "        \n",
    "# Test your PrincetonStudent class using this test suite. Feel free to write your own too!\n",
    "nalin = PrincetonStudent('Nalin Ranjan', 'COS', '123456789', 2022)\n",
    "print(nalin, end=\"\\n\\n\")\n",
    "\n",
    "nalin.clubs.extend(['ACM', 'Taekwondo', 'Princeton Legal Journal', 'Badminton'])\n",
    "print(nalin, end=\"\\n\\n\")\n",
    "\n",
    "sacheth_clubs = ['ACM', 'Table Tennis']\n",
    "sacheth_prefs = ['WuCox', 'Whitman', 'Forbes', 'RoMa', 'CJL']\n",
    "sacheth = PrincetonStudent.detailed_student('Sacheth Sathyanarayanan', 'COS', \\\n",
    "                                '24681012', 2022, sacheth_clubs, sacheth_prefs)\n",
    "print(sacheth)\n",
    "\n",
    "print('Sacheth had a great meal at Whitman! It is now his favorite.\\n')\n",
    "sacheth.move_dhall_to_top('Whitman')\n",
    "print(sacheth)\n",
    "\n",
    "print('Sacheth is the same student as Nalin:', sacheth == nalin)\n",
    "print('Sacheth\\'s name comes before Nalin\\'s:', sacheth < nalin)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bba8a9a2",
   "metadata": {},
   "source": [
    "### 6.2 Inheritance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "67e8cec4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Write an ACMOfficer class that inherits the PrincetonStudent class. An ACMOfficer has every attribute\n",
    "# a PrincetonStudent has, and also a position and term expiration date. You'll only need to overwrite\n",
    "# the constructors to accommodate these two additions. Remember that you can still call the parent's \n",
    "# functions as subroutines.\n",
    "\n",
    "class ACMOfficer(PrincetonStudent):\n",
    "    # WRITE THE DETAILS OF YOUR CLASS HERE (also delete the 'pass keyword')\n",
    "    pass\n",
    "        \n",
    "# Test your PrincetonStudent class using this test suite. Feel free to write your own too!\n",
    "nalin = ACMOfficer('Nalin Ranjan', 'COS', '123456789', 2022, 'Chair', 2022)\n",
    "print(nalin, end=\"\\n\\n\")\n",
    "\n",
    "nalin.clubs.extend(['ACM', 'Taekwondo', 'Princeton Legal Journal', 'Badminton'])\n",
    "print(nalin, end=\"\\n\\n\")\n",
    "\n",
    "sacheth_clubs = ['ACM', 'Table Tennis']\n",
    "sacheth_prefs = ['WuCox', 'Whitman', 'Forbes', 'RoMa', 'CJL']\n",
    "sacheth = ACMOfficer.detailed_officer('Sacheth Sathyanarayanan', 'COS', '24681012', \n",
    "                                      2022, sacheth_clubs, sacheth_prefs, 'Treasurer', 2022)\n",
    "print(sacheth)\n",
    "\n",
    "print('Sacheth had a great meal at Whitman! It is now his favorite.\\n')\n",
    "sacheth.move_dhall_to_top('Whitman')\n",
    "print(sacheth)\n",
    "\n",
    "print('Sacheth is the same student as Nalin:', sacheth == nalin)\n",
    "print('Sacheth\\'s name comes before Nalin\\'s:', sacheth < nalin)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "983feed5",
   "metadata": {},
   "source": [
    "## Topic 7: Using Existing Python Libraries"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1355d3b2",
   "metadata": {},
   "source": [
    "Sigmoid activation functions are ubiquitous in machine learning. They all look somewhat like an S shape, starting\n",
    "out flat, and then somewhere in the middle jumping pretty quickly before leveling off. One example is the **Gudermannian Function**, which takes the form\n",
    "\n",
    "$$f(x, \\gamma) = \\gamma \\arctan \\left(\\tanh \\left( \\frac x \\gamma \\right) \\right)$$\n",
    "\n",
    "for some value $\\gamma$. You can think of $\\gamma$ as a parameter that specifies \"which\" Gudermannian function we're talking about. Can you plot the Gudermannian Function in the range $[-5, 5]$ with $\\gamma = \\{2, 4, 6\\}$? You will need access to `numpy` to find implementations of the arctan and tanh functions, and you will need `matplotlib` to create the actual plot.\n",
    "\n",
    "HINT: Since we have three different values of $\\gamma$, we'll have three different curves on the same graph."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d07cb104",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Numpy contains many mathematical functions/data analysis tools you might want to use\n",
    "import numpy as np\n",
    "\n",
    "# First: Write a function that returns the Gudermannian function evaluated at x.\n",
    "def gudermannian(x, gamma):\n",
    "    # PUT YOUR GUDERMANNIAN FUNCTION IMPLEMENTATION HERE (also delete the 'pass keyword')\n",
    "    pass\n",
    "\n",
    "# Next: use matplotlib to plot the function. HINT: Use matplotlib.pyplot\n",
    "from matplotlib import pyplot as plt # You'll refer to pyplot as plt from now on\n",
    "\n",
    "# HINT: pyplot requires that you have a set of x-values and a corresponding set of y-values.\n",
    "# To make your plot look like a continuous curve, just make your x-values close enough (say in\n",
    "# increments of 0.01). \n",
    "x_vals = ... # CHANGE THIS LINE OF CODE. You'll have to use numpy's arange function (Google it!)\n",
    "\n",
    "# Then, you'll have to make a set of y values for each gamma. HINT: If f(x) is a function\n",
    "# defined on a single number, then running it on x_vals evaluates the function at every x value\n",
    "# in x_vals. \n",
    "\n",
    "# EDIT THE FOLLOWING THREE LINES OF CODE (You may or may not want to add some of your own too.)\n",
    "plt.plot(...)\n",
    "plt.plot(...)\n",
    "plt.plot(...)\n",
    "\n",
    "# If you're done early, can you add a legend to your graph?"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
