{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "After working through the exercises in this notebook you should be familiar with Python variables, indexing, [for loops][for], and [if statements][if].\n", "\n", "[for]: http://docs.python.org/2/reference/compound_stmts.html#the-for-statement\n", "[if]: http://docs.python.org/2/reference/compound_stmts.html#the-if-statement" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from ipythonblocks import BlockGrid, colors, show_color, show_color_triple" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[IPython help features](https://jakevdp.github.io/PythonDataScienceHandbook/01.01-help-and-documentation.html)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "BlockGrid?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These blocks with `In[ ]:` and `Out[ ]:` next to them are \"cells\". Jupyter \"echos\" whatever is on the last line of a cell." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "BlockGrid(4, 5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use an `=` to assign something (on the right side of the `=`) to the name you want it to have (on the left side of the `=`)." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "grid = BlockGrid(5, 5, fill=colors.RosyBrown)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`grid.show()` is another way to get a grid displayed, it's especially useful if you can't echo the grid on the last line of a cell.\n", "\n", "`.show` is a \"method\" on the `grid` instance. It's like a function attached to this particular grid. Note the parentheses used to \"call\" the method (and to call the `BlockGrid` above when making `grid`)." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "grid.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `show_color` and `show_color_triple` functions are useful for previewing colors. The `colors` object/dictionary has a bunch of useful preset colors." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_color_triple(colors.Bisque)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Color(red=240, green=248, blue=255)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "colors.AliceBlue" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When pulling an individual block out of a grid use square brackets and specify a row and column:\n", "`grid[row_index, column_index`.\n", "Python is zero-indexed." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "Block(188, 143, 143, size=20)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block = grid[0, 0]\n", "block" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`.rgb` is an \"attribute\" of blocks that has the \"red, green, blue\" values of the color of the block.\n", "These these integers can have values from 0 - 255 and the combination of the three specifies the color of the block." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(188, 143, 143)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block.rgb" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can assign a new triplet of color integers to the `.rgb` attribute to change the color of a block." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "Block(240, 248, 255, size=20)" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block.rgb = colors.AliceBlue\n", "block" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see further information about a block using the `print` and `type` functions." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Block [0, 0]\n", "Color: (240, 248, 255)\n" ] } ], "source": [ "print(block)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "ipythonblocks.Block" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(block)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that changing the color of the block variable above also changed the color of the block in the grid.\n", "When we ran `block = grid[0, 0]` above we created a new name (`block`) that referenced the top-left cell\n", "of the grid. We did _not_ make a copy of that block." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We could also change the color of the top-left block without first pulling it into a variable." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid[0, 0].rgb = colors.Cyan\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note also that assigning the `grid` variable to a new variable (`new_grid` here) there is still _no copy_. Modifying `new_grid` modifies the original `grid` as well because they are different names for the same thing." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "new_grid = grid\n", "new_grid[1, 1].rgb = colors.DarkCyan\n", "grid" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid[2, 2] = colors.FireBrick\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `grid` object doesn't have a `.rgb` attribute.\n", "Python lets you create one by assigning something to it, but nothing happens to the appearance of the grid." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid.rgb = colors.Gold\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 2: \"Change the color of the block in the third row and fourth column.\"" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid[2, 3].rgb = colors.Black\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 3: \"Change the color of the block in the lower-right corner of the grid.\"" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "grid[4, 4].rgb = colors.Teal" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python also supports negative indexing, allowing you to index into the ends of containers without knowing\n", "how big they are.\n", "Index `-1` is the last item, index `-2` is the second-to-last item, etc." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid[-1, -1].rgb = colors.Violet\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you wanted to show two or more grids in the output of a notebook cell you could use the `.show()` method." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "grid.show()\n", "new_grid.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 4: \"Use negative indexing to change the color of the block in the second row\n", "and first column.\"" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid[-4, -5].rgb = colors.Wheat\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loops\n", "\n", "Python's `for thing in container:` syntax lets you iterate over whatever is in `container`.\n", "But, note that what exactly this means varies depending on what `container` is.\n", "In the case of our grids, each iteration of the loop gives us one of the blocks from the grid.\n", "\n", "As an example we could change the color of every block in the grid using a loop." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "for block in grid:\n", " block.rgb = colors.HotPink\n", " \n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 5: \"Use a `for` loop to change the color of every block in your grid.\"\n", "\n", "The `.animate()` method will show you the state of grid as the loop runs.\n", "(But you'll only see the final state of the grid after the loop if you're reading this later.)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for block in grid.animate():\n", " block.rgb = colors.Honeydew" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ifs\n", "\n", "`if` statements allow us to only execute code when a given condition is true.\n", "The `==` comparator checks whether two things are equal.\n", "Don't get it confused with the single `=` used for assignment!" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for block in grid.animate():\n", " if block.row == 2:\n", " block.rgb = colors.PapayaWhip" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How would I figure out that blocks had a `.row` attribute?\n", "I could use the `?` help feature to read the docstring or use `block.` to see available methods\n", "and attributes.\n", "But, note that `block.` only works if block is an existing variable with something assigned to it\n", "when you press tab. That's not the case when writing the loop above." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "block = grid[0, 0]\n", "block?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 6: \"Use a `for` loop and an `if` statement to change the color of every block\n", "in the fourth *column* of your grid.\"\n", "\n", "Blocks also have a `.col` attribute that has the column index of the block." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for block in grid.animate():\n", " if block.col == 3:\n", " block.rgb = colors.Magenta" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`elif` and `else` allow us to write separate blocks of code that run under different conditions.\n", "Only one of these branches will run for each `block` in the grid.\n", "`else` applies to anything not matched by an `if` or `elif` above it." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for block in grid.animate():\n", " if block.row == 0:\n", " block.rgb = colors.Black\n", " elif block.row == 2:\n", " block.rgb = colors.White\n", " else:\n", " block.rgb = colors.Blue" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 7: \"Augment your code from Exercise 6 with an `elif` and an `else` to change the\n", "color of all blocks in your grid. But make the second column red, the\n", "third column green, and all the other blocks gold.\"" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for block in grid.animate():\n", " if block.col == 1:\n", " block.rgb = colors.Red\n", " elif block.col == 2:\n", " block.rgb = colors.Green\n", " else:\n", " block.rgb = colors.Gold" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other Python comparators:\n", "\n", "- `<` less than\n", "- `<=` less than or equal\n", "- `>` greater than\n", "- `>=` greater than or equal\n", "- `!=` not equal" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`and` and `or` allow us to construct more complicated `if` expressions.\n", "When using `or` only one of the conditions needs to be true for the branch to be executed." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for block in grid.animate():\n", " if block.col == 2 or block.col == 4:\n", " block.rgb = colors.Khaki" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 8: \"Use an `if` with an `or` to change the color of the blocks in the first\n", "and fifth rows to black.\"" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for block in grid.animate():\n", " if block.row == 0 or block.row == 4:\n", " block.rgb = colors.Black" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we want to make checks on the _color_ of the blocks here are some different ways to do that." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [], "source": [ "block = grid[1, 1]" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(255, 0, 0)" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block.rgb" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block.rgb == (255, 0, 0)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block.rgb == colors.Red" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "255" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block.red" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block.blue" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 9: \"Use an `if` with an `and` condition to turn every block that is in the\n", "fourth column AND black to blue.\"\n", "\n", "When using `and` both of the conditions must be true in order for the branch to be executed." ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for block in grid.animate():\n", " if block.col == 3 and block.rgb == colors.Black:\n", " block.rgb = colors.Blue" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can use parentheses to specify an order of operations for `if` conditions.\n", "Absent parentheses `or` and `and` will be combined left to right." ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for block in grid.animate():\n", " if (block.col == 1 or block.col == 2) and block.rgb == colors.Black:\n", " block.rgb = colors.Blue" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `range`\n", "\n", "Sometimes we don't need to loop over every block in a grid because we know ahead of time we're\n", "only interested in some subset of them.\n", "The `range` function can help construct a sequence of integer values to use as indices while in the loop.\n", "[`range` documentation](https://docs.python.org/3.8/library/stdtypes.html#range)\n", "\n", "Note: the `stop` argument to range is not included in the result!" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "2\n", "3\n", "4\n" ] } ], "source": [ "for index in range(5):\n", " print(index)" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n", "6\n", "7\n" ] } ], "source": [ "for index in range(5, 8):\n", " print(index)" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n", "8\n", "11\n", "14\n" ] } ], "source": [ "for index in range(5, 15, 3):\n", " print(index)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we want to change the color of every block in the 2nd row, so we loop over a `range` that encompasses\n", "all the columns in the grid." ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "for column_index in range(grid.width):\n", " grid[1, column_index].rgb = colors.Orange\n", "\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 10: \"Make a new 20 by 20 block grid. Use a `for` loop with `range` to change the\n", "color of every block in the third, 10th, and 18th rows.\"\n", "\n", "Note the use of `grid.flash()` to briefly show the grid at each iteration since we're no longer\n", "using `grid.animate()`. We also need to echo `grid` on the last line (or use `grid.show()`\n", "after the loop) in order to see the final result." ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [], "source": [ "grid = BlockGrid(20, 20)" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "for column_index in range(grid.width):\n", " grid[2, column_index].rgb = colors.YellowGreen\n", " grid[9, column_index].rgb = colors.YellowGreen\n", " grid[17, column_index].rgb = colors.YellowGreen\n", " grid.flash()\n", "\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An alternate way of doing this is to have nested loops, the outer one for the columns we want to change and\n", "the inner one for the rows we want to change.\n", "Note that the `[2, 9, 17]` is a list with the row indices.\n", "(We can't use `range` for the row indices because they aren't evenly spaced.)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "for column_index in range(grid.width):\n", " for row_index in [2, 9, 17]:\n", " grid[row_index, column_index].rgb = colors.Indigo\n", " grid.flash()\n", "\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 11: \"Use nested `for` loops with `range` to change the color of the bottom-left\n", "quadrant of your 20 by 20 grid.\"\n", "\n", "Here we use some math instead of hard-coding the row and column indexes in our calls to `range`.\n", "The `//` operator does floor division, returning an integer and discarding any fractional component of the result\n", "(needed because `range` doesn't work with floating point inputs and `/` always returns a float)." ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "for row_index in range(grid.height // 2, grid.height):\n", " for column_index in range(0, grid.width // 2):\n", " grid[row_index, column_index].rgb = colors.LavenderBlush\n", "\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `int` function will try to convert an input to an integer, it also truncates the input (does not round)." ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int(2.3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Slicing\n", "\n", "Slicing is an abbreviated, inline way of specifying a subset of a Python container.\n", "The syntax of a slice is `start:stop:step`, but not all of those are required.\n", "\n", "In this first example `5:15` means \"from the 5th index up to but not including the 15th index\"." ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid[5:15, 5:15]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When the start or stop of a slice is not specified it means \"from the beginning\" or \"until the end\", respectively." ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid[:5, 15:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A lone `:` means \"include everything along this dimension\" (in this case all the columns)." ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid[:5, :]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can assign a color to a slice of a grid to change the color of all the blocks in that slice." ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid[:5, :] = colors.Crimson\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 12: \"Try to get the same affects as in Exercises 10 & 11, but using slicing instead\n", "of `for` loops.\"" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid[2, :] = colors.Thistle\n", "grid[9, :] = colors.Tomato\n", "grid[17, :] = colors.Turquoise\n", "grid[-10:, :10] = colors.Blue\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Slicing also supports specifying a step-size, very similar to `range`.\n", "Here `1::2` means \"start at the first index, go through the end, and include every 2nd index\"." ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid[1::2, :] = colors.Teal\n", "grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functions\n", "\n", "Functions are one way to package code and re-use it again and again.\n", "Note the `def` keyword indicating we're writing a function, the name of the function\n", "(here `fahr_to_celsius`), the parentheses, and the list of arguments inside the paretheses.\n", "\n", "The `return` statement is used to pass something back to the code that calls the function.\n", "A function can return multiple things by separating them with commas after the `return`:\n", "`return 1, 2, 3, 4`." ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [], "source": [ "def fahr_to_celsius(temp):\n", " return ((temp - 32) * (5 / 9))" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "17.22222222222222" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fahr_to_celsius(63)" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "32.22222222222222" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fahr_to_celsius(90)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 13: \"Write a function that takes a grid as input and returns a new grid with\n", "the colors inverted (e.g. white becomes black, black becomes white,\n", "yellow becomes ???).\"" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [], "source": [ "def invert_colors(input_grid):\n", " \"\"\"\n", " Returns a new grid the same size as the input grid but with colors \"inverted\".\n", " \n", " Colors in our grids are are integers that can have values between 0 - 255 (inclusive).\n", " To \"invert\" a color channel (red, green, or blue) we mirror it within\n", " that 0 - 255 range: if it was 0 the output will be 255 and if it was 255 the output will be 0.\n", " A value of 123 will invert to 132.\n", " \n", " \"\"\"\n", " new_grid = input_grid.copy()\n", " \n", " for row_index in range(input_grid.height):\n", " for col_index in range(input_grid.width):\n", " new_grid[row_index, col_index].red = 255 - input_grid[row_index, col_index].red\n", " new_grid[row_index, col_index].blue = 255 - input_grid[row_index, col_index].blue\n", " new_grid[row_index, col_index].green = 255 - input_grid[row_index, col_index].green\n", " \n", " return new_grid" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "invert_colors(grid)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 14: \"Write a function that takes a grid and a color as input returns a new grid\n", "that is the input grid with an added border of the given color.\n", "\n", "BONUS: Make the color input argument optional.\"\n", "\n", "If the user doesn't supply a value for the `border_color` input it will default to `colors.Black`." ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [], "source": [ "def add_border(input_grid, border_color=colors.Black):\n", " \"\"\"\n", " Add a two-block border to the input grid.\n", " \n", " Specify the border color as a tuple of (red, green, blue) integers.\n", " \n", " \"\"\"\n", " # increase grid size by 4 to accomodate the two-block border on each side\n", " new_width = input_grid.width + 4\n", " new_height = input_grid.height + 4\n", " new_grid = BlockGrid(new_width, new_height, fill=border_color)\n", " \n", " for block in input_grid:\n", " # The +2 here offsets the input grid within the new grid so it ends up with a border\n", " new_grid[block.row + 2, block.col + 2].rgb = block.rgb\n", " \n", " return new_grid" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "add_border(grid, border_color=colors.Cyan)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 15: Write a function that can follow a list of directions\n", "(`'up'`, `'down'`, `'left'`, `'right'`) along a path, changing the color of\n", "blocks as it goes.\n", "An example function definition:\n", "\n", "```python\n", "def path_color(grid, path, starting_point, color):\n", " ...\n", "```" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [], "source": [ "def path_color(input_grid, path, starting_point, color):\n", " \"\"\"\n", " Change the color of all the blocks along a path starting at starting_point.\n", " \n", " Specify the path as a sequence of 'up', 'down', 'left', 'right' strings.\n", " Specify the starting point as (row, column) tuple.\n", " Specify the color a (red, green, blue) tuple.\n", " \n", " \"\"\"\n", " new_grid = input_grid.copy()\n", " \n", " # pull the location into separate row/col indices we can update individually\n", " current_row = starting_point[0]\n", " current_col = starting_point[1]\n", " \n", " # first, change the color of the block we're at\n", " new_grid[current_row, current_col].rgb = color\n", " \n", " # then move to the new location based on the path\n", " for direction in path:\n", " if direction == 'up':\n", " # one row higher in the grid\n", " current_row = current_row - 1\n", " elif direction == 'down':\n", " # one row lower\n", " current_row = current_row + 1\n", " elif direction == 'left':\n", " # one column to the left\n", " current_col = current_col - 1\n", " elif direction == 'right':\n", " # one column to the right\n", " current_col = current_col + 1\n", " \n", " # and update the new location's color\n", " new_grid[current_row, current_col].rgb = color\n", " \n", " return new_grid" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "path = (\n", " 'right', 'right', 'down', 'right', 'down', 'down', 'left', 'down', 'down', 'right', 'right', 'right', 'up'\n", ")\n", "\n", "path_color(grid, path, (3, 4), colors.HotPink)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.8.3" } }, "nbformat": 4, "nbformat_minor": 1 }