{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "l03-c000",
   "metadata": {},
   "source": [
    "# Lecture 3 - Conditions and logic\n",
    "\n",
    "**Authors:** Fiona McNeill, Matteo Degiacomi, Rayo Verweij, and Nigel Topham\n",
    "\n",
    "<!-- <a rel=\"license\" href=\"https://creativecommons.org/licenses/by/4.0/\" target=\"_blank\"><img alt=\"Creative Commons Licence\" style=\"border-width:0\" src=\"https://licensebuttons.net/l/by/4.0/88x31.png\" title=\"This work is licensed under a Creative Commons Attribution 4.0 International License.\" align=\"right\"/></a> -->\n",
    "\n",
    "## Introduction\n",
    "\n",
    "So far, our programs have followed every instruction in order. Here, we will start building programs that do different things based on whether certain conditions are true or false.\n",
    "\n",
    "### Learning outcomes\n",
    "\n",
    "In this notebook, we'll discuss:\n",
    "\n",
    "- constructing comparisons with `==`, `!=`, `<`, `<=`, `>`, and `>=`\n",
    "- combining Boolean values with `and`, `or`, and `not`\n",
    "- selecting one or more paths with `if`, `elif`, and `else`\n",
    "- using indentation to show which statements belong to a branch\n",
    "- recognising reserved keywords in Python\n",
    "\n",
    "### Using the notebook\n",
    "\n",
    "Remember, this notebook is _yours_! You can edit each cell, for example by adding new examples or changing values to see what happens. Feel free to experiment!\n",
    "\n",
    "A common approach for learning how to read and write code in a structured way is called **PRIMM**:\n",
    "1. **Predict**: before running the code, look at it - do you understand each line? What do you think will happen?\n",
    "2. **Run**: now run the code and see what output you get.\n",
    "3. **Investigate**: did it go as you thought it would? If not, can you figure out why?\n",
    "4. **Modify**: now change the code and once again try to predict the output. If you got it wrong the first time, did you get it right now?\n",
    "5. **Make**: finally, try to write your own program from scratch using the skills you learned.\n",
    "\n",
    "You can apply steps 1-4 to each code cell in the notebook and many will have prediction prompts to help you get started. In addition, there will be challenges that ask you to put everything together yourself and execute step 5. There will often be multiple ways to solve these, but each challenge has a potential answer listed.\n",
    "\n",
    "### Navigating the notebook\n",
    "\n",
    "A Jupyter notebook can be operated with your keyboard. Here is a **cheat sheet**:\n",
    "- To run the currently highlighted cell and move focus to the next cell, hold <kbd>&#x21E7; Shift</kbd> and press <kbd>&#x23ce; Enter</kbd>;\n",
    "- To run the currently highlighted cell and keep focus in the same cell, hold <kbd>&#x21E7; Ctrl</kbd> and press <kbd>&#x23ce; Enter</kbd>;\n",
    "- To create a cell under the one currently highlighted, press <kbd>B</kbd>;\n",
    "- To delete the currently highlighted cell, press <kbd>X</kbd> (be careful with this one!);\n",
    "- To get help for a specific function, place the cursor within the function's brackets, hold <kbd>&#x21E7; Shift</kbd>, and press <kbd>&#x21E5; Tab</kbd>.\n",
    "\n",
    "Watch out: **code cells remember what happened in cells before**. So, especially in the more complicated notebooks later down the line, make sure to always run **every** cell from top to bottom, as one might rely on a piece of code that came before it!\n",
    "\n",
    "## Further reading\n",
    "\n",
    "- [Python: `if` statements](https://docs.python.org/3/tutorial/controlflow.html#if-statements)\n",
    "- [Python: Boolean operations](https://docs.python.org/3/reference/expressions.html#boolean-operations)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b6636556",
   "metadata": {},
   "source": [
    "## 1. Comparison operators and Boolean values"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c001",
   "metadata": {},
   "source": [
    "So far, we have seen assignment and arithmetic operators. We'll start today with a third type: **comparison operators**. An expression with a comparison operator evaluates to one of two values: `True` or `False`.\n",
    "\n",
    "In Python, `True` and `False` are special values, that have the type **Boolean** or `bool`. They are named after George Boole, a 19th century English mathematician who first introduced logical operators.\n",
    "\n",
    "| Operator | Meaning |\n",
    "|---|---|\n",
    "| `==` | equal to |\n",
    "| `!=` | not equal to |\n",
    "| `<` | less than |\n",
    "| `<=` | less than or equal to |\n",
    "| `>` | greater than |\n",
    "| `>=` | greater than or equal to |\n",
    "\n",
    "**Predict:** Before running the code, what do you think will be printed on each line?\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-c002",
   "metadata": {},
   "outputs": [],
   "source": [
    "temperature = 12\n",
    "print(temperature < 15)\n",
    "print(temperature == 12)\n",
    "print(temperature != 12)\n",
    "print(type(temperature >= 10))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "546abe33",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-warning\">\n",
    "<b>Pay close attention: single and double equals</b>\n",
    "\n",
    "In mathematics, we are used to read `=` as 'is equal to'. However, in programming, this is usually not the case.\n",
    "\n",
    "Python, like most programming languages, uses the single equals sign `=` for *variable assignment*, whereas the double equals sign `==` is used for checking whether two values are the same. \n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "65d9f2a9-74a4-4c24-8e10-79ed6fe0bda4",
   "metadata": {},
   "source": [
    "### String comparisons\n",
    "\n",
    "There is a key difference between strings and numbers. When comparing numbers, Python compares their numerical size.\n",
    "However, when strings are compared, Python looks at where each character stands in the ***character encoding*** of the program. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4b62f9b5-6c56-416a-97c4-ab531b0e8443",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "<b>Note: character encoding</b>\n",
    "    \n",
    "Computers are calculators: ultimately, everything is expressed in numbers, so under the hood, each possible character is assigned a number in a long list. There exist many different encoding standards. A famous example is ***ASCII***, one of the oldest standards that many other modern character encodings build on or remain compatible with. In ASCII, the digits <code>0</code> to <code>9</code> are represented by the numbers 48-57; the uppercase letters <code>A</code> to <code>Z</code> by the numbers 65-90, and the lowercase letters <code>a</code> to <code>z</code> by the numbers 97-122, with punctuation marks and special characters taking up the numbers in between.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c003",
   "metadata": {},
   "source": [
    "When comparing strings, Python compares the numbers that the characters in the strings are represented by. Say that we ask\n",
    "\n",
    "```python\n",
    "\"apple\" < \"orange\"\n",
    "```\n",
    "\n",
    "These strings are encoded as `97 112 112 108 101` and `111 114 97 110 103 101`, respectively. For comparing strings, we just look at the starting characters. 97 is smaller than 111, so this expression evaluates to `True`.\n",
    "\n",
    "If the starting characters are the same, we move on to the next one.\n",
    "\n",
    "```python\n",
    "\"bee\" > \"bus\"\n",
    "```\n",
    "\n",
    "...evaluates to `False`, because `e` is represented by a smaller number than `u`.\n",
    "\n",
    "For equality, we have to check *every* character of the strings. For example, in\n",
    "\n",
    "```python\n",
    "\"McNeill\" == \"Mcneill\"\n",
    "```\n",
    "\n",
    "the strings are encoded as `77 99 78 101 105 108 108` and `77 99 110 101 105 108 108`, respectively. As these are not the same, the expression evaluates to `False`.\n",
    "\n",
    "You do **not** need to be able to encode and decode strings to their numerical representations. (The entire point of programming is to have computers do tedious work like this for us.) What you should know, however, is the following:\n",
    "\n",
    "1. Computers are able to work with text because they have a numerical representation of each character, called the encoding.\n",
    "2. While different computers use different types of encoding, practically speaking, digits virtually always have lower values than letters, and uppercase letters virtually always have lower values than lowercase letters.\n",
    "3. When comparing strings, programming languages do so by using these underlying encodings. \n",
    "\n",
    "Let's try it out ourselves.\n",
    "\n",
    "**Predict:** Find a notepad and write your predictions for each line before running it. After running the code once, change the values and operators to different ones to make sure you get a feel for how comparisons work."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-c004",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Rain\" == \"rain\")\n",
    "print(\"Appleton\" > \"Forum\")\n",
    "print(\"banana\" < \"KIWI\")\n",
    "\n",
    "print(\"3\" == 3)\n",
    "print(2.0 >= 2)\n",
    "print(str(5) == \"5\")\n",
    "\n",
    "print(type(1) != type(2))\n",
    "\n",
    "print(\"10\" < \"2\")\n",
    "print(10 < 2)\n",
    "print(10 < \"2\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c005",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "source": [
    "Note the final line: the less than and greater than operators only work on values of similar types. The equality operators, however, work across types.\n",
    "\n",
    "<div class=\"alert alert-success\">\n",
    "<b>Try it yourself: sorting alphabetically</b>\n",
    "\n",
    "You might wonder - why would we ever need string comparisons if it's just based on the underlying numerical representations? One of the most common use cases for it is to sort strings alphabetically. However, there is one snag: because of the way letters are encoded, Python first separates out letters by whether they are uppercase or lowercase before looking at their place in the alphabet.\n",
    "\n",
    "Based on the Python functionality you have seen so far, **how would you update the following piece of code** so that it checks a string's place in the alphabet *regardless* of whether it contains uppercase or lowercase characters?\n",
    "</div>\n",
    "\n",
    "<details>\n",
    "<summary><b>Click for a hint</b></summary>\n",
    "\n",
    "Stuck? Check the methods we discussed in the lecture 2 notebook for inspiration!\n",
    "\n",
    "</details>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-c006",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "# This piece of code checks whether some string input comes before \"ChEcKpOiNt\" in the alphabet\n",
    "base_text = \"ChEcKpOiNt\"\n",
    "user_text = input(\"Enter a string to compare: \")\n",
    "print(user_text < base_text)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c007",
   "metadata": {
    "tags": [
     "solution"
    ]
   },
   "source": [
    "<details>\n",
    "<summary><b>Click for a possible solution</b></summary>\n",
    "\n",
    "An easy way to do this is to convert both values to be either completely uppercase or lowercase. For example:\n",
    "\n",
    "```python\n",
    "base_text = \"ChEcKpOiNt\"\n",
    "user_text = input(\"Enter a string to compare: \")\n",
    "print(user_text.upper() < base_text.upper())\n",
    "```\n",
    "<br>\n",
    "Remember, <code>.upper()</code> and <code>.lower()</code> return a new string and leave the original unchanged. So if you wanted to use <code>base_text</code> or <code>user_text</code> for something else after the print statement, they would still have their original capitalisation.\n",
    "</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b3a0a604",
   "metadata": {},
   "source": [
    "## 2. Combining conditions"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c008",
   "metadata": {},
   "source": [
    "There is one final type of operator to introduce: the **logical operator**. Like comparison operators, logical operators evaluate to either `True` or `False`. They allow you to *combine* multiple statements that might be true or false.\n",
    "\n",
    "There are just three: `and`, `or`, and `not`. That's right - while some languages use symbols for these (like `&`), Python simply uses the words.\n",
    "\n",
    "- `A and B` is true only when **both** operands are true.\n",
    "- `A or B` is true when **at least one** operand is true.\n",
    "- `not A` reverses true and false.\n",
    "\n",
    "Just like in mathematical expressions, you can use parentheses to group statements that should be evaluated first.\n",
    "\n",
    "**Predict:** Once again, trace each line before running the following code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-c009",
   "metadata": {},
   "outputs": [],
   "source": [
    "has_ticket = True\n",
    "doors_open = False\n",
    "on_guest_list = True\n",
    "\n",
    "print(has_ticket and doors_open)\n",
    "print(has_ticket or doors_open)\n",
    "print(has_ticket or on_guest_list)\n",
    "print(not doors_open)\n",
    "print((has_ticket or on_guest_list) and doors_open)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c010",
   "metadata": {},
   "source": [
    "Now, here is where Python gets a little funky. In addition to `False`, Python also treats some non-Boolean values as false in a condition: specifically, `0`, `0.0`, and the empty string `\"\"`. Other numbers and non-empty strings are treated as true."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-c011",
   "metadata": {},
   "outputs": [],
   "source": [
    "alcohol_percentage = 0.0\n",
    "allergens = \"\"\n",
    "\n",
    "# Both of these count as false, so 'not' turns them into True\n",
    "print(not alcohol_percentage)\n",
    "print(not allergens)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6f33a9f",
   "metadata": {},
   "source": [
    "You can also convert these values to Boolean values using the `bool()` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a17387e9",
   "metadata": {},
   "outputs": [],
   "source": [
    "new_bool = bool(\"true\")\n",
    "print(type(new_bool))\n",
    "\n",
    "newer_bool = bool(0)\n",
    "print(type(newer_bool))\n",
    "\n",
    "surprising_bool = bool(\"false\")\n",
    "print(type(surprising_bool))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c012",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "source": [
    "<div class=\"alert alert-success\">\n",
    "<b>Try it yourself: combine access rules</b>\n",
    "\n",
    "Admission requires a valid card and either staff status or a booking. Use the three variables to print the condition for whether someone may enter or not.\n",
    "</div>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-c013",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "has_valid_card = True\n",
    "is_staff = False\n",
    "has_booking = True\n",
    "\n",
    "can_enter = ???\n",
    "print(can_enter)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c014",
   "metadata": {
    "tags": [
     "solution"
    ]
   },
   "source": [
    "<details>\n",
    "<summary><b>Click for a possible solution</b></summary>\n",
    "\n",
    "```python\n",
    "has_valid_card = True\n",
    "is_staff = False\n",
    "has_booking = True\n",
    "\n",
    "can_enter = has_valid_card and (is_staff or has_booking)\n",
    "print(can_enter)\n",
    "```\n",
    "</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb6017b9",
   "metadata": {},
   "source": [
    "## 3. Choosing paths with `if`, `elif`, and `else`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c015",
   "metadata": {},
   "source": [
    "An `if` statement connects a Boolean question to an action, allowing us to branch our program in different directions depending on whether conditions are true or false.\n",
    "\n",
    "`if` statements use the following syntax:\n",
    "\n",
    "```python\n",
    "if condition:\n",
    "  do_something()\n",
    "```\n",
    "\n",
    "The header starts with the keyword `if` and ends with a colon.\n",
    "\n",
    "The body is **indented**, that is, there is some blank space between the beginning of the line and the body of the `if` statement. Indentation marks which part of the code runs only as part of the `if` statement, and which part of the code runs regardless."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a20545fa-4c35-4d45-a4a2-23ef7d9e7836",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-warning\">\n",
    "<b>Pay close attention: indentation</b>\n",
    "\n",
    "In Python, indentation is not only used to help code readability: it is *meaningful*.\n",
    "You can indent text using either spaces (usually 2 or 4) or tabs, whichever you prefer. However, ***be consistent***: Python will throw an error if you mix spaces and tabs, or if you use a different number of spaces in the same block!\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9cdb4330-91e2-4340-9fbe-254b3b3e8ad8",
   "metadata": {},
   "source": [
    "**Predict:** What is printed when you run the following code? What would be printed if the value of `battery` is `30`, instead?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-c016",
   "metadata": {},
   "outputs": [],
   "source": [
    "battery = 18\n",
    "\n",
    "if battery < 20:\n",
    "    print(\"Charge soon!\")\n",
    "\n",
    "print(\"Battery check complete.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c017",
   "metadata": {},
   "source": [
    "We can define what will run in case the condition is false using the `else` keyword.\n",
    "\n",
    "Like the `if` statement, `else` is followed by a colon.\n",
    "\n",
    "Note the indentation in the following example.\n",
    "* `result = \"pass\"` is indented because it should only run under the `if` condition;\n",
    "* `else:` is back to the beginning of the line because it is part of the main program;\n",
    "* `result = \"fail\"` is indented again because it should only run under the `else` condition; and\n",
    "* the print statement is back to the beginning of the line because it should run regardless of the `if/else` conditions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-c018",
   "metadata": {},
   "outputs": [],
   "source": [
    "mark = 58\n",
    "\n",
    "if mark >= 40:\n",
    "    result = \"pass\"\n",
    "else:\n",
    "    result = \"fail\"\n",
    "\n",
    "print(f\"Result: {result}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c019",
   "metadata": {},
   "source": [
    "The `elif` keyword (else-if) allows us to add more mutually exclusive alternatives between `if` and `else`. *Python checks each condition from top to bottom and stops at the first branch that is true*, so put more specific or higher thresholds before broader or lower ones.\n",
    "\n",
    "**Predict:** What is printed when `mark` is `70`, or `60`, or `39`?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-c020",
   "metadata": {},
   "outputs": [],
   "source": [
    "mark = 70\n",
    "\n",
    "if mark >= 70:\n",
    "    band = \"distinction\"\n",
    "elif mark >= 60:\n",
    "    band = \"merit\"\n",
    "elif mark >= 40:\n",
    "    band = \"pass\"\n",
    "else:\n",
    "    band = \"fail\"\n",
    "\n",
    "print(f\"Result: {band}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c021",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "source": [
    "<div class=\"alert alert-success\">\n",
    "<b>Try it yourself: classifying temperatures</b>\n",
    "\n",
    "Write a program that labels a temperature below 5 as `cold`, from 5 up to but not including 15 as `cool`, from 15 up to but not including 25 as `mild`, and 25 or above as `warm`. Make sure you test the boundary values to check that you used the comparison operators correctly.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-c022",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "temperature = 15\n",
    "# Add the conditional and print the label"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c023",
   "metadata": {
    "tags": [
     "solution"
    ]
   },
   "source": [
    "<details>\n",
    "<summary><b>Click for a possible solution</b></summary>\n",
    "\n",
    "```python\n",
    "temperature = 15\n",
    "if temperature < 5:\n",
    "    label = \"cold\"\n",
    "elif temperature < 15:\n",
    "    label = \"cool\"\n",
    "elif temperature < 25:\n",
    "    label = \"mild\"\n",
    "else:\n",
    "    label = \"warm\"\n",
    "print(label)\n",
    "```\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d14715a",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "source": [
    "<div class=\"alert alert-success\">\n",
    "<b>Try it yourself: classifying time of day</b>\n",
    "\n",
    "One more round of practice. Ask for an integer hour from 0 to 23. Print `morning` for 5–11, `afternoon` for 12–17, `evening` for 18–22, and `night` otherwise. Also print an error message when the hour is outside 0–23.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a07acabb",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "# Write your code here"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a155313f",
   "metadata": {},
   "source": [
    "<details>\n",
    "<summary><b>Click for a possible solution</b></summary>\n",
    "\n",
    "However you have implemented your solution, make sure you print `night` both for the early hours (0-4) and for 23!\n",
    "\n",
    "```python\n",
    "hour = int(input(\"Enter an hour between 0 and 23: \"))\n",
    "\n",
    "if hour < 0 or hour > 23:\n",
    "    print(\"error: hour must be from 0 to 23\")\n",
    "elif hour >= 5 and hour <= 11:\n",
    "    print(\"morning\")\n",
    "elif hour <= 17:\n",
    "    print(\"afternoon\")\n",
    "elif hour <= 22:\n",
    "    print(\"evening\")\n",
    "else:\n",
    "    print(\"night\")\n",
    "```\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c1da17f-4395-486a-935f-6f6b2f6ce634",
   "metadata": {},
   "source": [
    "## 4. Common errors"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c024",
   "metadata": {},
   "source": [
    "Let's discuss some common errors when using conditions.\n",
    "\n",
    "### Assignment vs comparison\n",
    "\n",
    "Remember: `=` is for assignment and `==` for comparison. The following is **invalid** Python and will throw a `SyntaxError`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61bfa7b3-c2a7-41fd-9c30-6f7a9685585f",
   "metadata": {},
   "outputs": [],
   "source": [
    "if status = \"open\":\n",
    "    print(\"Come in\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "05164f91-f19e-4c4a-baa9-3011f1a06c6e",
   "metadata": {},
   "source": [
    "### Mistaken indentation\n",
    "\n",
    "These programs mean different things:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c6506ea5-2ac8-4120-b8a8-f98d747610d0",
   "metadata": {},
   "outputs": [],
   "source": [
    "raining = False\n",
    "\n",
    "if raining:\n",
    "    print(\"Take a coat\")\n",
    "    print(\"Check the forecast\")  # Only happens if raining == True\n",
    "\n",
    "if raining:\n",
    "    print(\"Take a coat\")\n",
    "print(\"Check the forecast\")      # Always runs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c4aa2f92-de47-4edd-9579-926787965a31",
   "metadata": {},
   "source": [
    "Remember to be consistent in your indentation!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a88c813f",
   "metadata": {},
   "outputs": [],
   "source": [
    "plant_name = \"rose\"\n",
    "  quantity = 3\n",
    "print(f\"I have {quantity} {plant_name}s\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f3acb43",
   "metadata": {},
   "source": [
    "If you use indentation where Python does not expect it, it will raise an `IndentationError`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c025",
   "metadata": {},
   "source": [
    "### Branch order and boundaries\n",
    "\n",
    "While this next piece of code does not contain a syntax error, it does contain a logic bug:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d2397726-c42c-412c-80b0-180755d07df3",
   "metadata": {},
   "outputs": [],
   "source": [
    "mark = 74\n",
    "\n",
    "if mark >= 40:\n",
    "    print(\"pass\")\n",
    "elif mark >= 70:\n",
    "    print(\"distinction\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9e8bf90-a766-4939-8b54-07d78ddf8321",
   "metadata": {},
   "source": [
    "`if` statements always follow the first condition that is satisfied. Because any mark that is greater than or equal to 70 is *also* greater than or equal to 40, no-one will ever get a distinction!\n",
    "\n",
    "When writing conditions, it can be useful to perform **boundary tests**. Run your code with values on the boundaries of your conditions, in this case, 39, 40, 69, and 70, to expose any faulty ordering or incorrect operator usage.\n",
    "\n",
    "<div class=\"alert alert-success\">\n",
    "<b>Try it yourself: repair a fare rule</b>\n",
    "\n",
    "A person aged under 5 travels free, a person under 18 pays £2.50, and everyone else pays £4... but that's not what the following code has implemented. Edit it to adhere to the rules and test your work with ages 4, 5, 17, and 18.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-c028",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "age = 17\n",
    "\n",
    "# Fix the code!\n",
    "if age <= 18:\n",
    "    fare = 2.5\n",
    "elif age <= 5:\n",
    "    fare = 0.0\n",
    "else:\n",
    "    fare = 4\n",
    "\n",
    "print(f\"Fare: £{fare:.2f}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-c029",
   "metadata": {
    "tags": [
     "solution"
    ]
   },
   "source": [
    "<details>\n",
    "<summary><b>Click for the solution</b></summary>\n",
    "\n",
    "Two mistakes needed to be corrected.\n",
    "1. The rules specified reduced fare for people *below* ages 5 and 18, not *below or at* these ages. Therefore, the operators needed to be `<` instead of `<=`.\n",
    "2. The second condition is never reached as 5 is lower than 18, so these needed to be swapped.\n",
    "\n",
    "```python\n",
    "age = 17\n",
    "\n",
    "if age < 5:\n",
    "    fare = 0.0\n",
    "elif age < 18:\n",
    "    fare = 2.5\n",
    "else:\n",
    "    fare = 4.0\n",
    "\n",
    "print(f\"Fare: £{fare:.2f}\")\n",
    "```\n",
    "</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51beedb5-4474-44a0-9217-38a1825de9c2",
   "metadata": {},
   "source": [
    "## 5. Reserved keywords"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6356f96d",
   "metadata": {},
   "source": [
    "One final note. In this lecture, we have introduced a few **keywords**: words in Python that take on specific functionality, such as `if`, `elif`, `else`, `and`, `or`, and `not`.\n",
    "\n",
    "Keywords differ from *functions* (like `print()`, `input()`, and `type()`) in that functions always use parentheses, whereas keywords don't.\n",
    "\n",
    "Keywords are **reserved** in Python. This means that you cannot name your variables after any!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9d0ade56",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Invalid code!\n",
    "else = 2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19823447",
   "metadata": {},
   "source": [
    "There are not many keywords, so this is not usually an issue when coding, and we will see most of them over the course of this semester.\n",
    "\n",
    "For a full list of keywords, see [Python keywords on W3Schools](https://www.w3schools.com/python/python_ref_keywords.asp)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "70bf4dfc",
   "metadata": {},
   "source": [
    "## Consolidation challenge"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-consolidation-prompt",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "source": [
    "If you worked through lecture 1's self-guided notebook, you might remember our catering business *Algorithmic Appetites*. Unfortunately, due to its inability to cater to people's dietary requirements, it was sued under the 2010 Equality Act and went out of business. But no reason to panic: we'll just start a new one!\n",
    "\n",
    "<div class=\"alert alert-success\">\n",
    "<b>Try it yourself: creating a menu based on dietary requirements</b>\n",
    "    \n",
    "Here at *Conditional Cuisines* we are going to go the extra mile and **generate a personalised menu** for people based on their dietary requirements. Our menu looks like this:\n",
    "\n",
    "**Starters**\n",
    "* Default: haggis bites with mango chutney\n",
    "* For vegetarians: one large veggie samosa\n",
    "\n",
    "**Mains**\n",
    "* Default: steak and ale pie\n",
    "* For those with gluten allergies: salmon with asparagus and new potatoes\n",
    "* For vegetarians: goat cheese salad with croutons\n",
    "* For vegetarians with gluten allergies: goat cheese salad WITHOUT croutons\n",
    "\n",
    "**Dessert**\n",
    "* Cranachan\n",
    "* For those with gluten allergies: a slightly sad scoop of vanilla ice cream\n",
    "\n",
    "Create a program that asks a user for their dietary requirements and prints out their menu as a single string.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l03-consolidation-work",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "# Your answer here!\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-consolidation-solution",
   "metadata": {
    "tags": [
     "solution"
    ]
   },
   "source": [
    "<details><summary><b>Click for a possible solution</b></summary>\n",
    "\n",
    "Our version uses three different `if` statements. Alternatively, you could use one statement that sets the starter, main, and dessert all at once. How you go about it is up to you!\n",
    "\n",
    "```python\n",
    "# Get user input\n",
    "is_veggie_text = input(\"Are you vegetarian? (yes/no) \")\n",
    "has_gluten_allergy_text = input(\"Are you allergic to gluten? (yes/no) \")\n",
    "\n",
    "# Convert the input to booleans we can use\n",
    "# Let's make sure it doesn't matter whether the user used capital letters or not\n",
    "if is_veggie_text.upper() == \"YES\":\n",
    "    is_veggie = True\n",
    "else:\n",
    "    is_veggie = False\n",
    "\n",
    "if has_gluten_allergy_text.upper() == \"YES\":\n",
    "    has_gluten_allergy = True\n",
    "else:\n",
    "    has_gluten_allergy = False\n",
    "\n",
    "# Determine the dishes served\n",
    "if is_veggie:\n",
    "    starter = \"one large veggie samosa\"\n",
    "else:\n",
    "    starter = \"haggis bites with mango chutney\"\n",
    "\n",
    "if is_veggie and has_gluten_allergy:\n",
    "    main = \"goat cheese salad WITHOUT croutons\"\n",
    "elif is_veggie:\n",
    "    main = \"goat cheese salad with croutons\"\n",
    "elif has_gluten_allergy:\n",
    "    main = \"salmon with asparagus and new potatoes\"\n",
    "else:\n",
    "    main = \"steak and ale pie\"\n",
    "\n",
    "if has_gluten_allergy:\n",
    "    dessert = \"a slightly sad scoop of vanilla ice cream\"\n",
    "else:\n",
    "    dessert = \"cranachan\"\n",
    "\n",
    "# Print the result\n",
    "print(f\"Welcome to Conditional Cuisines! Tonight, you will first receive {starter}, then our delicious {main}, and finally {dessert} to end the night. Enjoy!\")\n",
    "```\n",
    "</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l03-consolidation-summary",
   "metadata": {
    "tags": [
     "summary"
    ]
   },
   "source": [
    "## Summary\n",
    "\n",
    "Well done! In order to cover conditions we also had to cover some fundamental computer science topics around logic and text encoding. You'll encounter these again in more detail in future Informatics courses but for now, you are starting to build a good understanding of the basics of programming.\n",
    "\n",
    "### Key terms\n",
    "\n",
    "<dl>\n",
    "\t<dt><b>Boolean</b></dt>\n",
    "\t<dd>A type of value that is either true or false.</dd>\n",
    "\t<dt><b>Indentation</b></dt>\n",
    "\t<dd>Whitespace at the beginning of lines of code that, in Python, groups pieces of code together.</dd>\n",
    "\t<dt><b>Boundary test</b></dt>\n",
    "\t<dd>When writing an if statement using numbers, a test that checks the statement by using values that are on the boundaries of the conditions.</dd>\n",
    "\t<dt><b>Character encoding</b></dt>\n",
    "\t<dd>The numerical representation of characters that computers use to process them, for example when comparing strings.</dd>\n",
    "\t<dt><b>Reserved keyword</b></dt>\n",
    "\t<dd>A word with special functionality in Python that cannot be used as a variable name.</dd>\n",
    "</dl>\n",
    "\n",
    "### New syntax\n",
    "\n",
    "<dl>\n",
    "\t<dt><code>True</code> and <code>False</code></dt>\n",
    "\t<dd>Boolean values in Python. Remember to capitalise them!</dd>\n",
    "\t<dt><code>bool</code> and <code>bool()</code></dt>\n",
    "\t<dd>The Boolean type in Python and the function to convert a value to the <code>bool</code> type in Python, respectively.</dd>\n",
    "\t<dt><code>==</code> and <code>!=</code></dt>\n",
    "\t<dd>Equal to and not equal to comparison operators. Works across types.</dd>\n",
    "\t<dt><code><</code>, <code><=</code>, <code>></code>, <code>>=</code></dt>\n",
    "\t<dd>Less than; less than or equal to; greater than; and greater than or equal to comparison operators. Only work when their operands are of similar types.</dd>\n",
    "\t<dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n",
    "\t<dd>Logic operators that combine Boolean expressions.</dd>\n",
    "\t<dt><code>if</code>, <code>elif</code>, <code>else</code></dt>\n",
    "\t<dd>Keywords that define if statements and their branches. Remember that for each branch, the head ends with a colon and the body is indented.</dd>\n",
    "    <dt><code>SyntaxError</code></dt>\n",
    "\t<dd>A type of error that highlights when you break the rules of Python, such as naming a variable after a reserved keyword or attempting to assign a variable as part of a condition (by using <code>=</code> instead of <code>==</code>, for example).</dd>\n",
    "\t<dt><code>IndentationError</code></dt>\n",
    "\t<dd>A type of error that highlights when you misuse indentation.</dd>\n",
    "</dl>\n"
   ]
  }
 ],
 "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.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
