{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/04_iteration/04_exercises.ipynb)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Chapter 4: Recursion & Looping (Coding Exercises)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The exercises below assume that you have read the [third part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/03_content.ipynb) of Chapter 4.\n", "\n", "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Throwing Dice" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this exercise, you will model the throwing of dice within the context of a guessing game similar to the one shown in the \"*Example: Guessing a Coin Toss*\" section in [Chapter 4 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/03_content.ipynb#Example:-Guessing-a-Coin-Toss).\n", "\n", "As the game involves randomness, we import the [random ](https://docs.python.org/3/library/random.html) module from the [standard library ](https://docs.python.org/3/library/index.html). To follow best practices, we set the random seed as well." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import random" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "random.seed(42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A die has six sides that we labeled with integers `1` to `6` in this exercise. For a fair die, the probability for each side is the same.\n", "\n", "**Q1**: Model a `fair_die` as a `list` object!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fair_die = ..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q2**: What function from the [random ](https://docs.python.org/3/library/random.html) module that we have seen already is useful for modeling a single throw of the `fair_die`? Write a simple expression (i.e., one function call) that draws one of the equally likely sides! Execute the cell a couple of times to \"see\" the probability distribution!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's check if the `fair_die` is indeed fair. To do so, we create a little numerical experiment and throw the `fair_die` `100000` times. We track the six different outcomes in a `list` object called `throws` that we initialize with all `0`s for each outcome.\n", "\n", "**Q3**: Complete the `for`-loop below such that it runs `100000` times! In the body, use your answer to **Q2** to simulate a single throw of the `fair_die` and update the corresponding count in `throws`!\n", "\n", "Hints: You need to use the indexing operator `[]` and calculate an `index` in each iteration of the loop. Do do not actually need the target variable provided by the `for`-loop and may want to indicate that with an underscore `_`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "throws = [0, 0, 0, 0, 0, 0]\n", "\n", "for ... in ...:\n", " ...\n", " ...\n", " ...\n", "\n", "throws" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`throws` contains the simulation results as absolute counts.\n", "\n", "**Q4**: Complete the `for`-loop below to convert the counts in `throws` to relative frequencies stored in a `list` called `frequencies`! Round the frequencies to three decimals with the built-in [round() ](https://docs.python.org/3/library/functions.html#round) function!\n", "\n", "Hints: Initialize `frequencies` just as `throws` above. How many iterations does the `for`-loop have? `6` or `100000`? You may want to obtain an `index` variable with the [enumerate() ](https://docs.python.org/3/library/functions.html#enumerate) built-in." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "frequencies = [0, 0, 0, 0, 0, 0]\n", "\n", "for ... in ...:\n", " ...\n", "\n", "frequencies" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q5**: How could we adapt the `list` object used above to model an `unfair_die` where `1` is as likely as `2`, `2` is twice as likely as `3`, and `3` is twice as likely as `4`, `5`, or `6`, who are all equally likely?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "unfair_die = ..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q6**: Copy your solution to **Q2** for the `unfair_die`! Execute the cell a couple of times to \"see\" the probability distribution!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q7**: Copy and adapt your solutions to **Q3** and **Q4** to calculate the `frequencies` for the `unfair_die`!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "throws = [0, 0, 0, 0, 0, 0]\n", "frequencies = [0, 0, 0, 0, 0, 0]\n", "\n", "for ... in ...:\n", " ...\n", " ...\n", " ...\n", "\n", "for ... in ...:\n", " ...\n", "\n", "frequencies" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q8**: The built-in [input() ](https://docs.python.org/3/library/functions.html#input) allows us to ask the user to enter a `guess`. What is the data type of the object returned by [input() ](https://docs.python.org/3/library/functions.html#input)? Assume the user enters the `guess` as a number (i.e., \"1\", \"2\", ...) and not as a text (e.g., \"one\")." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "guess = input(\"Guess the side of the die: \")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "guess" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q9**: Use a built-in constructor to cast `guess` as an `int` object!\n", "\n", "Hint: Simply wrap `guess` or `input(\"Guess the side of the die: \")` with the constructor you choose." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q10**: What type of error is raised if `guess` cannot be cast as an `int` object?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " < your answer >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q11**: Write a `try` statement that catches the type of error (i.e., your answer to **Q10**) raised if the user's input cannot be cast as an `int` object! Print out some nice error message notifying the user of the bad input!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "try:\n", " ...\n", "except ...:\n", " ..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q12**: Write a function `get_guess()` that takes a user's input and checks if it is a valid side of the die! The function should *return* either an `int` object between `1` and `6` or `None` if the user enters something invalid.\n", "\n", "Hints: You may want to re-use the `try` statement from **Q11**. Instead of printing out an error message, you can also `return` directly from the `except`-clause (i.e., early exit) with `None`. So, the user can make *two* kinds of input errors and maybe you want to model that with two *distinct* `return None` statements. Also, you may want to allow the user to enter leading and trailing whitespace that gets removed without an error message." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def get_guess():\n", " \"\"\"Process the user's input.\n", " \n", " Returns:\n", " guess (int / NoneType): either 1, 2, 3, 4, 5 or 6\n", " if the input can be parsed and None otherwise\n", " \"\"\"\n", " ...\n", "\n", " # Check if the user entered an integer.\n", " ...\n", " ...\n", " ...\n", " ...\n", "\n", " # Check if the user entered a valid side.\n", " ...\n", " ...\n", " ..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q13** Test your function for all *three* cases!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "get_guess()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q14**: Write an *indefinite* loop where in each iteration a `fair_die` is thrown and the user makes a guess! Print out an error message if the user does not enter something that can be understood as a number between `1` and `6`! The game should continue until the user makes a correct guess." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "...\n", "...\n", "...\n", "\n", "...\n", "...\n", "...\n", "...\n", "...\n", "...\n", "..." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.12.2" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": true, "skip_h1_title": true, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": false, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }