diff --git a/assessments/primer.ipynb b/assessments/primer.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..952dcb185da4fb6f95404359dc3ff5f6ab740fb6 --- /dev/null +++ b/assessments/primer.ipynb @@ -0,0 +1,283 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b1b675fc-7aff-4c5c-b0e7-bb785817e979", + "metadata": {}, + "source": [ + "# Primer\n", + "\n", + "In this assessment, you'll implement, document, and test a variety of unrelated functions to demonstrate your ability to apply control structures and data structures to solve problems involving numbers, text, and files. There's no realistic data science motivation or context for this assignment: it's just a grab-bag of questions. Future assessments will have more context.\n", + "\n", + "For each question, you'll be asked to *write a function*, **document it** with a docstring, and **test** it with doctests added in the docstring. We've provided several input-output examples for each function.\n", + "\n", + "The `run_docstring_examples` function call will *not* print anything if the function *passes all* the doctests you defined. \n", + "\n", + "To fulfill the documentation requirements, use your own words to provide a brief description of only the details that a client needs to know to call the function. To fulfill testing requirements, convert each provided example into a doctest and **additionally write 2 more test cases of your own**. Be ready to justify and explain the design of all your work: how and why did you write each line of code?" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "582de7ad-4a48-4ce6-9896-de32b31483d8", + "metadata": {}, + "outputs": [], + "source": [ + "import doctest" + ] + }, + { + "cell_type": "markdown", + "id": "31845b38-3323-4dee-b1a1-1734af326c9e", + "metadata": {}, + "source": [ + "## Collaboration and Conduct\n", + "\n", + "Students are expected to follow Washington state law on the [Student Conduct Code for the University of Washington](https://www.washington.edu/admin/rules/policies/WAC/478-121TOC.html). In this course, students must:\n", + "\n", + "- Indicate on your submission any assistance received, including materials distributed in this course.\n", + "- Not receive, generate, or otherwise acquire any substantial portion or walkthrough to an assessment.\n", + "- Not aid, assist, attempt, or tolerate prohibited academic conduct in others.\n", + "\n", + "Update the following code cell to include your name and list your sources. If you used any kind of computer technology to help prepare your assessment submission, include the queries and/or prompts. Submitted work that is not consistent with sources may be subject to the student conduct process." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "1faa1411-4de6-4b17-99af-7586f56c1973", + "metadata": {}, + "outputs": [], + "source": [ + "your_name = \"\"\n", + "sources = [\n", + " ...\n", + "]\n", + "\n", + "assert your_name != \"\", \"your_name cannot be empty\"\n", + "assert ... not in sources, \"sources should not include the placeholder ellipsis\"\n", + "assert len(sources) >= 2, \"must include at least 2 sources, inclusive of lectures and sections\"" + ] + }, + { + "cell_type": "markdown", + "id": "2696e23b-d964-4c2a-844b-602c69ed3952", + "metadata": {}, + "source": [ + "## Task: `is_relatively_prime`\n", + "\n", + "Write and test a function `is_relatively_prime` that takes two integer numbers `n` and `m` and returns `True` if and only if `n` and `m` are relatively prime to each other. Two numbers are relatively prime if they share no common factors besides 1. (1 is relatively prime with every number.) Assume the value of `n` and `m` are at least 1.\n", + "\n", + "- `is_relatively_prime(12, 13)` returns `True` since the factors of 12 are 1, 2, 3, 4, 6, 12 and the factors of 13 are 1, 13.\n", + "- `is_relatively_prime(12, 14)` returns `False` since the factors of 12 are 1, 2, 3, 4, 6, 12 and the factors of 14 are 1, 2, 7, 14.\n", + "- `is_relatively_prime(5, 9)` returns `True` since the factors of 5 are 1, 5 and the factors of 9 are 1, 3, 9.\n", + "- `is_relatively_prime(8, 9)` returns `True` since the factors of 8 are 1, 2, 4, 8 and the factors of 9 are 1, 3, 9.\n", + "- `is_relatively_prime(8, 1)` returns `True` since we define that 1 is relatively prime with every number.\n", + "\n", + "Do not use data structures to store factors during the execution of the algorithm, and use a single loop rather than nested loops." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "da1c4734-5a86-4db8-86b7-8c6e1da96594", + "metadata": {}, + "outputs": [], + "source": [ + "...\n", + "\n", + "doctest.run_docstring_examples(is_relatively_prime, globals())" + ] + }, + { + "cell_type": "markdown", + "id": "01fa76ba-c51c-4013-a72a-0dc6f1dd78b0", + "metadata": {}, + "source": [ + "## Task: `travel`\n", + "\n", + "Write and test a function `travel` that takes a string of north/east/south/west directions and a `tuple` indicating the starting `x, y` location on a grid. This function should return a `tuple` that indicates the new position after following the directions starting from the starting `x, y` location. The returned tuple should be in the format `(x_new, y_new)`. Assume we use integer coordinates where each direction increments or decrements a coordinate by 1.\n", + "\n", + "The directions string will use `\"N\"` to indicate increasing the y-coordinate, `\"E\"` to indicate increasing the x-coordinate, `\"S\"` to indicate decreasing the y-coordinate, and `\"W\"` to indicate decreasing the x-coordinate. The case of the characters should be ignored. You can assume that `x` and `y` are both of type `int`. Any characters that are not `\"N\"`, `\"E\"`, `\"W\"`, or `\"S\"` (ignoring letter-casing) should be ignored.\n", + "\n", + "`travel(\"NW!ewnW\", (1, 2))` should return the tuple `(-1, 4)` following this sequence of movements:\n", + "\n", + "1. Start at `(1, 2)`.\n", + "1. Move `\"N\"` to `(1, 3)`.\n", + "1. Move `\"W\"` to `(0, 3)`.\n", + "1. Ignore `\"!\"` since it is not a valid direction.\n", + "1. Move `\"e\"` to `(1, 3)`.\n", + "1. Move `\"w\"` to `(0, 3)`.\n", + "1. Move `\"n\"` to `(0, 4)`.\n", + "1. Move `\"W\"` to `(-1, 4)`." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0c0eb1fd-4408-4b02-a1b4-9c3950e0fbc1", + "metadata": {}, + "outputs": [], + "source": [ + "...\n", + "\n", + "doctest.run_docstring_examples(travel, globals())" + ] + }, + { + "cell_type": "markdown", + "id": "7fee7b98-b53e-4d13-9a07-51a4c447a6a3", + "metadata": {}, + "source": [ + "## Task: `longest_token`\n", + "\n", + "Write and test a function `longest_token` that takes a string file path and returns a `tuple` of the longest token in the file and the line it appears on.\n", + "\n", + "A **token** is a sequence of characters separated by whitespace. If there are ties for the longest token, return the one that appears first in the file. If the file does not exist, the file is empty, or the file only contains whitespace, behavior is **undefined**: your program may do anything, including crash or throw an exception.\n", + "\n", + "For example, if we have a file `song.txt` with the following contents.\n", + "\n", + "```\n", + "Row, row, row your boat\n", + "Gently down the stream\n", + "Merrily, merrily, merrily, merrily\n", + "Life is but a dream!\n", + "```\n", + "\n", + "`longest_token(\"song.txt\")` should return `(\"Merrily,\", 3)`.\n", + "\n", + "To write additional test cases, create new text files. From the JupyterLab **File** menu, choose **New** and then **Text File**." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "4511b55d-372e-4316-8749-605b011f3502", + "metadata": {}, + "outputs": [], + "source": [ + "...\n", + "\n", + "doctest.run_docstring_examples(longest_token, globals())" + ] + }, + { + "cell_type": "markdown", + "id": "924a8f2d-8126-4b40-b388-3e0e5238f91c", + "metadata": {}, + "source": [ + "## Task: `reformat_date`\n", + "\n", + "Write and test a function `reformat_date` that takes three strings: a date string, an input date format, and an output date format. This function should return a new date string formatted according to the output date format.\n", + "\n", + "A **date string** is a non-empty string of numbers separated by `/`, such as `\"2/20/1991\"` or `\"1991/02/20\"`. The order of date fields (month, day, year) will depend on the date format, and the number of digits for each field can vary but there must be at least one digit for each field.\n", + "\n", + "A **date format** is a non-empty string of the date symbols `\"D\"`, `\"M\"`, `\"Y\"` separated by `/`. Assume the date string will match the date formats (share the same number of `/`s), that any date symbol in the output date format will also appear in the input date format, and that date formats do not duplicate date symbols.\n", + "\n", + "- `reformat_date(\"12/31/1998\", \"M/D/Y\", \"D/M/Y\")` returns `\"31/12/1998\"`.\n", + "- `reformat_date(\"1/2/3\", \"M/D/Y\", \"Y/M/D\")` returns `\"3/1/2\"`.\n", + "- `reformat_date(\"0/200/4\", \"Y/D/M\", \"M/Y\")` returns `\"4/0\"`.\n", + "- `reformat_date(\"3/2\", \"M/D\", \"D\")` returns `\"2\"`.\n", + "\n", + "The following calls do not satisfy the date string or date format requirements, so their behavior is undefined. You *do not* need to validate or test these cases.\n", + "\n", + "- `reformat_date(\"3/2\", \"M/D/Y\", \"Y/M/D\")` date string and input date format do not match.\n", + "- `reformat_date(\"3/2\", \"M/D\", \"Y/M/D\")` input date format missing a field present in the output date format.\n", + "- `reformat_date(\"1/2/3/4\", \"M/D/Y/S\", \"M/D\")` input date format contains a field that is not `\"D\"`, `\"M\"`, `\"Y\"`.\n", + "- `reformat_date(\"1/2/3\", \"M/M/Y\", \"M/Y\")` input date format contains a duplicate date symbol.\n", + "- `reformat_date(\"\", \"\", \"\")` date strings and date formats must be non-empty strings." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "881eb6e8-1c80-4767-8749-f1acb3b05c7e", + "metadata": {}, + "outputs": [], + "source": [ + "...\n", + "\n", + "doctest.run_docstring_examples(reformat_date, globals())" + ] + }, + { + "cell_type": "markdown", + "id": "cde2ec0c-2bdd-4a39-bc9e-0d46c381905d", + "metadata": {}, + "source": [ + "## Task: `most_frequent`\n", + "\n", + "Write and test a function `most_frequent` that takes a list of integers and returns the integer value that appears most frequently in the list. If there is more than one most frequent integer, return the one that appears first in the sequence. Assume the list has at least 1 value.\n", + "\n", + "- `most_frequent([1, 2, 1, 2, 1])` returns `1`.\n", + "- `most_frequent([0])` returns `0`.\n", + "- `most_frequent([-1, 2, 2])` returns `2`.\n", + "- `most_frequent([1, 2, 1, 1, 2, 3, 2, 2, 3, 1])` returns `1`." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "f4c14419-ffaf-4b39-af00-4e6df619fcdc", + "metadata": {}, + "outputs": [], + "source": [ + "...\n", + "\n", + "doctest.run_docstring_examples(most_frequent, globals())" + ] + }, + { + "cell_type": "markdown", + "id": "709784fd-5998-4f1a-a4ca-820de521f0f5", + "metadata": {}, + "source": [ + "## Testing\n", + "\n", + "Double check that **each task has 2 of your own additional test cases**." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "20b5051d-2f6c-440d-a44a-1b5911334eb6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "TestResults(failed=0, attempted=25)\n" + ] + } + ], + "source": [ + "test_results = doctest.testmod()\n", + "print(test_results)\n", + "assert test_results.failed == 0, \"There are failed doctests.\"\n", + "assert test_results.attempted >= 25, \"Total number of doctests should be at least 25; less than 25 means you did not add two additional test cases per task.\"" + ] + } + ], + "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.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/assessments/song.txt b/assessments/song.txt new file mode 100644 index 0000000000000000000000000000000000000000..08f422c55465e5c75d1bb035e2e0a1417b005a17 --- /dev/null +++ b/assessments/song.txt @@ -0,0 +1,4 @@ +Row, row, row your boat +Gently down the stream +Merrily, merrily, merrily, merrily +Life is but a dream! \ No newline at end of file