Skip to content
Snippets Groups Projects
python-data-extra-life.ipynb 7.25 KiB
Newer Older
ignat's avatar
ignat committed
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conway's Game of Life\n",
    "\n",
    "This is a 2D grid of cells, which can be on or off, 'living' or 'dead'. This grid changes over a series of generations.\n",
    "\n",
    "Each cell has 8 neighbours (up, down, left, right and the diagonals). The number of neighbours of each cell determines whether it will live in the next generation:\n",
    "\n",
    "* Cells with less than two neighbours will die\n",
    "* Cells with two neighbours will stay alive if already alive\n",
    "* Cells with three neighbours will come to life\n",
    "* Cells with four or more neighbours will die"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, run the `import`s below that we'll need for the exercise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from matplotlib import animation, rc\n",
    "from IPython.display import HTML\n",
    "import random"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Starting out\n",
    "\n",
    "Have a quick look through the rest of the worksheet to familiarise yourself. All of the code you need to edit is in the cells labelled:\n",
    "\n",
    "```python\n",
    "### Update the grid\n",
    "```\n",
    "\n",
    "and\n",
    "\n",
    "```python\n",
    "### Starting conditions\n",
    "```\n",
    "\n",
    "The eventual goal is that the function `update_cell()` will apply the Life rules as above. `update_grid` will run these rules on the whole grid, and return a new grid (the next generation of the cellular automaton).\n",
    "\n",
    "Let's do something simpler first. In the section `### Update the grid`, edit `update_grid()` so that it:\n",
    "\n",
    "* Creates a new grid the same shape as the one passed to it.\n",
    "* Calls `update_cell` for each position in the grid, and puts the result in the same position in the new grid.\n",
    "* Returns the new grid.\n",
    "\n",
    "Once that's done, you'll be ready to edit `update_cell()` to apply the rules, and return a `0` if the cell is dead in the next generation, and `1` if it's alive.\n",
    "\n",
    "First we should test the code though, and make sure everything works! So for now let's get `update_cell` to return a random `0` or `1`:\n",
    "\n",
    "```python\n",
    "def update_cell(x, y, grid):\n",
    "    return random.choice([0, 1])\n",
    "```\n",
    "\n",
    "Run all of the rest of the cells to the end of the worksheet. When you get to the one marked ```### VIDEO```, after a short wait, you should see video of a randomly changing grid.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A simple rule\n",
    "\n",
    "Rather than going straight to the Life rules, let's try something simpler.\n",
    "\n",
    "Change `update_cell` so that each cell is alive in the next generation if the cell to the left of it is alive.\n",
    "\n",
    "Re-run the rest of the worksheet and look at the result."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A less simple rule\n",
    "\n",
    "Now change `update_cell` so that a cell is alive if two cells adjacent to it (up, down, left, right) are alive.\n",
    "\n",
    "You'll have to work around the limits of the grid. If you like, for now you could just ignore the edges. (I.e., just update up to the second-last row and second-last column, and ignore the last row and last column)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Life!\n",
    "\n",
    "Now it's time to implement the Game of Life rules. As before, if you want you can ignore the last row and last column, to make things easier around the edges of the grid."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$\\downarrow$ The code below will need to be filled out for the Game of Life to run."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Update the grid\n",
    "\n",
    "def update_cell(x, y, grid):\n",
ignat's avatar
ignat committed
    "\n",
    "def update_grid(grid):\n",
    "    \n"
ignat's avatar
ignat committed
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$\\downarrow$ This code sets up the starting conditions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Starting conditions\n",
    "\n",
    "# random grid\n",
    "start_grid = np.random.randint(2,size=(100,100))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$\\downarrow$ This code sets up the plot where we'll display the grid -- you don't need to edit it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "\n",
    "fig = plt.figure()\n",
    "ax = plt.axes()\n",
    "image = plt.imshow(start_grid, interpolation='none')\n",
    "plt.set_cmap(\"Greys\")\n",
    "plt.tick_params(axis='x',which='both',bottom='off',top='off',labelbottom='off')\n",
    "plt.tick_params(axis='y',which='both',left='off',right='off',labelleft='off')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$\\downarrow$ The next three code cells are setup for the animation -- you don't need to edit them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Code to animate the grid -- do not modify\n",
    "def init():\n",
    "    return (image,)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Code to animate the grid -- do not modify\n",
    "def animate(_):\n",
    "    global grid\n",
    "    grid = update_grid(grid)\n",
    "    image.set_data(grid)\n",
    "    return (image,)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
ignat's avatar
ignat committed
   "outputs": [],
   "source": [
    "global grid\n",
    "grid = start_grid\n",
    "anim = animation.FuncAnimation(fig, animate, init_func=init, frames=100, interval=500, blit=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$\\downarrow$ This cell creates a video of the generations of the grid."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "HTML(anim.to_jshtml())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
ignat's avatar
ignat committed
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "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.6.6"
ignat's avatar
ignat committed
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}