Added questions to all problem pages, solution workings for days 1 and 2
authorNeil Smith <neil.git@njae.me.uk>
Wed, 2 Aug 2017 11:25:34 +0000 (12:25 +0100)
committerNeil Smith <neil.git@njae.me.uk>
Wed, 2 Aug 2017 11:25:34 +0000 (12:25 +0100)
29 files changed:
01-ticket-prices/ticket-pricing-solution.ipynb
02-lifts/lifts-solution.ipynb
03-door-codes/door-codes-solution.ipynb
04-amidakuji/amidakuji-solution-1.ipynb
06-tour-shapes/question-example-tour-000-s0010-m000-trim.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-000-s0010-m000.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-001-s0012-m000-trim.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-001-s0012-m000.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-002-s0012-m001-trim.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-002-s0012-m001.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-003-s0014-m001-trim.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-003-s0014-m001.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-004-s0051-m001-trim.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-004-s0051-m001.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-005-s0043-m001-trim.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-005-s0043-m001.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-006-s0094-m000-trim.png [new file with mode: 0644]
06-tour-shapes/question-example-tour-006-s0094-m000.png [new file with mode: 0644]
06-tour-shapes/question-examples.txt [new file with mode: 0644]
06-tour-shapes/tour-creation-for-background.ipynb
06-tour-shapes/tour-shapes-build-problem-set.ipynb
06-tour-shapes/tour-shapes-build-raw-tours.ipynb
06-tour-shapes/tour-shapes-sample-tours.ipynb
06-tour-shapes/tour-shapes-solution.ipynb
07-interpreter/interpreter-solution.ipynb [new file with mode: 0644]
07-interpreter/machine-code-4-reg.ipynb
08-word-chains/visa-woes-solution.ipynb [new file with mode: 0644]
08-word-chains/word-chain-solution.ipynb [deleted file]
10-word-search/wordsearch-solution.ipynb

index 8ba20442b6dae95c16ff439de4d42a0c242d26c1..eb0cd2e42ca43889fad8b1644bb9e14cf16ef50c 100644 (file)
     "The 21 day trip to Morgantown and the trips to  Giessenmestia and Nordkapp are all too expensive."
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Part 2\n",
+    "You don't just want _a_ holiday. You want the _best_ holiday. What is the code of the holiday which would give you the best value?\n",
+    "\n",
+    "The \"value\" of a holiday is the duration per pound. Because some destinations are better than others, you'll want to scale the value for some locations. For instance, a night in Timbuktu is worth three times as much as a holiday in Bletchley.\n",
+    "\n",
+    "Assume all holidays have a relative value of 1, apart from these destinations.\n",
+    "\n",
+    "| Destination | Score |\n",
+    "|-------------|-------|\n",
+    "| Almaty | 2.0 |\n",
+    "| Brorfelde | 0.9 |\n",
+    "| Estacada | 0.4 |\n",
+    "| Jayuya | 0.6 |\n",
+    "| Karlukovo | 2.2 |\n",
+    "| Morgantown | 2.9 |\n",
+    "| Nordkapp | 1.5 |\n",
+    "| Nullarbor | 2.2 |\n",
+    "| Puente-Laguna-Garzonkuala-Penyu | 0.4 |\n",
+    "| Uzupis | 0.9 |\n",
+    "\n",
+    "## Example\n",
+    "\n",
+    "Given the holiday list above, the holiday to Geoje-Si (with the standard weighting of 1) has a value of $\\frac{14}{782} = 0.0179$ nights per pound. \n",
+    "\n",
+    "The trip to Estacada looks promising, at $\\frac{21}{1052} = 0.0200$ nights per pound. Unfortunately, the weighting for Estacada is low, to the adjusted cost is $0.4 \\times \\frac{21}{1052} = 0.00798$ nights per pound.\n",
+    "\n",
+    "The best value holiday is the 21 day trip to Morgantown, with a value of $2.9 \\times \\frac{21}{1284} = 0.0474$ nights per pound. Unfortunately, it's unaffordable. \n",
+    "\n",
+    "The best value affordable holiday is the trip to Stonnington Island, with $\\frac{14}{1284} = 0.0193$ nights per pound."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Worked example of solving\n",
+    "\n",
+    "For those still getting to grips with things, I thought I'd show how I'd work through solving the day 1 task.\n",
+    "\n",
+    "My first step when looking at this kind of thing is to think about data structures and operations. What data do we have, and what do we need to do with it?\n",
+    "\n",
+    "We're given a list of holidays. In the first part of the task, we have to filter that list against some condition and count how many meet the condition. In the second part, we have to find the holiday with some maximal value. \n",
+    "\n",
+    "How to store holidays? We just need something we can walk over (iterate over). There are many choices. We could just use a list, or a set (if we assume each holiday is distinct), or a dict/map/hashmap, using the holiday ID as a key. They're all much of a sameness, so let's take the path of least resistance and use a list.\n",
+    "\n",
+    "How to represent each holiday? Each holiday is a record of four parts (ID, destination, price, duration). I could use a dict or (in Python) a namedtuple to store the parts. That has the advantage that it gives a name to each of the parts. The alternative is to use a list to store each holiday and refer to the parts by number. Either is good, but as this task is small, I'll be able to get away with just remembering four numbers and what they mean.\n",
+    "\n",
+    "So, my chosen representation is a list of lists. That's not the best representation, but it's good enough for this task."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Next step: reading the list of holidays. Let's just start by trying to read in the data file and split it into a list, one element for each holiday. Let's not try to sort out each holiday in that list at the moment.\n",
+    "\n",
+    "I could look through the Python documentation for how to do this, or I could hit a search engine. \n",
+    "\n",
+    "I'm not the first to have done that. Typing \"python read file lines\" suggests and autocomplete of \"python read file lines into a list\", which is spot on, and leads to a [StackOverflow post](https://stackoverflow.com/questions/3925614/how-do-you-read-a-file-into-a-list-in-python). Result!\n",
+    "\n",
+    "Let's try the top-rated answer, with some print statements to check what's going on:\n",
+    "```\n",
+    "with open('01-holidays.txt') as f:\n",
+    "    lines = f.read().splitlines()\n",
+    "print(len(lines), lines[0])\n",
+    "```\n",
+    "That gives output\n",
+    "```\n",
+    "124 dda7d369 1546 Uzupis 21\n",
+    "```\n",
+    "which looks right: 124 lines, and that's the first line in the file.\n",
+    "\n",
+    "Another quick search for splitting a string into a list points me in the direction of .split().\n",
+    "\n",
+    "I can combine those ideas like this:\n",
+    "\n",
+    "```\n",
+    "holidays = []\n",
+    "with open('01-holidays.txt') as f:\n",
+    "    for line in f.read().splitlines():\n",
+    "        holidays += [line.split()]\n",
+    "        \n",
+    "print(len(lines), holidays[0])\n",
+    "```\n",
+    "\n",
+    "But I actually like the second answer of that Stack Overflow post better, and prefer to use the list comprehension:\n",
+    "\n",
+    "```\n",
+    "holidays = [line.strip().split() for line in open('01-holidays.txt')]\n",
+    "\n",
+    "print(len(lines), holidays[0])\n",
+    "```\n",
+    "\n",
+    "The basic format is `[<do something to item> for <item> in <bunch of items>]`\n",
+    "\n",
+    "I think it's cleaner, and it's certainly more compact."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now we have the holidays, time to find the affordable ones. \n",
+    "\n",
+    "The basic idea is to keep a count of the number of affordable holidays as we walk along the list of holidays. Every time we get to an affordable one, increase the count by one. The price is in the second element of the holiday record, which is number 1 in Python's count-from-zero world.\n",
+    "\n",
+    "That turns quite simply into code:\n",
+    "\n",
+    "```\n",
+    "affordable_count = 0\n",
+    "for holiday in holidays:\n",
+    "    if holiday[1] <= 1200:\n",
+    "        affordable_count += 1\n",
+    "\n",
+    "print(affordable_count)\n",
+    "```\n",
+    "\n",
+    "…which gives an error about unorderable types, comparing `str()` with `int()`.\n",
+    "\n",
+    "That makes sense. Strings and numbers are different, and what we've got is a list of strings. A quick search online tells us that `int(something)` will convert `something` into a number, if possible. Let's make that change and try again.\n",
+    "\n",
+    "```\n",
+    "affordable_count = 0\n",
+    "for holiday in holidays:\n",
+    "    if int(holiday[1]) <= 1200:\n",
+    "        affordable_count += 1\n",
+    "\n",
+    "print(affordable_count)\n",
+    "```\n",
+    "\n",
+    "And that gives the right answer!"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now for part 2. \n",
+    "\n",
+    "At first sight, its intimidating. Complex calculation, lots of data to move around. But, let's just start with what we can do easily and see where we end up.\n",
+    "\n",
+    "Each destination has a weight for how much it's liked. If a weight's not given, we use 1.\n",
+    "\n",
+    "We can store the given weights in a `dict`: it's what they were made for. Associate some value with a key; in this case, the key is the destination name and the value is the weight.\n",
+    "\n",
+    "```\n",
+    "destination_values = {'Almaty': 2.0, 'Brorfelde': 0.9, 'Estacada': 0.4, 'Jayuya': 0.6, 'Karlukovo': 2.2, \n",
+    "                      'Morgantown': 2.9,'Nordkapp': 1.5, 'Nullarbor': 2.2, \n",
+    "                      'Puente-Laguna-Garzonkuala-Penyu': 0.4, 'Uzupis': 0.9}\n",
+    "```\n",
+    "\n",
+    "We can get the values from the dict quite easily:\n",
+    "\n",
+    "```\n",
+    "print(destination_values['Jayaya'])\n",
+    "```\n",
+    "\n",
+    "How to get the value when the destination isn't in the table? We could use the defaultdict from the Python library, or we could use the `get()` method which accepts a default value, or we could just wrap some control in a function.\n",
+    "\n",
+    "```\n",
+    "def value_of_destination(name):\n",
+    "    if name in destination_values:\n",
+    "        return destination_values[name]\n",
+    "    else:\n",
+    "        return 1\n",
+    "```\n",
+    "\n",
+    "And try it:\n",
+    "\n",
+    "```\n",
+    "print(destination_values['Mamula'])\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now we can find the destination weight for each destination, how to find the value of a holiday? Again, wrap that in a function so we can call it without getting bogged down in the details. \n",
+    "\n",
+    "The tricky part here is to keep track of data types. We have to convert strings to numbers again, but division involving integers will often give an integer as the answer. The standard trick in these situation is to make sure that at least one number in each calculation is a floating-point number, and Python will ensure that the whole calculation is done a floating point numbers.\n",
+    "\n",
+    "```\n",
+    "def value_of_holiday(holiday):\n",
+    "    hid, cost, destination, duration = tuple(holiday)\n",
+    "    value = value_of_destination(destination) * float(duration) / int(cost)\n",
+    "    return value\n",
+    "```\n",
+    "\n",
+    "Again, we can test it\n",
+    "\n",
+    "```\n",
+    "print(value_of_holiday(holidays[0]))\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now we have the parts for solving the task. Just like part 1, we'll walk over the list of holidays, keeping track of the best value one so far. We have remember two items now, though: the best value, and the code of the holiday with that value. We'll just use two separate variables to keep track of them.\n",
+    "\n",
+    "```\n",
+    "best_holiday = ''\n",
+    "best_value = 0\n",
+    "\n",
+    "for holiday in holidays:\n",
+    "    if int(holiday[1]) <= 1200:\n",
+    "        if value_of_holiday(holiday) > best_value:\n",
+    "            best_value = value_of_holiday(holiday)\n",
+    "            best_holiday = holiday[0]        \n",
+    "\n",
+    "print(best_holiday)\n",
+    "```\n",
+    "\n",
+    "Rather than having two `if` statements, we could say \n",
+    "\n",
+    "```\n",
+    "if int(holiday[1]) <= 1200 and value_of_holiday(holiday) > best_value:\n",
+    "```\n",
+    "\n",
+    "but I'm not sure it's much better in this context.\n",
+    "\n",
+    "And there you have it!"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "I hope you found the exposition useful.\n",
+    "\n",
+    "Yes, I use the internet a lot to look up bits of syntax. It's much the same as looking in a textbook and finding snippets of code to reuse and repurpose. The skill of programming isn't so much the mastery of syntax as it is about understanding the problem and how to put together a solution. By all means look stuff up; a good programmer knows what to look up (or ask) and how to use the answer."
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
     "sum(1 for h in open('01-holidays.txt') if int(h.split()[1]) <= 1200)"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "# Part 2\n",
-    "You don't just want _a_ holiday. You want the _best_ holiday. What is the code of the holiday which would give you the best value?\n",
-    "\n",
-    "The \"value\" of a holiday is the duration per pound. Because some destinations are better than others, you'll want to scale the value for some locations. For instance, a night in Timbuktu is worth three times as much as a holiday in Bletchley.\n",
-    "\n",
-    "Assume all holidays have a relative value of 1, apart from these destinations.\n",
-    "\n",
-    "| Destination | Score |\n",
-    "|-------------|-------|\n",
-    "| Almaty | 2.0 |\n",
-    "| Brorfelde | 0.9 |\n",
-    "| Estacada | 0.4 |\n",
-    "| Jayuya | 0.6 |\n",
-    "| Karlukovo | 2.2 |\n",
-    "| Morgantown | 2.9 |\n",
-    "| Nordkapp | 1.5 |\n",
-    "| Nullarbor | 2.2 |\n",
-    "| Puente-Laguna-Garzonkuala-Penyu | 0.4 |\n",
-    "| Uzupis | 0.9 |\n",
-    "\n",
-    "## Example\n",
-    "\n",
-    "Given the holiday list above, the holiday to Geoje-Si (with the standard weighting of 1) has a value of $\\frac{14}{782} = 0.0179$ nights per pound. \n",
-    "\n",
-    "The trip to Estacada looks promising, at $\\frac{21}{1052} = 0.0200$ nights per pound. Unfortunately, the weighting for Estacada is low, to the adjusted cost is $0.4 \\times \\frac{21}{1052} = 0.00798$ nights per pound.\n",
-    "\n",
-    "The best value holiday is the 21 day trip to Morgantown, with a value of $2.9 \\times \\frac{21}{1284} = 0.0474$ nights per pound. Unfortunately, it's unaffordable. \n",
-    "\n",
-    "The best value affordable holiday is the trip to Stonnington Island, with $\\frac{14}{1284} = 0.0193$ nights per pound."
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": 16,
index dc7724f964ee36d13ca7945c622a46fee7167aea..c52facc07695c869642bb63c65e9cfabc6d76f1c 100644 (file)
     "Given the input in [02-lifts.txt](02-lifts.txt), where would you get out?"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Worked example of solution: Part 1\n",
+    "\n",
+    "This is an example of a very common pattern: walking along a list, finding some total or final value. As such, there are a great many ways of doing it.\n",
+    "\n",
+    "The most obvious way is to have a variable that holds the current floor, and update it with every instruction that's read from the list of instructions. As the current floor is just a number, we can have a simple variable.\n",
+    "\n",
+    "The list of instructions will be read as a string, and we can iterate through a string easily, so we'll leave the instructions as a string. Happily, each instruction is one character, so no need to count characters and instructions separately.\n",
+    "\n",
+    "The only complication is that there's no obvious trick for converting the instruction characters. Given that, let's just do a simple `if`-`elisf`-`else` structure (or a `case` statement of your language of choice has it) to convert an instruction into a floor change. \n",
+    "\n",
+    "(I could also have used a `dict` like \n",
+    "\n",
+    "```\n",
+    "value = {'^': 1, 'v': -1, '=': 0}\n",
+    "```\n",
+    "\n",
+    "and it would behave in the same way.)\n",
+    "\n",
+    "(Another common solution was to count the number of `^` characters and the number of `v` characters, subtract one from the other, and give the result. That works for part 1 but doesn't work for part 2!)"
+   ]
+  },
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 2,
    "metadata": {
     "collapsed": true
    },
     "        return 0"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now we can find the floor-change of each instruction, we set the initial floor to 0 and run down the list, updating the current floor at each step."
+   ]
+  },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 3,
    "metadata": {
     "collapsed": true
    },
     "    return current"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Finally, open the file of instructions and find the final floor."
+   ]
+  },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [
     {
        "209"
       ]
      },
-     "execution_count": 3,
+     "execution_count": 4,
      "metadata": {},
      "output_type": "execute_result"
     }
     "exit"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "(For my testing purposes, find all the floors visited so I can give sensible hints for wrong answers.)"
+   ]
+  },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 5,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 6,
    "metadata": {},
    "outputs": [
     {
        "(10002, 216, -6)"
       ]
      },
-     "execution_count": 5,
+     "execution_count": 6,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 7,
    "metadata": {},
    "outputs": [
     {
        "209"
       ]
      },
-     "execution_count": 6,
+     "execution_count": 7,
      "metadata": {},
      "output_type": "execute_result"
     }
     "The sequence `v^^^^^v=v=` would allow you to exit on floors 3 and 2, so the highest floor you could leave from would be floor 3 (even though the lift reaches floor 4)."
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Worked example of solution: part 2\n",
+    "This is another common pattern: walking down a list, keeping some extreme value (the largest, the smallest, or something like that.)\n",
+    "\n",
+    "The basic idea is to keep a variable holding the highest exit seen so far, and update it if we see a higher exit. We start with some initial value, such as zero. \n",
+    "\n",
+    "The `highest_exit` function is very similar to the `final` function, but with the `if` statement in the loop. This just checks if we're at an exit and it's higher than what we've seen so far; if so, it updates the `highest_exit` variable.\n",
+    "\n",
+    "It was pointed out in the forums that by starting with the `highest_exit` at 0, we're assuming that the highest exit is above ground. That's true in this case, but its a valid concern. In this case, I should set the initial value to be smaller than the smallest valid value we can find, so that the first exit we find is correctly recorded. In this case, the smallest value for the exit is if all the instructions are down, or -1 × (number of instructions)."
+   ]
+  },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 22,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def highest_exit(sequence):\n",
+    "    highest_exit = -1 - len(sequence) # or 0\n",
+    "    current = 0\n",
+    "    for i in sequence:\n",
+    "        if value(i) == 0 and current > highest_exit:\n",
+    "            highest_exit = current\n",
+    "        else:\n",
+    "            current += value(i)\n",
+    "    return highest_exit"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "215"
+      ]
+     },
+     "execution_count": 21,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "highest_exit(instructions)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A variation that returns a list of all the exits, so I can generate hints for obvious wrong answers (the last exit, the lowest exit, the first exit, the number of exits)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 11,
    "metadata": {},
    "outputs": [
     {
        "215"
       ]
      },
-     "execution_count": 8,
+     "execution_count": 11,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 12,
    "metadata": {},
    "outputs": [
     {
        "-5"
       ]
      },
-     "execution_count": 9,
+     "execution_count": 12,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 10,
+   "execution_count": 13,
    "metadata": {},
    "outputs": [
     {
        "209"
       ]
      },
-     "execution_count": 10,
+     "execution_count": 13,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 11,
+   "execution_count": 14,
    "metadata": {},
    "outputs": [
     {
        "-2"
       ]
      },
-     "execution_count": 11,
+     "execution_count": 14,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 12,
+   "execution_count": 15,
    "metadata": {},
    "outputs": [
     {
        "1259"
       ]
      },
-     "execution_count": 12,
+     "execution_count": 15,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 16,
    "metadata": {},
    "outputs": [
     {
        "         215: 2})"
       ]
      },
-     "execution_count": 13,
+     "execution_count": 16,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 17,
    "metadata": {},
    "outputs": [
     {
        "-2"
       ]
      },
-     "execution_count": 14,
+     "execution_count": 17,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 12,
+   "execution_count": 18,
    "metadata": {},
    "outputs": [
     {
        "(209, 215)"
       ]
      },
-     "execution_count": 12,
+     "execution_count": 18,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 19,
    "metadata": {},
    "outputs": [
     {
        "(209, 215)"
       ]
      },
-     "execution_count": 13,
+     "execution_count": 19,
      "metadata": {},
      "output_type": "execute_result"
     }
index 7c5867f02f39e81d5b49d1a8d59699bba786f78d..b1fd1051589e9f2d4df18b83e280c0d3776ee42e 100644 (file)
@@ -45,7 +45,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 3,
    "metadata": {
     "collapsed": true
    },
@@ -56,7 +56,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 4,
    "metadata": {
     "collapsed": true
    },
@@ -71,7 +71,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 5,
    "metadata": {},
    "outputs": [
     {
@@ -80,7 +80,7 @@
        "('a', 'z', 'z', 'a')"
       ]
      },
-     "execution_count": 4,
+     "execution_count": 5,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 6,
    "metadata": {
     "collapsed": true
    },
    "outputs": [],
    "source": [
     "def sanitise(phrase):\n",
-    "    return ''.join(l for l in phrase if l in string.ascii_lowercase)"
+    "    return ''.join(l.lower() for l in phrase if l in string.ascii_letters)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'helloworld'"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sanitise('Hello World')"
    ]
   },
   {
index 15a816add45d15161e4fa63f28547c67de0db43c..0a9b424494a4b744dac91b453edd63c2ac9360df 100644 (file)
@@ -40,7 +40,7 @@
     "\n",
     "# Part 1\n",
     "\n",
-    "The full labyrinth description is given in (04-lines.txt). The labyrinth has 26 lines, labelled 0 to 25 inclusive. If you and 25 friends, labelled `a` to `z` in order, entered the labyrinth, in what order would you come out?\n",
+    "The full labyrinth description is given in [04-lines.txt](04-lines.txt). The labyrinth has 26 lines, labelled 0 to 25 inclusive. If you and 25 friends, labelled `a` to `z` in order, entered the labyrinth, in what order would you come out?\n",
     "\n",
     "(Your answer should be one string of 26 letters, without spaces or punctuation, like `acfbed` .)"
    ]
diff --git a/06-tour-shapes/question-example-tour-000-s0010-m000-trim.png b/06-tour-shapes/question-example-tour-000-s0010-m000-trim.png
new file mode 100644 (file)
index 0000000..bab9f89
Binary files /dev/null and b/06-tour-shapes/question-example-tour-000-s0010-m000-trim.png differ
diff --git a/06-tour-shapes/question-example-tour-000-s0010-m000.png b/06-tour-shapes/question-example-tour-000-s0010-m000.png
new file mode 100644 (file)
index 0000000..0d222fe
Binary files /dev/null and b/06-tour-shapes/question-example-tour-000-s0010-m000.png differ
diff --git a/06-tour-shapes/question-example-tour-001-s0012-m000-trim.png b/06-tour-shapes/question-example-tour-001-s0012-m000-trim.png
new file mode 100644 (file)
index 0000000..ccfd7da
Binary files /dev/null and b/06-tour-shapes/question-example-tour-001-s0012-m000-trim.png differ
diff --git a/06-tour-shapes/question-example-tour-001-s0012-m000.png b/06-tour-shapes/question-example-tour-001-s0012-m000.png
new file mode 100644 (file)
index 0000000..04eb536
Binary files /dev/null and b/06-tour-shapes/question-example-tour-001-s0012-m000.png differ
diff --git a/06-tour-shapes/question-example-tour-002-s0012-m001-trim.png b/06-tour-shapes/question-example-tour-002-s0012-m001-trim.png
new file mode 100644 (file)
index 0000000..3181a5c
Binary files /dev/null and b/06-tour-shapes/question-example-tour-002-s0012-m001-trim.png differ
diff --git a/06-tour-shapes/question-example-tour-002-s0012-m001.png b/06-tour-shapes/question-example-tour-002-s0012-m001.png
new file mode 100644 (file)
index 0000000..1493861
Binary files /dev/null and b/06-tour-shapes/question-example-tour-002-s0012-m001.png differ
diff --git a/06-tour-shapes/question-example-tour-003-s0014-m001-trim.png b/06-tour-shapes/question-example-tour-003-s0014-m001-trim.png
new file mode 100644 (file)
index 0000000..c31b005
Binary files /dev/null and b/06-tour-shapes/question-example-tour-003-s0014-m001-trim.png differ
diff --git a/06-tour-shapes/question-example-tour-003-s0014-m001.png b/06-tour-shapes/question-example-tour-003-s0014-m001.png
new file mode 100644 (file)
index 0000000..132bef0
Binary files /dev/null and b/06-tour-shapes/question-example-tour-003-s0014-m001.png differ
diff --git a/06-tour-shapes/question-example-tour-004-s0051-m001-trim.png b/06-tour-shapes/question-example-tour-004-s0051-m001-trim.png
new file mode 100644 (file)
index 0000000..848d13f
Binary files /dev/null and b/06-tour-shapes/question-example-tour-004-s0051-m001-trim.png differ
diff --git a/06-tour-shapes/question-example-tour-004-s0051-m001.png b/06-tour-shapes/question-example-tour-004-s0051-m001.png
new file mode 100644 (file)
index 0000000..1f0cedd
Binary files /dev/null and b/06-tour-shapes/question-example-tour-004-s0051-m001.png differ
diff --git a/06-tour-shapes/question-example-tour-005-s0043-m001-trim.png b/06-tour-shapes/question-example-tour-005-s0043-m001-trim.png
new file mode 100644 (file)
index 0000000..058b95e
Binary files /dev/null and b/06-tour-shapes/question-example-tour-005-s0043-m001-trim.png differ
diff --git a/06-tour-shapes/question-example-tour-005-s0043-m001.png b/06-tour-shapes/question-example-tour-005-s0043-m001.png
new file mode 100644 (file)
index 0000000..2a0d8f0
Binary files /dev/null and b/06-tour-shapes/question-example-tour-005-s0043-m001.png differ
diff --git a/06-tour-shapes/question-example-tour-006-s0094-m000-trim.png b/06-tour-shapes/question-example-tour-006-s0094-m000-trim.png
new file mode 100644 (file)
index 0000000..ec245e7
Binary files /dev/null and b/06-tour-shapes/question-example-tour-006-s0094-m000-trim.png differ
diff --git a/06-tour-shapes/question-example-tour-006-s0094-m000.png b/06-tour-shapes/question-example-tour-006-s0094-m000.png
new file mode 100644 (file)
index 0000000..a1853e4
Binary files /dev/null and b/06-tour-shapes/question-example-tour-006-s0094-m000.png differ
diff --git a/06-tour-shapes/question-examples.txt b/06-tour-shapes/question-examples.txt
new file mode 100644 (file)
index 0000000..0eaa964
--- /dev/null
@@ -0,0 +1,7 @@
+FFRRFLRRFR
+FFLLRLRLLFLR
+RRFFLLFFFFLF
+RRLLRRFFRFRFLR
+FFRFLLFFFRLRRFFFLFLRRFLLFFFFFRFLFFFFFRLLFRFRLLFFFFF
+FLRFFRLLFRFFFLFFLFFRFRRLLFFRLFFFFFLLFFRFRFL
+FFRFLLFFFRLRRFFFLFLRRFLLFFFFFRFLFFFFFRLLFRFRLLFFFFFFLRFFRLLFRFFFLFFLFFRFRRLLFFRLFFFFFLLFFRFRFL
index 74716dfbb4714f99fe0c0ce7a92b0f29319298cd..e9848a5be14cc87742c55a7185ab4a446cc3505b 100644 (file)
    },
    "outputs": [],
    "source": [
-    "def plot_trace(trace, colour='k', xybounds=None, fig=None, subplot_details=None, filename=None):\n",
+    "def plot_trace(trace, colour='k', highlight_start=True,\n",
+    "               xybounds=None, fig=None, subplot_details=None, filename=None):\n",
     "    plt.axis('on')\n",
     "    plt.axes().set_aspect('equal')\n",
+    "        \n",
+    "    if highlight_start:\n",
+    "        plt.axes().add_patch(plt.Circle((trace[0].x, trace[0].y), 0.2, color=colour))\n",
+    "        \n",
     "    for s, t in chunks(trace, 2):\n",
     "        w, h = plot_wh[t.dir]\n",
     "        plt.arrow(s.x, s.y, w, h, head_width=0.1, head_length=0.1, fc=colour, ec=colour, length_includes_head=True)\n",
index 05df3100e5e578478bbb4fa4a1b6cf51670f6d81..5d9c57dd6396809f6d02e2f2d4cc83f3f481cb71 100644 (file)
    },
    "outputs": [],
    "source": [
-    "def plot_trace(trace, colour='k', xybounds=None, fig=None, subplot_details=None, filename=None):\n",
+    "def plot_trace(trace, colour='k', highlight_start=True,\n",
+    "               xybounds=None, fig=None, subplot_details=None, filename=None):\n",
     "    plt.axis('on')\n",
     "    plt.axes().set_aspect('equal')\n",
+    "        \n",
+    "    if highlight_start:\n",
+    "        plt.axes().add_patch(plt.Circle((trace[0].x, trace[0].y), 0.2, color=colour))\n",
+    "        \n",
     "    for s, t in chunks(trace, 2):\n",
     "        w, h = plot_wh[t.dir]\n",
     "        plt.arrow(s.x, s.y, w, h, head_width=0.1, head_length=0.1, fc=colour, ec=colour, length_includes_head=True)\n",
index 79030704fc2185b126ee6e997df8ba9c649eda90..7731efa0d2ba79a3bcba4b6cc74f3afafed2507e 100644 (file)
    },
    "outputs": [],
    "source": [
-    "def plot_trace(trace, colour='k', xybounds=None, fig=None, subplot_details=None, filename=None):\n",
+    "def plot_trace(trace, colour='k', highlight_start=True,\n",
+    "               xybounds=None, fig=None, subplot_details=None, filename=None):\n",
     "    plt.axis('on')\n",
     "    plt.axes().set_aspect('equal')\n",
+    "        \n",
+    "    if highlight_start:\n",
+    "        plt.axes().add_patch(plt.Circle((trace[0].x, trace[0].y), 0.2, color=colour))\n",
+    "        \n",
     "    for s, t in chunks(trace, 2):\n",
     "        w, h = plot_wh[t.dir]\n",
     "        plt.arrow(s.x, s.y, w, h, head_width=0.1, head_length=0.1, fc=colour, ec=colour, length_includes_head=True)\n",
   {
    "cell_type": "code",
    "execution_count": 119,
-   "metadata": {},
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "tours_filename = 'tours-random-walk.txt'\n",
index e438aedaf30b2183d861d6a700b8069766c10407..59f7720f2f2368acf9aff9b42a4dd976b4851538 100644 (file)
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 58,
    "metadata": {
     "collapsed": true
    },
    "outputs": [],
    "source": [
-    "def plot_trace(trace, colour='k', xybounds=None, fig=None, subplot_details=None, filename=None, show_axis=False):\n",
+    "def plot_trace(trace, colour='k', highlight_start=True,\n",
+    "               xybounds=None, fig=None, subplot_details=None, filename=None, show_axis=False):\n",
     "    if show_axis:\n",
     "        plt.axis('on')\n",
     "    else:\n",
     "        plt.axis('off')\n",
     "    plt.axes().set_aspect('equal')\n",
+    "    \n",
+    "    if highlight_start:\n",
+    "        plt.axes().add_patch(plt.Circle((trace[0].x, trace[0].y), 0.2, color=colour))\n",
+    "        \n",
     "    for s, t in chunks(trace, 2):\n",
     "        w, h = plot_wh[t.dir]\n",
     "        plt.arrow(s.x, s.y, w, h, head_width=0.1, head_length=0.1, fc=colour, ec=colour, length_includes_head=True)\n",
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 23,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 53,
    "metadata": {},
    "outputs": [
     {
      "data": {
-      "image/png": "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\n",
+      "image/png": "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\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fcb73ad0978>"
+       "<matplotlib.figure.Figure at 0x7f2cfbc25ac8>"
       ]
      },
      "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": 54,
    "metadata": {},
    "outputs": [
     {
      "data": {
-      "image/png": "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\nhMqGoYtNhANGByBP3bLhxWPIPI4M8pSuE9AJQL7SdQJzGCAcgDybqBOQGIQ8dUcHJAahC3UCMLi6\nQ4TKhqGLTYQDyoYhz6rE4KpxxWMt6gT+uNvt7kXEXyLio4i4GRHPIuL9iPgiIn4ZEXfb8l9FxO2I\n+Doi7kXENxHxoP3sb2353Yj4Z/v5fyPivYi4FRF/j4iHbb1PI+JncdlLXrT1P23r34+Ix22/1yPi\neWvL56199yPiUUR83Lb9tO3zq4j4eXvvX9u23o+IJ60tT9u+b7W2PmzrfR4RH0TED21/tyPik7b+\nvdbuX8TlyTyLiDuLtj5obfkoLs/bs8Xv/2Fb/9Hecbvfvn/QtvV4r633I+L79v61x+1aRLxo2/+s\nHav94/Zt2+eX7fdbnuM77Xje3zvHjw8ctxdx+Tez39ZP2vmIuLzt9vK43W/n6MNXnOP57/Hjtt3/\n7J3j5XG7036HBxHxXdvO3Jb57/GzdtxetvN4q7Vvbuuhc/yPxXGb23qz7eNu/P9n41Hb1qHPxsNY\nY5qm9K+4/EP5U1z+QU3tQE97X98tXv/rwPKLxesnB5ZPr1h+fmD5l4vX3x9Y/s3i9b8PLH++eP3V\nEW059PXF4vUPB5Yvt//tgeVPrzhuZyvbcuhredyeH1j+9RXn+NkRx+2qtiyXv7yirc8OLL/qHL94\nxbbWnOMnr9juofP29MDyYz4bfzj287kz1R/GZnQABqcTgMHpBGBwOgEYnE4ABqcTgMHpBGBwOgEY\nnE4ABqcTgMHpBGBwOgEYnE4ABqcTgMHpBGBwOgEYnE4ABqcTgMHpBGBwOgEYnE4ABqcTgMH9D868\nJ7EMO+IfAAAAAElFTkSuQmCC\n",
+      "image/png": "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\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea71b8cc0>"
+       "<matplotlib.figure.Figure at 0x7f2cfbca67b8>"
       ]
      },
      "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 26,
+   "execution_count": 57,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7f2cfbcdf748>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(square_tour(a=5)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 55,
    "metadata": {},
    "outputs": [
     {
      "data": {
-      "image/png": "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\n",
+      "image/png": "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\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea71dde10>"
+       "<matplotlib.figure.Figure at 0x7f2cfbab1400>"
       ]
      },
      "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 27,
+   "execution_count": 56,
    "metadata": {},
    "outputs": [
     {
      "data": {
-      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQYAAAD7CAYAAACITjpPAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAEFZJREFUeJzt3dlu3Fh6wPE/ZXmRvMptq213Ty/TeYQACQYI0sAgGCB5\nh7xBLvMAAXKVB8gjJJcBgrmam1xOggFmECC57CW9WYslWba8SJbNXBwSVSZFntKwVDws/n+AIJWL\ndXyKy1eHXx1+zPI8R5KmrfTdAUnpMTBIqjEwSKoxMEiqMTBIqjEwSKpZ7bsDAFmW/Rr4c+ADYB/Y\nBj4GbgI/Ac+Az4ErwP8Bp8AXwFvg6+LfPwOOi8e3gUfAEfAd8OE52n4D/ElD298AtyptbwL3gANg\nC/ioWOYxcFi89uoZbX9DWP+fn9H2C+B3wC/zPH/3R69YkWXZXwD/QVi/K8DPgRPgK8I+8DHwEviW\nsB03CdvtR8K2uEPYZw6AT4E1wnZ/XbSVndH218CNhrafAT9Mtb1D2C8/AdaB74FXU21/W/w+q+1X\nxf/9AWEff168/iGwUbS9V7R9vdL23+Z5/q9N6y2JwAD8DfC/wFPCm9snHDzXCG/sVbHcJcJGyouf\nd4QD8Erx+HXx+Kh4zeti+ZOi7aOivVPCBt4nbLjptssD8R3hQF+ttP2s0vYxYUc6qvQ71nbZb4q2\ntiptf0nY4LuzrkSd6Z8J6//H4jeE/aHclm8I6/xx8fuIEJh3CdtyjxAUjgjb7QrhgDst2soJ2/ZS\n8feboq31qba3zmj7tKHt3eJ15QSjbULQOavt11NtvyDsbztTbR8W7zGvtP0Z8C9A8oEB4K/yPH/c\ndydSkWVZGfzUzQ7wVZ7nX/bdkVRkWfZfhFFEo5RyDFnfHUiQ66S7y4RPWE28JIygG6UUGDyXrktp\n+wzVPcI5tyY+JORLGqW0413uuwMJOo0voogTQh5IE6uEPFjrAql423cHEuSpRHe7hESzJnaYJL7P\nlNKIwUSbLsJNwumEJt4SRlKNUgoMfjrWXYovoojbwN2+O5GYh4R5QI1SCgwp9SUV5hi6e0GYG6OJ\ncg5QI3MMaTNYdrdPmOGqicdERugp7XieSugi3Ad+1ncnErNKZFBgYEib66S7NZzgVPWIcI1Oo5QC\ng99K1Dnpq7unhOsGNPGayLcSKeUYpItwCDzpuxOJ2Yot4IghbZ5KdPeAcJmxJq4TLvFvlFJgSKkv\nqTAwdHcNp9tX3SPUDWmU0qmEI4Y610l3u4TZj5oo6zc0MjCkzXXSXVkgRRPbDGgeg+o8lejuAZHp\nvyO0QSgz1yilwJBSX1JhYOhuFfetqltELixL6VTC7+zrPJXobhsvu646ItSabJRSYJAuwjv80Kna\nx3oMg+apRHebRKb/jlD068qUAoOjlzqDpS7CGpEJTikdjF52XWdg6G6bSH3DESpvjtQopRGDw+Y6\n10l3q5h8rHqB5eMHLaXtM1T3CZcZa8Ly8QNnabfuTohcYjxClo8fOE8lutvFQi1Vu4QbLTdKacRg\nok0X4SZWia46JXITnpQCg5+OdZaP7+424a7hmrB8/MCZY+jO8vF1lo8fOINld/vAj313IjFbDOiy\na08l6sy7dHcPy8dXXcLy8YOW0vYZqnVCjUNNWD5+4Jz01d0hlo+vOsby8YPmKKq7p1g+vip6yz5H\nDFp2lo+vu0GkQG5KgSGlvqTCEUN3lo+vs3z8wLlOurN8fJ3l4wfOddLdK5zgVBUtH59SYFDdTpZl\n5Qb8Afi4+PuYkGkvLyd+RrhRaVkSfIdQ0+9O8fhHwvUCZV2CHwhDyWzq+XJoeUyYFPSwpe3LhBLk\nTW0/YnJqON3vE0IisKnfu4R9sqnt74t+ztL2c0JQ2MQAW7VBuBy9UUqBwRzD+/4B+DPCVXCvCTv6\nHcJB+ZxwIGwQDu6y6MYG4SvOA8Iklg+K5faZlPMqH98inH8fF+3dbmj7kHBglW3vF8vdBd4QAtQ6\nYbg+3fZa0e9nRb+vFH+fFI9Xptq+U/wu+32XMB18r9LvA0LibL3o92HR7yuEysfHU20/nWr778+z\n4kfgNpHAkOV5/8E0y7IceJTn+eO++yItuyzL/hv4JM/zjaZlUhoxmIGXFmOPyDc1KQ3fneUnLcY9\nIuXuUgoMKY1epGW2TsgzNErpYHTEIC3GPpELy1IaMfSfBZXGYVDl4w0M0mJsYvl4SRWXsXy8pIod\nLB8vqeItAyofL2kxojUqUgoM3kNBSoQ5Bml8LB8vqWYFy8dLqrB8vKSaEywfL6nC8vGSaq5j+XhJ\nFZtEysendDA6YpAW42Xx0yilHIOBQVqMaPn4lEYMkhbjDqG8W6OUAkNKfZGW2R0m9/I4U0oHo6Xd\npMU4ItyTo1FKOQZnPkqL8YTIsZ/SDWdK3xKCxKeEUcTXhLsPPSDc2eg7wl10Ngh3NvqpWHaN8Ib3\nCJeUXi6eewl8UbQ53XYOfHVG2/cId0Kqtr0H/E+e51/O+e1rSWRZ9gvg14RCKJ8RiqFsEfalLwhX\nEH9HuMtWednzV4RqSh8V//4NYah/n7Dvfk+YwnyTcCeu6ba3CZ/8bW1fJdzGr9r2YZ7n5S0Ma1IZ\nMfwT8NeEN7dNOGiPit/lfRgPCMUldgmFLG8SVtwe4aC+RlhJh8Vy14rXvi5+Vhvavlq0fdLS9lrR\n7l9e1ArQUvhHwgfW75jsN08IxVePCfvxFuEgfUX4kNoi7JuHhCuMd4rXPCmW2SPsr9cJtw88KNq+\nSqj2XLZ9FXhctFG2vU1IFzwr/s/dqbb/ru2NJDFiGIIsy64QNsBK7krTGbIs+3fgV3met5ZNG4KU\nko/S0B0TPo0Hz8BwTo4W1OIOkVu/DYWB4ZyyLPPbEzVZmuNpad7IAjhSUMxTQoJw8AwM0vzkhG8E\nBs/AMLsMzDGo1QaRqcZDYWA4J3MMarE0HxoGBml+DgiTiAbPwCDNzyWW5MZJBoZzMsegFneLn8Ez\nMJyTOQa1OO27A/NiYJDmZ48ZSrMPgYFBmp81wrTowTMwnJM5BrW4Baz33Yl5MDDMLgdzDGr1pu8O\nzIuBQZqffULFpcEzMEjzcxMvux4dr5VQzBpOcBodcwyKOe67A/NiYJidAUExh8APfXdiHgwMs8vB\nUwm1ukMo1T54BobZZeCphFpd7rsD82JgkObnBUtyvYSBQZqf14QbxgyegeGczDGoxQbOYxgncwxq\nsTTH09K8kQVwpKAYy8dLqskJN0MePAPD7JwSrZg7wId9d2IeDAznZI5BY2BgmJ0jBcXsY/n40XGk\noBjLx4+VOQa1sHz8WJljUAtLu0mqOcDy8ZIqrgK3++7EPBgYzskcg1rcBq733Yl5MDDMztJuijnp\nuwPzYmCQ5ucAS7tJqrgBPOy7E/NgYJid10ooZh0nOI2OOQbFWD5+hAwIirF8/AhZPl4xt7F8/OhY\nPl4xV/ruwLwYGKT5sXy8pJpXWD5+nMwxqIXl48fKHINaLMUcBjAwnIcjBcU8BY767sQ8GBik+ckJ\nCcjBMzDMzinRitnA8vHjZI5BLZbmQ8PAMLul2ei6MAfAk747MQ8Ghtk5UlDMJZbkmFqKN7FI5hjU\nYgPLx4+TOQa1sHy8pBrLx0uquYbl48fJHINa3MLy8aNjaTfFmGOQVLOHpd0kVdwEHvTdiXkwMMzO\nayUUsw6s9t2JeTAwzM4cg2K8Rd0IGRAU8xRzDKNj+XjFWD5+hCwfrxjLx0uqeQG87bsT82BgkObn\nFbDVdyfmwcBwTuYY1GID+KjvTsyDgeGczDGoxdIcT0vzRhbAkYJinmH5eEkVb7F8/Og4JVoxlo8f\nK3MMGgMDw+wcKShmH8vHj44jBcVYPn6szDGoxdKUj0/i2vEsy9aAG4RP5XfF7xXen156CTgt/j2f\ner4Mblnx73nxd/mYqednbXv6cfnaS0VfM4ODGrwFyLLsPpN9tNzn4P19tNzXSuU+mVUeTz//bqqN\ns9p+N7VsW9sZ8CTP83c0SCIwAC/77oA0B78Bfgns9N2RGfwW+EXTk1kKH35ZluXAR3meL0VNfill\nWZb9J/Aoz/NPmpZJKcdgck9ajE3gZ20LpBQYGs93JM3Vq+KnUSo5BnDEIC1K9NLwlEYM/Sc7pHG4\nDdxrWyClwJBSX6RltkHIMzRK6WB0xCAtxkvgedsCKeUYDAzSYuwQGRQ4YpDG5wPgYdsCKQWGlEYv\n0jK7TsgzNEopMCxF2W1pAJ4Bu20L+Cktjc8hsNa2QEojBnMM0mJsAo3XSUBagcHRi7QYVwl5hkYp\nHYzmGKTFeAJca1sgpRGD10pIi3FMpMx9SoHBHIO0GA+An7ctkFJguNR3B6SRWCFyvKWUY7Aeg7QY\nj3FKtKSK6HGfUmAw+SgtxkPgi7YFDAzS+LwpfhqZY5DG5zGRD2JHDNL4rAHrbQsYGKTx+ZBI+XhP\nJRJW3g4vy7IMwn0zy7/n/XjZ2/a2gu+xfPxQFXfnYmoff+/veT9e8rZ/A/wKlbaIHG8pBQYjet0j\nYG/qcXnD3qpy3c0SXKs3+r3ItvPK7z7a/j3hfpKauE0o79YopcCQUr4jFW/zPD/puxNDlmXZVZxu\nXxUtH59SYHDEUGfepbvHRC4xHiHLx2v0TgFHXe+zfPzApbR9hmqTyPTfEbJ8/MAZLLszv1AXLR+f\n0sFoaTddhC1CjUNNDKp8vPMY6hwxdLcCXO67E4kZVPl4Rwx1DoO72yQy/XeEouskpcBgVK8zWHZ3\nWvxo4ipwo22BlE4lPAjqPL3qbgfnMVQNqny8dBHWCFOANXFMmOTUyMCQNrdPd9HpvyP0APi8bYGU\ndjwTbXWeG3cX/XQcoUGVjzfHUGeOobtdIl/NjdAWkcCQ0ohBdQaG7jaITP8doeh+lVJg8CCoc510\ndwO41XcnEvOQAd2izoOgzsuuu3sOPO27E4k5xfLxGrmnwHbfnUjM49gCjhi07DaBT/vuRGKuYfn4\nQUtp+wzVVZz5WBUtH5/SjuepRJ3rpLsDwrRoTVg+fuBcJ90dYfKxKlo+PqURg7UH6lwn3T3A0m5V\nt4C7bQukFBhS6ksqXCfdXcPp9lUbhDxDo5ROJfx0rDPH0J3l4+teYfn4QTPH0N0bLB9fZfn4gTMw\ndPch5hiqLB8/cAbL7lLax1NxA8vHa+S2McdQdUgo79YopWjqsLnOEUN3K6T1AZiCQyL3lUgpMDhi\nqPNrtu7uA5/03YnE3GdAU6ItH19nsOzuHa7HqkGVj/c7+zpPr7rbxlvUVe0xoKsrPZ/WRbiG5eOr\njgnXkDRKKTCozu3T3V0sH181qPLxKZ3WpMLy8d0dE7nEeIQyIsdbSgejB0FdSoF7qCwfX7dD5NhP\naccz0aaLsEEYOmsiJ5LTSykwqM5g2d0NTD5WPSJy/UhKpxKbWZatEL62LCPaKuE76Kz498uEU47y\ngMmmll3h/UhYtlW+9tLU801tvy2ey6b+nQtoe2Xq+ayhbfAr3Hk4Ap5lWfaQ5vXdtm1XeX+fnN4H\nc8K2L5+fbqtt2/6xbTP1+mzq75z395v8jLan98mcyKl7SoHhD313IEHec7G73wJ/CvzUd0cS829t\nT2Z57vQBSe8zxyCpxsAgqcbAIKnGwCCpxsAgqcbAIKnGwCCpxsAgqcbAIKnGwCCpxsAgqcbAIKnG\nwCCpxsAgqcbAIKnGwCCpxsAgqcbAIKnGwCCpxsAgqcbAIKnm/wGyPjyrfbBoQAAAAABJRU5ErkJg\ngg==\n",
+      "image/png": "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\nAABJRU5ErkJggg==\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea6f8a160>"
+       "<matplotlib.figure.Figure at 0x7f2cfb990d30>"
       ]
      },
      "metadata": {},
      "data": {
       "image/png": "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\n1sd/Aw+RJa+eq45oAAAAAElFTkSuQmCC\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea6d354e0>"
+       "<matplotlib.figure.Figure at 0x7f2cfb8b1dd8>"
       ]
      },
      "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 68,
+   "execution_count": 30,
    "metadata": {},
    "outputs": [
     {
        "10"
       ]
      },
-     "execution_count": 68,
+     "execution_count": 30,
      "metadata": {},
      "output_type": "execute_result"
     },
      "data": {
       "image/png": "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\nJogA7b/FLob4OhrHyQAAAABJRU5ErkJggg==\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea6b5b1d0>"
+       "<matplotlib.figure.Figure at 0x7f2cfb83d3c8>"
       ]
      },
      "metadata": {},
      "data": {
       "image/png": "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\nAElFTkSuQmCC\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea6ff01d0>"
+       "<matplotlib.figure.Figure at 0x7f2cfb9748d0>"
       ]
      },
      "metadata": {},
      "data": {
       "image/png": "iVBORw0KGgoAAAANSUhEUgAAASMAAAEACAYAAAD4GBC1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAACyxJREFUeJzt3W2spHdZx/Hvr552d8v2KV2FtkELGGwgkKLUB4Lb8sKm\nGB8SFXVfaGJB1FKrCUrarRVNoUDTghqr2GAjwRgxohKDDzFRUw3gAxXUhCUNqAlSoK1uS93ubrvn\n8sV9L6jJdncbz/2/zsz3k0w607S5rplz5nv+M2/uVBWSNNoZoxeQJDBGkpowRpJaMEaSWjBGklow\nRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBG\nklowRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaS\nWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBGC0qyO8nrklw0ehepm43RC6yDJLuBG4AbgV3AlyW5\ne8EVjlXVEwvOk05bqmr0DisvyYPAnvlhARmwxtdW1T8MmCudEj+mLWMP8H7gILAJXFdVWeIG7J9n\n3jbw+UsnZYyWcy9wMfBa4H1LDJw/Ht7E9HO+MsmLl5grPR3GaEFV9XhV3VNVn19o5JXAM+b7O4B9\nC82VTpsxWm1/DFw+378WePPAXaSnZIxWWFVtVtU/zQ8PVNVjQxeSnoIxktSCMZLUgjGS1IIxktSC\nMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS1IIx\nktSCMZLUgjGS1IIxktSCMdpCSc5I8h3zw71Jnjt0IamxjdELrLgXAe+f738bcAT4vnHrSH2t1cko\nyZ4ktyW5YqGR/wgcv4jiEeAdC82Vtp21OBkleSbwU8B1wE7g8iR3LDT+PcBbgfuq6sMLzZS2nbWI\nEXAfcPH/ePzK+bak/QvPAyDJhcAhYM+I+dKpWpePaRcD9wIfAwp4W1Vl4dtfDXrub2A6Df7MoPnS\nKVmXGAE8CLwEuAq4fewqy5hPRdcz/ZxfnOTlg1eSTmidYkRN7q2q/xi9y0K+Dtg13z8b+JaBu0hP\naV2+M1pXfwZcABwErgb+Yuw60omt1clo3cwnwUfmh49W1ZNDF5KegjGS1IIxktSCMZLUgjGS1IIx\nktSCMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS\n1IIxktSCMZLUgjGS1MJKxyiTV88Pr0myd+hCkk5opWMEXAjcDWwyXVn1bWPXkXQiKx2jqnoI+C2m\nGD0OvHGp2UneneR1SXYsNfNkklyV5A+SPGfA7CT5ziS/n+TCAfM3kvxAkt8Z8TNJsjPJDUnuWXr2\ndpGqGr3DlprfePcDDwJ3LTj6VuAQcBi4raruXHD2/5KkgAPAs4GdwJ8CH1pwhcPAa4GLgN3AbwCf\nXHD+E8ANwLnz/NuBLyw4/0zgx4EdwNnALQvOBri7qj6/8MzTtvIxAkjyLuDVJ/0Pt8ZR4Czg+6vq\nvSMWSPIR4HLGnYT/EzgH2Bg0/2GmEJ05aP5jTL8DZw2a/1ngkqraHDT/lKz0x7Tjquo1VZUlb8AR\npjfhG+Y1Lhn3CvBS4Grgo/PjVy78WuwBvhf41Dz/hQvPfxbwI0xvygLOX3j+VwA3AgeBQwvPPQSc\nB3zXMr9qT19qDU5GIyR5LvCZqjo8f0x6fVW9ffBOAS4DDtSAH3ySM4DnV9WBpWfP8zeA51TV/YPm\n7wKeVVX/stC8twPXMX08/FfgedX4dDTq2LzyqupTJ/+vljUH6OMD528yfXc1av6TTN8fjpr/OLBI\niGYvYAoRTB+Tz2U6nbW0Fh/TpHVUVdcAH5jv76mqtiECYySpCWMkqQVjJKkFYySpBWMkqQVjJKkF\nYySpBWMkqQVjJKkFYySpBWMkqQVjJKkFYySpBWMkqQVjJKkFYySpBWMkqQVjJKkFYySpBWMkqQVj\nJKkFYySpBWMkqQVjtIWSnD1f1RPg+iRXD11IaswYba1nAz85378U2DduFam3tYpRkquSfDjJq5aY\nV1WfYLqi5yZwBPj5JeZqvSXZl+SDSfaO3uV0ZLr8+mpL8grgDuBrgGfM//pPFhq/G3g58J6q+sGF\nZqqJJGcBtzP97i3lmvmf/wU8AZxfVVlw/tOyLjEq4BjwJLBjwAoHga+vqvsHzNZASd4E3Dxo/BEg\nwJuq6tZBO5yydfqY9kfArwBHgZurKgveLjBE6yfJucBPMP3O3bbU7xvT1wFHgV8GLtkOIYL1Ohm9\nr6q+J8l5wKO1Dk9cQyW5helUtAM4DFxUVQcXmHsGcE5VPbLVs/4/rdPJCICqesQQaSG7+NLXAp/h\nS99Xbqmq2txuIQLYGL2AtKqqan+SR4G3VNXzRu/T3dqdjCT1ZIwktWCMJLVgjCS1YIwktWCMJLVg\njCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCM\nJLVgjCS1YIwktbDSMUqyI8l754ffneSnhy4k6YRWOkbATuDb5/sFfPNSg5NkqVkdjX7+o+fr9K10\njOZL/N7BdJ3zw8BNC47/eJLfS3LZgjNbSHIp8ECSO5PsGTD/CuCzSW5Ocs7S8/X0ZNUvO5/kfOAB\nIMDRBUefAxybZ34Q+NaqWnL+FyV5I/D6BUceD8BhYBP4a+CbBsw/xPQz+IWq+tkF539Rkv3Am6vK\nk9pJrHyMAJJcC/z6gNHF9IbcBVxfVXctvUCSlwD3LT13dpQpRh8DvmHA/MNMf4R2jIpBkl8Cfgz4\nyqp6YMQO28VKf0w7rqruqaoseQM+DfwlsHdeY8egp387UxQfYn5TLvDcvxr4AvCbwPOr6hsXfu1f\nBjwG3AW8atDrTpIvB17D9PrfMmqP7WJj9AIr7NKqOgYw6rvU+VT0CqbTwbnAtcA7t3puVX0yyQXH\nn//SqupDSc6vqmNJ9p78/9gyNwFnMr3PfjjJrZ6OTmwtTkYjjHoj/h+HgL+d7/870+loEaOf/+j5\ns39j+kMA0/eGQ74z3C48Ga2wqvoE8LIkBeyrqr8ZvdM6qapfTLILeEtVXTl6n+48GUlqwRhJasEY\nSWrBGElqwRhJasEYSWrBGElqwRhJasEYSWrBGElqwRhJasEYSWrBGElqwRhJasEYSWrBGElqwRhJ\nasEYSWrBGElqwRhJasEYSWrBGElqwRhJasEYbaEkFyf56PzwziQ3Dl1ozST5IeB35/v/nOSFg1fS\nUzBGW+sY8IL5/lFg51KDkyw2q7ENpst6A1zG9PNYhK//6TNGW6iqPsd0bfsn5ts7lpib5Dzg4SR/\nnuSlS8xs6t3AI0ABf1hVB5YYmmQfcDDJncDZS8xcBamq0TustCTPBD7NmEuJF3CE6UR2RVX9/YAd\nhkryo8CvDhi9yXQa3gA2qioDdthWRrxB1kpVfW7+S/lzC47dDXwVU4g2gV8DPrLg/E7eBbwIWPJa\n98e/m3oSeBjYv+DsbcuT0QpKshv4O+ADwFur6qHBK62VJFcDdzH9Afrtqlrsu6rtzBhJasEvsCW1\nYIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVg\njCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCM\nJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwk\ntWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktfDfe+gKnnXxV4YAAAAASUVORK5CYII=\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea700c4e0>"
+       "<matplotlib.figure.Figure at 0x7f2cfbd8d5c0>"
       ]
      },
      "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 40,
+   "execution_count": 33,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "['FLRFRFFFRFFFRFFR',\n",
-       " 'FFFRFRFRLR',\n",
-       " 'FFFFRFRFRLFR',\n",
-       " 'FFFLFFLFFLFF',\n",
-       " 'FFRRFLRRFR',\n",
-       " 'RLRFFRFRFFFR',\n",
-       " 'LFRFLLFFFLFFLF',\n",
-       " 'RLFFLFLFLR',\n",
-       " 'RFFFLLRFFFLLRRLLFFFF',\n",
-       " 'FLFFLFFLFLRL']"
+       "['FFFLLFFFFLLF',\n",
+       " 'LLFLFLRFLLFF',\n",
+       " 'FLRRLLFLFFLF',\n",
+       " 'FRLLFRRFLRFLRRFFFRLRFF',\n",
+       " 'LLRFLFFLFFFFLFFFFLFL',\n",
+       " 'LFRFFFRRFLRF',\n",
+       " 'LFRFFLRRFFRFLRFR',\n",
+       " 'LFFFLLFFFRFLLFFL',\n",
+       " 'RLFFLRLFLFFFLF',\n",
+       " 'RLRFFRFFFRRLRLFR']"
       ]
      },
-     "execution_count": 40,
+     "execution_count": 33,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 43,
+   "execution_count": 34,
    "metadata": {},
    "outputs": [
     {
      "data": {
-      "image/png": "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\n",
+      "image/png": "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\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea6ba2c50>"
+       "<matplotlib.figure.Figure at 0x7f2cfb907630>"
       ]
      },
      "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 44,
+   "execution_count": 35,
    "metadata": {},
    "outputs": [
     {
        "1"
       ]
      },
-     "execution_count": 44,
+     "execution_count": 35,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 45,
+   "execution_count": 36,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQMAAAEACAYAAAC3RRNlAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAABydJREFUeJzt3U+o9XldwPH3x+axNEpwEBSdCO0PghCG6MI/S5HAoF0h\n1CJIIm2VtHCgbBPSQkGFESxQN6H1UC4E2wRFCv2hmCisQCnJzGxIcWaceXS+Le43Eheiz7nnnLnn\neb3gcM/Z3M/nHu593/P7bb6z1grgGedeAHh6EAOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNg\nEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOg\nEgNgEwOgEgNgEwOgEgNgEwOgEoMbY2aeOzM/eu49uFyz1jr3DjfezDyj44f1o9VPV7ert6+1/vnI\n87jHiME1mJn3Vr9yonFPVat62Vrr0yeayT3AZcL1+NXq1pEff9RVCG5X31O5ZOBa3XfuBS7BWuup\nrv5Qj2ZmfrG6f631LzPj4xzXTgxuiLXWI9Uj596Dy+UyAajEANjEAKjEANjEAKjEANjEAKjEANjE\nAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjE4EaZmefMzL/ulx+bmdefdSEu\nihhco5l53sy8fmbmSCMe7eoAlaonq38/0hzuQc5NuAYz8/zq16s3V8+qXjszjx9p3EPVO6pPrLX+\n4UgzuAc5a/EazMxXq+8/8difWGs9fOKZXDAxuAb7uLOPVq+sXlT9wFrrWJ8M4CjcM7g+/1i9uPoh\nIeAmcs/gGu0DWD9/7j3gbvhkAFRiAGxiAFRiAGxiAFRiAGxiAFRiAGxiAFRiAGxiAFRiAGxiAFRi\nAGxiAFRiAGxiAFRiAGxiAFRiAGxiAFRicJCZuTUzX9wvf2Nm3nLWheAAFx2DmXlgZt48M7eO8f3X\nWneqT1ereqz6y2PMgVO4yHMTZubF1YPVz1XfVz0wM5870ri/qF5T/fVaSwy4sS7yeLWZ+VJ1f1f/\nsY91IvK3evVa65MnmgXX7lJjsKo/q56oXle9ZK3l+HL4Ni7yMmH7ylrrjTPz7LXWY+deBp7uLvoG\nYpUQwHfm4mMAfGfEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjE\nANjEAKjEANjEAKguMAYz84P76XNm5nvPugzcIBcXg+rh/fW11TvPuQjcJJcYg49XT1aPVh871pCZ\necXMvP2bPonAjXZxJyrNzAuqf6v+p7p9xFG/UN3q6sDV91dvW5f2ZnJPubgYVM3M71S/dqJxX+vq\ncNdfXms9dKKZcO0u8TKhtdbb1lpzzEf11uo/q7fssc8/308Mh7vIGJzCWuu91QvWWr977l3gOojB\nAdwj4JKIAVCJAbCJAVCJAbCJAVCJAbCJAVCJAbCJAVCJAbCJAVCJAbCJAVCJAbCJAVCJAbCJAVCJ\nAbCJAVCJAbCJwYFm5iX76Y/MzLPPugwcQAwOMDO3+v+zHd/U1VkKcCOJwQHWWneqP66+3tXJSh85\n70Zw98TgcA929T7eXmt99tzLwN0SgwOttT7T1fv4T+feBQ4hBtfHe8mN5hcYqMQA2MQAqMQA2MQA\nqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MTgQDPz\nqv30VTPz3LMuAwcQgwPssxb/dL98Q/VLZ1wHDiIGB9hnLX6wulM9vp/DjSQGh/utaqoPr7X+49zL\nwN0SgwPtANxXCQE3mhgAlRgAmxgAlRgAmxgAlRgAmxgAlRgAmxgAlRgAmxgAlRgAmxgAlRgAmxgA\nlRgAmxgAlRgAmxgAlRgAmxgAlRgAmxgAlRgcbGbeuJ/+1My88KzLwAHE4AD7rMXf3y9fUb3pjOvA\nQcTgAPusxfdUT1aPVR841qyZeXBmPjUzrznWjG+Z976Z+ZOZefmJ5t2emT+YmR870bw/n5nfm5kH\nTjDrmTPz8My8a2aed+x5d2vWWufe4Ubbx7B/obp1opGPV5+rTvJHUz1RfaZ66QlmPVV9vfps9eMn\nmHenWtXnqx8+wbwn9tefX2t95ATzviv3nXuBm26t9cjM/Ez1jq4OYD2Wn6y+0dUv799VXz3irP+b\nd2c//rarCB173pPV16q/qR49wbw7Xb2Pf1U9csRZz6xetuf9d1cxf9rxyeCGmJmfrV5Z/fZa679O\nMO+t1f3Vu9ZaXz7BvN+svlw9tNY6dniamXdXf199aF/uHXPWfdVD1SeqP1xrPXXMeXdLDIDKDURg\nEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOg\nEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNg\nEwOgEgNgEwOgEgNgEwOgEgNgEwOgqv8F9Hl5y6i1C9AAAAAASUVORK5CYII=\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea7040b70>"
+       "<matplotlib.figure.Figure at 0x7f2cfb4bba58>"
       ]
      },
      "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 48,
+   "execution_count": 37,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "(212,\n",
-       " 94,\n",
-       " 'FFRFLLFFFRLRRFFFLFLRRFLLFFFFFRFLFFFFFRLLFRFRLLFFFFFFLRFFRLLFRFFFLFFLFFRFRRLLFFRLFFFFFLLFFRFRFL')"
+       "(260, 64, 'RLFFFLRRFFLFFFFLLRRFLLRRLFRFLFLFFFFFRFFFFFLFRLLFFFRFLFFRFFLLRFFF')"
       ]
      },
-     "execution_count": 48,
+     "execution_count": 37,
      "metadata": {},
      "output_type": "execute_result"
     },
     {
      "data": {
-      "image/png": "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\ngg==\n",
+      "image/png": "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\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea7095780>"
+       "<matplotlib.figure.Figure at 0x7f2cfb49e908>"
       ]
      },
      "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 66,
+   "execution_count": 38,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "['LFLLFFFFLLLFFRFRFF',\n",
-       " 'LFFLLFFL',\n",
-       " 'FRFFRRFFFFFFLLRLRLRLLFFF',\n",
-       " 'RFFRRRFLFFFFLFLFRLLF',\n",
-       " 'LFFRFRFFFFFRFFRLRFRF',\n",
-       " 'LFFRFRFRFL',\n",
-       " 'FLFFLLFFRLLL',\n",
-       " 'FLLFFLLF',\n",
-       " 'FFLLRLRLLFLR',\n",
-       " 'FRRLLFLFFFFLFFFLLFFRRFLL',\n",
-       " 'FRFRRFFF',\n",
-       " 'FFFRFRRFFFFFFLFLFFFLRR',\n",
-       " 'FFRRRFFLRLFRLFLFLFRFLF',\n",
-       " 'RFFRRFFR',\n",
-       " 'LFFFFRRRFLFFFL',\n",
-       " 'FFLLLRRLLL',\n",
-       " 'FFRFFRFRFRLL',\n",
-       " 'RFLFFFFRRFFFFFRFFLLLLR',\n",
-       " 'RRLLRRFFRFRFLR',\n",
-       " 'FFRFRFFRFR']"
+       "['FRFRFFRFRF',\n",
+       " 'LLRFLLRLFFLFLR',\n",
+       " 'FFRFRFFFFFRFFRFFFR',\n",
+       " 'LLRLLLRL',\n",
+       " 'RLLLRFFFLFLLRFFL',\n",
+       " 'LLFFFLLFFF',\n",
+       " 'FLLRLFRFLFLFFFLLRFFR',\n",
+       " 'LLRFLRLFLLFRFFLF',\n",
+       " 'FFRFFFRFRFFF',\n",
+       " 'LRRLRFRFFFFRFRLRRL',\n",
+       " 'RFFRFFFRFFFFFRFRLFRF',\n",
+       " 'LFLLRLLF',\n",
+       " 'RFFRRFFRFFFLFFRRRFLRFL',\n",
+       " 'FFFRLLFFFLFLRFFFLFFFLFLF',\n",
+       " 'FFRFRRFFRLFFLLFRFFRRRFLR',\n",
+       " 'RRFRFFFRFFRFRL',\n",
+       " 'LFRFLLFFFFLLFRFL',\n",
+       " 'FLFRRRRLLF',\n",
+       " 'FRFFRRFFLLLL',\n",
+       " 'RFRRFFRLFRRFFR']"
       ]
      },
-     "execution_count": 66,
+     "execution_count": 38,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 67,
+   "execution_count": 39,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "317"
-      ]
-     },
-     "execution_count": 67,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
-    "open('mistakes.txt', 'w').write('\\n'.join(mistakes))"
+    "open('mistakes.txt', 'w').write('\\n'.join(mistakes))"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 69,
+   "execution_count": 40,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "137"
-      ]
-     },
-     "execution_count": 69,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
-    "open('samples.txt', 'w').write('\\n'.join(samples))"
+    "open('samples.txt', 'w').write('\\n'.join(samples))"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 71,
+   "execution_count": 41,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "('FFRRFLRRFR', 10)"
+       "('LLRFLFFLFFFFLFFFFLFL', 20)"
       ]
      },
-     "execution_count": 71,
+     "execution_count": 41,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 83,
+   "execution_count": 42,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "('RRLLRRFFRFRFLR', 14)"
+       "('FRFFRRFFLLLL', 12)"
       ]
      },
-     "execution_count": 83,
+     "execution_count": 42,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 74,
+   "execution_count": 43,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "'RRFFLLFFFFLF'"
+       "'RLLFRFFFFFFFRFLF'"
       ]
      },
-     "execution_count": 74,
+     "execution_count": 43,
      "metadata": {},
      "output_type": "execute_result"
     },
     {
      "data": {
-      "image/png": "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\n",
+      "image/png": "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\nrkJggg==\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea6e5cac8>"
+       "<matplotlib.figure.Figure at 0x7f2cfbc02a20>"
       ]
      },
      "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 76,
+   "execution_count": 44,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 80,
+   "execution_count": 45,
    "metadata": {},
    "outputs": [
     {
        "'FFRFLLFFFRLRRFFFLFLRRFLLFFFFFRFLFFFFFRLLFRFRLLFFFFF'"
       ]
      },
-     "execution_count": 80,
+     "execution_count": 45,
      "metadata": {},
      "output_type": "execute_result"
     },
      "data": {
       "image/png": "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\nAElFTkSuQmCC\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea6fc12e8>"
+       "<matplotlib.figure.Figure at 0x7f2cfbae7ef0>"
       ]
      },
      "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 81,
+   "execution_count": 46,
    "metadata": {},
    "outputs": [
     {
        "'FLRFFRLLFRFFFLFFLFFRFRRLLFFRLFFFFFLLFFRFRFL'"
       ]
      },
-     "execution_count": 81,
+     "execution_count": 46,
      "metadata": {},
      "output_type": "execute_result"
     },
      "data": {
       "image/png": "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\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea6c4e550>"
+       "<matplotlib.figure.Figure at 0x7f2cfbb6f978>"
       ]
      },
      "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 84,
+   "execution_count": 47,
    "metadata": {},
    "outputs": [
     {
        " 'FFRFLLFFFRLRRFFFLFLRRFLLFFFFFRFLFFFFFRLLFRFRLLFFFFFFLRFFRLLFRFFFLFFLFFRFRRLLFFRLFFFFFLLFFRFRFL')"
       ]
      },
-     "execution_count": 84,
+     "execution_count": 47,
      "metadata": {},
      "output_type": "execute_result"
     },
      "data": {
       "image/png": "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\ngg==\n",
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fdea6e6ca20>"
+       "<matplotlib.figure.Figure at 0x7f2cfbb69be0>"
       ]
      },
      "metadata": {},
index ceb641fbc83c48136aee813d611d91993c902f3b..c4949e8a5dcd3027e8325586021931d37ba7775a 100644 (file)
@@ -4,9 +4,77 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Given a sequence of {F|L|R}, each of which is \"move forward one step\", \"turn left, then move forward one step\", \"turn right, then move forward one step\":\n",
-    "1. which tours are closed?\n",
-    "2. what is the area enclosed by the tour?"
+    "You've arrived at your destination and are looking forward to seeing the site. But it's a large site and you'll need a guide.\n",
+    "\n",
+    "Each guide posts the route they'll take on a board, described the by steps they'll take. The steps are either `F` (take a step forward), `L` (turn left 90⁰ then take a step forward) or `R` (turn right 90⁰ then take a step forward). For example, the route `FFRRFLRRFR` will look like this (assuming you start facing right; the blob shows the starting point):\n",
+    "\n",
+    "\n",
+    "![Sample valid tour](question-example-tour-000-s0010-m000-trim.png)\n",
+    "\n",
+    "A sample valid tour\n",
+    "\n",
+    "while the tour `FFLLRLRLLFLR` looks like this (again, assuming you start facing right):\n",
+    "\n",
+    "![Sample valid tour](question-example-tour-001-s0012-m000-trim.png) \n",
+    "\n",
+    "A sample valid tour\n",
+    "\n",
+    "However, some of the tour guides are charlatans. They have tour that either doesn't return you to your starting place, or loops around to visit the same place more than once. For example, the tour `RRFFLLFFFFLF` doesn't return to your starting place:\n",
+    "\n",
+    "![Sample invalid tour](question-example-tour-002-s0012-m001-trim.png)\n",
+    "\n",
+    "An invalid tour\n",
+    "\n",
+    "and the tour `RRLLRRFFRFRFLR` may get you back to where you started, but only after going around a small loop:\n",
+    "\n",
+    "![Sample invalid tour](question-example-tour-003-s0014-m001-trim.png)\n",
+    "\n",
+    "A sample invalid tour\n",
+    "\n",
+    "You're only interested in valid tours, the ones that return you to your starting place and don't visit any other spot more than once. (It doesn't matter what direction you're facing when you return to your starting place, just that you return there at the end of the tour.)\n",
+    "\n",
+    "In fact, you've got your daily fitness tracker widget to keep happy. Even on holiday, you need to keep up the number of steps you take. You're interested in the total length of all the valid tours. In the examples here, the total length of the two valid tours is 10 + 12 = 22 steps.\n",
+    "\n",
+    "# Part 1\n",
+    "\n",
+    "The tours are given in [06-tours.txt](06-tours.txt), one tour per line. \n",
+    "\n",
+    "What is the total length of all the valid tours?\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "It seems you've done your guides a disservice.\n",
+    "\n",
+    "Yes, there are some charlatans around. But some of the tours a split between two guides. Each posted tour alone looks like it would be incomplete, but when you finish the first leg of a tour, you pick up a new guide and continue, eventually returning you to your starting place.\n",
+    "\n",
+    "For instance, the tours `FFRFLLFFFRLRRFFFLFLRRFLLFFFFFRFLFFFFFRLLFRFRLLFFFFF` and `FLRFFRLLFRFFFLFFLFFRFRRLLFFRLFFFFFLLFFRFRFL` are both incomplete; on its own, each tour would leave you stranded. \n",
+    "\n",
+    "![A split tour](question-example-tour-004-s0051-m001-trim.png)\n",
+    "\n",
+    "A split tour \n",
+    "\n",
+    "![More of a split tour](question-example-tour-005-s0043-m001-trim.png)\n",
+    "\n",
+    "More of a split tour\n",
+    "\n",
+    "But if you do one then the other, the complete 94-step tour is valid:\n",
+    "\n",
+    "![Split tour combined](question-example-tour-006-s0094-m000-trim.png)\n",
+    "\n",
+    "The split tour combined\n",
+    "\n",
+    "(You start the second half of the tour heading left, so turn the second picture 180⁰ to visualise it.)\n",
+    "\n",
+    "Luckily for you, tour guides only act alone or in pairs, and never in teams of three or more. \n",
+    "\n",
+    "(Because of way the initial facing changes the way a tour unfolds, it's generally the case that tour A followed by tour B is different from B followed by A.)\n",
+    "\n",
+    "# Part 2\n",
+    "\n",
+    "The tours are still given in [06-tours.txt](06-tours.txt), one tour per line. Your definition of a valid tour now includes the combination of two partial tours, so long as the combined tour never crosses itself and returns you to your staring place. With this new definition of valid tours, what is the total length of all the valid tours?"
    ]
   },
   {
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 39,
    "metadata": {
     "collapsed": true
    },
    "outputs": [],
    "source": [
-    "def plot_trace(trace, colour='k', xybounds=None, fig=None, subplot_details=None, filename=None):\n",
+    "def plot_trace(trace, colour='k', highlight_start=True,\n",
+    "               xybounds=None, fig=None, subplot_details=None, filename=None):\n",
     "    plt.axis('on')\n",
     "    plt.axes().set_aspect('equal')\n",
+    "    \n",
+    "    if highlight_start:\n",
+    "        plt.axes().add_patch(plt.Circle((trace[0].x, trace[0].y), 0.2, color=colour))\n",
+    "\n",
     "    for s, t in chunks(trace, 2):\n",
     "        w, h = plot_wh[t.dir]\n",
     "        plt.arrow(s.x, s.y, w, h, head_width=0.1, head_length=0.1, fc=colour, ec=colour, length_includes_head=True)\n",
     "        plt.savefig(filename)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\nnO0IPfrWAAAAAElFTkSuQmCC\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7f365877fd30>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(sample_tours[0]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7f36586f87b8>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(sample_tours[1]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\nGE/mZ+od3gAAAABJRU5ErkJggg==\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7f3658758860>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(sample_tours[2]))"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 18,
    "metadata": {},
    "outputs": [
     {
        "226"
       ]
      },
-     "execution_count": 17,
+     "execution_count": 18,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 19,
    "metadata": {},
    "outputs": [
     {
        "61762"
       ]
      },
-     "execution_count": 18,
+     "execution_count": 19,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
+   "execution_count": 20,
    "metadata": {},
    "outputs": [
     {
        "100"
       ]
      },
-     "execution_count": 19,
+     "execution_count": 20,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 21,
    "metadata": {},
    "outputs": [
     {
        "123845"
       ]
      },
-     "execution_count": 20,
+     "execution_count": 21,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 22,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "1 loop, best of 3: 214 ms per loop\n"
+      "10 loops, best of 3: 196 ms per loop\n"
      ]
     }
    ],
   },
   {
    "cell_type": "code",
-   "execution_count": 36,
+   "execution_count": 23,
    "metadata": {},
    "outputs": [
     {
        "80622"
       ]
      },
-     "execution_count": 36,
+     "execution_count": 23,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 24,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 25,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 26,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": 27,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 26,
+   "execution_count": 28,
    "metadata": {},
    "outputs": [
     {
        " (19, 1)]"
       ]
      },
-     "execution_count": 26,
+     "execution_count": 28,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 27,
+   "execution_count": 29,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 28,
+   "execution_count": 30,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 29,
+   "execution_count": 31,
    "metadata": {},
    "outputs": [
     {
        "80622"
       ]
      },
-     "execution_count": 29,
+     "execution_count": 31,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 30,
+   "execution_count": 32,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "1 loop, best of 3: 1.18 s per loop\n"
+      "1 loop, best of 3: 1.2 s per loop\n"
      ]
     }
    ],
   },
   {
    "cell_type": "code",
-   "execution_count": 31,
+   "execution_count": 33,
    "metadata": {},
    "outputs": [
     {
        "13"
       ]
      },
-     "execution_count": 31,
+     "execution_count": 33,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 32,
+   "execution_count": 34,
    "metadata": {},
    "outputs": [
     {
        " (212, 113)]"
       ]
      },
-     "execution_count": 32,
+     "execution_count": 34,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 33,
+   "execution_count": 35,
    "metadata": {},
    "outputs": [
     {
        " (208, 204)]"
       ]
      },
-     "execution_count": 33,
+     "execution_count": 35,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 34,
+   "execution_count": 36,
    "metadata": {},
    "outputs": [
     {
        " (127, 1)]"
       ]
      },
-     "execution_count": 34,
+     "execution_count": 36,
      "metadata": {},
      "output_type": "execute_result"
     }
diff --git a/07-interpreter/interpreter-solution.ipynb b/07-interpreter/interpreter-solution.ipynb
new file mode 100644 (file)
index 0000000..78200d9
--- /dev/null
@@ -0,0 +1,390 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Machine interpreter\n",
+    "\n",
+    "## Instructions\n",
+    "\n",
+    "After a good day sightseeing, it's back to the hotel and time for some refreshment. Unfortunately, the minibar in your room refuses to open. It's been hacked, with some ransomware! You'll need to provide the correct unlock code so you can get a nice, cold drink.\n",
+    "\n",
+    "You could pay a large chunk of bitcoin, or you could defeat the ransomware some other way. \n",
+    "\n",
+    "You quickly find the schematics of the minibar lock. It's a fairly simple machine. It has four registers, `a`, `b`, `c`, `d`, and a special purpose `pc` register for the program counter. Each register can hold a 64-bit value (far bigger than any number in the programs you'll be running). You can assume all registers hold zero when the program starts.\n",
+    "\n",
+    "On each clock tick, the machine executes the instruction pointed to by the `pc`, then increments `pc`. The machine halts when the machine tries to read from a location beyond the end of the program.\n",
+    "\n",
+    "The machine has only a few instructions. They're listed by handy mnemonics:\n",
+    "\n",
+    "| Instruction | Description |\n",
+    "|:------------|:------------|\n",
+    "| `inc r`     | increment contents of register `r` |\n",
+    "| `dec r`     | decrement contents of register `r` |\n",
+    "| `set r i`   | set contents of register `r` to literal value `i` |\n",
+    "| `cpy r s`   | copy contents of register `r` into register `s` | \n",
+    "| `jmp i`     | jump to instruction `i` places forward |\n",
+    "| `jpz r i`   | jump to instruction `i` places forward if<br>register `r` contains zero, otherwise continue to next instruction |\n",
+    "\n",
+    "The `jmp` and `jpz` instructions jump relative to the current instruction, overriding the normal change in `pc`. `jmp -1` would jump back to the previous instruction; `jpz a 2` would skip the next instruction if register `a` contains zero.\n",
+    "\n",
+    "Before you start execution of a program, you can set the values of some registers.\n",
+    "\n",
+    "For example, this program multiplies the values in the a and b registers, leaving the result in the c register:\n",
+    "\n",
+    "```\n",
+    "set c 0\n",
+    "cpy a d\n",
+    "jpz b 8\n",
+    "dec b\n",
+    "cpy d a\n",
+    "jpz a 4\n",
+    "inc c\n",
+    "dec a\n",
+    "jmp -3\n",
+    "jmp -7\n",
+    "set d 0\n",
+    "```\n",
+    "\n",
+    "# Part 1\n",
+    "\n",
+    "You think you've worked out how to generate the code wanted by the ransomware. The program is given in [07-program](07-program.txt), one instruction per line. \n",
+    "\n",
+    "Starting with register `a` holding 7, and all other registers holding zero, what does register `a` contain when the program finishes?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "It seems your guess of 7 as the starting value was wrong.\n",
+    "\n",
+    "# Part 2\n",
+    "\n",
+    "The program is still given in [07-program.txt](07-program.txt), one instruction per line. \n",
+    "\n",
+    "Starting with register `a` holding 937, and all other registers and memory locations holding zero, what does register `a` contain when the program finishes?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def new_machine():\n",
+    "    return {'pc': 0, \n",
+    "            'a': 0,\n",
+    "            'b': 0, \n",
+    "            'c': 0,\n",
+    "            'd': 0,\n",
+    "            'instructions': []}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def show_machine(machine):\n",
+    "    return ', '.join('{}: {}'.format(sk, machine[int(sk) if sk.isnumeric() else sk]) \n",
+    "                     for sk in sorted(str(k) for k in machine)\n",
+    "                     if sk != 'instructions')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def inc(reg, machine):\n",
+    "    machine[reg] += 1\n",
+    "    machine['pc'] += 1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def dec(reg, machine):\n",
+    "    machine[reg] -= 1\n",
+    "    machine['pc'] += 1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def jmp(addr, machine):\n",
+    "    machine['pc'] += addr"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def jpz(reg, addr, machine):\n",
+    "    if machine[reg] == 0:\n",
+    "        machine['pc'] += addr\n",
+    "    else:\n",
+    "        machine['pc'] += 1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def set_literal(reg, literal, machine):\n",
+    "    machine[reg] = literal\n",
+    "    machine['pc'] += 1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def cpy(from_reg, to_reg, machine):\n",
+    "    machine[to_reg] = machine[from_reg]\n",
+    "    machine['pc'] += 1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "instruction_table = {'inc': inc, 'dec': dec, 'jmp': jmp,\n",
+    "                    'jpz': jpz, 'set': set_literal, 'cpy': cpy}\n",
+    "numeric_args_table = {'jmp': [0], 'jpz': [1], 'set': [1], 'sto': [1], 'ld': [1]}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def parse(instruction):\n",
+    "    words = instruction.split()\n",
+    "    instr = words[0]\n",
+    "    args = words[1:]\n",
+    "    if instr in numeric_args_table:\n",
+    "        for p in numeric_args_table[instr]:\n",
+    "            args[p] = int(args[p])\n",
+    "    return instruction_table[instr], args"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def program_from_instructions(prog, machine):\n",
+    "    machine['instructions'] = [parse(instr) for instr in prog]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def unlabel_listing(listing):\n",
+    "    labelled_instructions = [i.strip() for i in listing.split('\\n') \n",
+    "                             if i.strip() \n",
+    "                             if not i.strip().startswith('#')]\n",
+    "    return replace_labels(labelled_instructions)    "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def program_from_listing(listing, machine):\n",
+    "    instructions = unlabel_listing(listing)\n",
+    "    program_from_instructions(instructions, machine)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def replace_labels(listing):\n",
+    "    locations = {}\n",
+    "    for n, i in enumerate(listing):\n",
+    "        if ':' in i:\n",
+    "            locations[i.split(':')[0]] = n\n",
+    "\n",
+    "    unlabelled_listing = []\n",
+    "    for n, i in enumerate(listing):\n",
+    "        instr = i.split()\n",
+    "        if ':' in i:\n",
+    "            instr = i.split(':')[1].split()\n",
+    "        else:\n",
+    "            instr = i.split()\n",
+    "        terms = []\n",
+    "        for term in instr:\n",
+    "            if term in locations:\n",
+    "                terms += [str(locations[term] - n)]\n",
+    "            else:\n",
+    "                terms += [term]\n",
+    "        transformed_instr = ' '.join(terms)\n",
+    "        unlabelled_listing += [transformed_instr]\n",
+    "        \n",
+    "    return unlabelled_listing    "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def run(machine, initial_state=None, trace=False):\n",
+    "    if initial_state:\n",
+    "        machine.update(initial_state)\n",
+    "    while machine['pc'] < len(machine['instructions']):\n",
+    "        if trace:\n",
+    "            print(show_machine(machine))\n",
+    "        cmd, args = machine['instructions'][machine['pc']]\n",
+    "        cmd(*args, machine)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def execute(listing, initial_state=None, trace=False):\n",
+    "    m = new_machine()\n",
+    "    program_from_listing(listing, m)\n",
+    "    run(m, initial_state=initial_state, trace=trace)\n",
+    "    return m"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'a: 52, b: 0, c: 0, d: 0, pc: 48'"
+      ]
+     },
+     "execution_count": 22,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "program = open('07-program.txt').read()\n",
+    "show_machine(execute(program, initial_state={'a': 7}))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'a: 250504, b: 0, c: 0, d: 0, pc: 48'"
+      ]
+     },
+     "execution_count": 23,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "program = open('07-program.txt').read()\n",
+    "show_machine(execute(program, initial_state={'a': 937}))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "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.5.2+"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
index abc09cc70b204bab2e9340cc612e1cb7f439cfa1..562543e4d3dfa253ee27f8c8909e2886452e58f2 100644 (file)
@@ -8,14 +8,15 @@
     "\n",
     "## Instructions\n",
     "\n",
-    "Four registers, `a`, `b`, `c`, and `d`.\n",
-    "Program counter, `pc`.\n",
+    "After a good day sightseeing, it's back to the hotel and time for some refreshment. Unfortunately, the minibar in your room refuses to open. It's been hacked, with some ransomware! You'll need to provide the correct unlock code so you can get a nice, cold drink.\n",
     "\n",
-    "Each register can hold 8-byte integers (Java `long`s).\n",
+    "You could pay a large chunk of bitcoin, or you could defeat the ransomware some other way. \n",
     "\n",
-    "Machine carries out the instruction at location `pc`. After it's executed, `pc` increments by 1.\n",
+    "You quickly find the schematics of the minibar lock. It's a fairly simple machine. It has four registers, `a`, `b`, `c`, `d`, and a special purpose `pc` register for the program counter. Each register can hold a 64-bit value (far bigger than any number in the programs you'll be running). You can assume all registers hold zero when the program starts.\n",
     "\n",
-    "`jmp` and `jpz` override this normal change in `pc`.\n",
+    "On each clock tick, the machine executes the instruction pointed to by the `pc`, then increments `pc`. The machine halts when the machine tries to read from a location beyond the end of the program.\n",
+    "\n",
+    "The machine has only a few instructions. They're listed by handy mnemonics:\n",
     "\n",
     "| Instruction | Description |\n",
     "|:------------|:------------|\n",
     "| `jmp i`     | jump to instruction `i` places forward |\n",
     "| `jpz r i`   | jump to instruction `i` places forward if<br>register `r` contains zero, otherwise continue to next instruction |\n",
     "\n",
-    "For `jmp` and `jpz`, `i` is relative to the current instruction. `i` can be negative to jump to earlier places in the program. `i`=1 is a no-op, `i`=0 causes an infinite loop."
+    "The `jmp` and `jpz` instructions jump relative to the current instruction, overriding the normal change in `pc`. `jmp -1` would jump back to the previous instruction; `jpz a 2` would skip the next instruction if register `a` contains zero.\n",
+    "\n",
+    "Before you start execution of a program, you can set the values of some registers.\n",
+    "\n",
+    "For example, this program multiplies the values in the a and b registers, leaving the result in the c register:\n",
+    "\n",
+    "```\n",
+    "set c 0\n",
+    "cpy a d\n",
+    "jpz b 8\n",
+    "dec b\n",
+    "cpy d a\n",
+    "jpz a 4\n",
+    "inc c\n",
+    "dec a\n",
+    "jmp -3\n",
+    "jmp -7\n",
+    "set d 0\n",
+    "```\n",
+    "\n",
+    "# Part 1\n",
+    "\n",
+    "You think you've worked out how to generate the code wanted by the ransomware. The program is given in `07-program.txt`, one instruction per line. \n",
+    "\n",
+    "Starting with register `a` holding 7, and all other registers holding zero, what does register `a` contain when the program finishes?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "It seems your guess of 7 as the starting value was wrong.\n",
+    "\n",
+    "# Part 2\n",
+    "\n",
+    "The program is still given in `07-program.txt`, one instruction per line. \n",
+    "\n",
+    "Starting with register `a` holding 937, and all other registers and memory locations holding zero, what does register `a` contain when the program finishes?"
    ]
   },
   {
   },
   {
    "cell_type": "code",
-   "execution_count": 45,
+   "execution_count": 13,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 14,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 53,
+   "execution_count": 15,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 16,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
+   "execution_count": 17,
    "metadata": {},
    "outputs": [
     {
        "['inc', 'a']"
       ]
      },
-     "execution_count": 15,
+     "execution_count": 17,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 47,
+   "execution_count": 18,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 49,
+   "execution_count": 19,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 20,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 21,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
+   "execution_count": 22,
    "metadata": {},
    "outputs": [
     {
        " 'pc': 4}"
       ]
      },
-     "execution_count": 19,
+     "execution_count": 22,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 23,
    "metadata": {},
    "outputs": [
     {
        " 'pc': 5}"
       ]
      },
-     "execution_count": 20,
+     "execution_count": 23,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 24,
    "metadata": {},
    "outputs": [
     {
        " 'pc': 5}"
       ]
      },
-     "execution_count": 21,
+     "execution_count": 24,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 25,
    "metadata": {},
    "outputs": [
     {
        " 'pc': 10}"
       ]
      },
-     "execution_count": 22,
+     "execution_count": 25,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 71,
+   "execution_count": 26,
    "metadata": {},
    "outputs": [
     {
        " 'pc': 9}"
       ]
      },
-     "execution_count": 71,
+     "execution_count": 26,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 64,
+   "execution_count": 27,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 65,
+   "execution_count": 28,
    "metadata": {},
    "outputs": [
     {
        "'a: 0, b: 1, c: 8, d: 0, pc: 10'"
       ]
      },
-     "execution_count": 65,
+     "execution_count": 28,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 66,
+   "execution_count": 29,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": 30,
    "metadata": {},
    "outputs": [
     {
        "'a: 4, b: 0, c: 12, d: 0, pc: 9'"
       ]
      },
-     "execution_count": 25,
+     "execution_count": 30,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 67,
+   "execution_count": 31,
    "metadata": {},
    "outputs": [
     {
        "'a: 0, b: 0, c: 27, d: 0, pc: 11'"
       ]
      },
-     "execution_count": 67,
+     "execution_count": 31,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 68,
+   "execution_count": 32,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 27,
+   "execution_count": 33,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 28,
+   "execution_count": 34,
    "metadata": {},
    "outputs": [
     {
        "'a: 2, b: 0, c: 10, d: 2, pc: 13'"
       ]
      },
-     "execution_count": 28,
+     "execution_count": 34,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 29,
+   "execution_count": 35,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 30,
+   "execution_count": 36,
    "metadata": {},
    "outputs": [
     {
        "'a: 52, b: 0, c: 0, d: 0, pc: 48'"
       ]
      },
-     "execution_count": 30,
+     "execution_count": 36,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 31,
+   "execution_count": 37,
    "metadata": {},
    "outputs": [
     {
        "40"
       ]
      },
-     "execution_count": 31,
+     "execution_count": 37,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 32,
+   "execution_count": 38,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 33,
+   "execution_count": 39,
    "metadata": {},
    "outputs": [
     {
        "52"
       ]
      },
-     "execution_count": 33,
+     "execution_count": 39,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 34,
+   "execution_count": 40,
    "metadata": {},
    "outputs": [
     {
        "(250504, 937)"
       ]
      },
-     "execution_count": 34,
+     "execution_count": 40,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 36,
+   "execution_count": 41,
    "metadata": {
     "scrolled": true
    },
        "[]"
       ]
      },
-     "execution_count": 36,
+     "execution_count": 41,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 37,
+   "execution_count": 42,
    "metadata": {},
    "outputs": [
     {
-     "ename": "KeyboardInterrupt",
-     "evalue": "",
-     "output_type": "error",
-     "traceback": [
-      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
-      "\u001b[0;32m<ipython-input-37-a9f4d977edea>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mshow_machine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexecute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprogram\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minitial_state\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'a'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m937\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
-      "\u001b[0;32m<ipython-input-18-d22f089366e4>\u001b[0m in \u001b[0;36mexecute\u001b[0;34m(listing, initial_state, trace)\u001b[0m\n\u001b[1;32m      2\u001b[0m     \u001b[0mm\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnew_machine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m     \u001b[0mprogram_from_listing\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlisting\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mm\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m     \u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mm\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minitial_state\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0minitial_state\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtrace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtrace\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      5\u001b[0m     \u001b[0;32mreturn\u001b[0m \u001b[0mm\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
-      "\u001b[0;32m<ipython-input-17-5478d48920ba>\u001b[0m in \u001b[0;36mrun\u001b[0;34m(machine, initial_state, trace)\u001b[0m\n\u001b[1;32m      2\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0minitial_state\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m         \u001b[0mmachine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minitial_state\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m     \u001b[0;32mwhile\u001b[0m \u001b[0mmachine\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'pc'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmachine\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'instructions'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      5\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mtrace\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      6\u001b[0m             \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mshow_machine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmachine\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
-      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
-     ]
+     "data": {
+      "text/plain": [
+       "'a: 250504, b: 0, c: 0, d: 0, pc: 48'"
+      ]
+     },
+     "execution_count": 42,
+     "metadata": {},
+     "output_type": "execute_result"
     }
    ],
    "source": [
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
+   "execution_count": 43,
+   "metadata": {
+    "collapsed": true
+   },
    "outputs": [],
    "source": [
     "# labelled_instructions = [i.strip() for i in program.split('\\n') \n",
   },
   {
    "cell_type": "code",
-   "execution_count": 58,
+   "execution_count": 44,
    "metadata": {},
    "outputs": [
     {
        " 'pc': 4}"
       ]
      },
-     "execution_count": 58,
+     "execution_count": 44,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 59,
+   "execution_count": 45,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 55,
+   "execution_count": 46,
    "metadata": {},
    "outputs": [
     {
        " 'pc': 4}"
       ]
      },
-     "execution_count": 55,
+     "execution_count": 46,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 61,
+   "execution_count": 47,
    "metadata": {},
    "outputs": [
     {
        " 'pc': 14}"
       ]
      },
-     "execution_count": 61,
+     "execution_count": 47,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 62,
+   "execution_count": 48,
    "metadata": {},
    "outputs": [
     {
diff --git a/08-word-chains/visa-woes-solution.ipynb b/08-word-chains/visa-woes-solution.ipynb
new file mode 100644 (file)
index 0000000..009e187
--- /dev/null
@@ -0,0 +1,1118 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Visa woes\n",
+    "\n",
+    "It seems there's been a problem with your visa, and the authorities have only just noticed, even though you're coming to the end of your holiday. There's no option but to navigate the bowels of the Foreign Ministry, to find the right series of offices to visit.\n",
+    "\n",
+    "For some reason known only to themselves, all the offices have a four-letter code that just happens to be an English word. (All the ministry office codes are given in the file [08-rooms.txt](08-rooms.txt).) An office will give you the authorisation to move to a different office if the codes differ by just one letter. For instance, the authorisation from office `rash` will allow you to move to the office `bash` and you can move from `able` to `axle`.\n",
+    "\n",
+    "You can move from office `rash` to `jags` by visiting five offices in total:\n",
+    "\n",
+    "```\n",
+    "rash\n",
+    "Bash\n",
+    "basS\n",
+    "baGs\n",
+    "Jags\n",
+    "```\n",
+    "\n",
+    "where the capital letters indicate the changed letters in each step. There are other ways of getting from `rash` to `jags`, but there is no shorter route.\n",
+    "\n",
+    "# Part 1\n",
+    "\n",
+    "Including the offices at both ends, what is the smallest number of offices do you have to visit to get from `coax` to `stay`?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "You may have found a route to your goal, but what if `stay` wasn't the right office? How many offices could you get in a few steps from a starting point?\n",
+    "\n",
+    "For example, there are 11 offices you can reach in one step from `rash`:\n",
+    "\n",
+    "`bash`, `cash`, `dash`, `gash`, `hash`, `lash`, `mash`, `rasp`, `rush`, `sash`, `wash`\n",
+    "\n",
+    "There are 47 distinct offices you could reach in up to two steps:\n",
+    "\n",
+    "`base`, `bash`, `bask`, `bass`, `bast`, `bath`, `bosh`, `bush`, `case`, `cash`, `cask`, `cast`, `dash`, `dish`, `gash`, `gasp`, `gosh`, `gush`, `hash`, `hasp`, `hath`, `hush`, `lash`, `lass`, `last`, `lath`, `lush`, `mash`, `mask`, `mass`, `mast`, `math`, `mesh`, `mush`, `push`, `ramp`, `rasp`, `ruse`, `rush`, `rusk`, `rust`, `sash`, `sass`, `tush`, `wash`, `wasp`, `wish`\n",
+    "\n",
+    "The there are 180 distinct offices reachable in up to three steps from `rash`.\n",
+    "\n",
+    "The ministry office codes are still given in the file [08-rooms.txt](08-rooms.txt).\n",
+    "\n",
+    "# Part 2\n",
+    "\n",
+    "How many different offices could you visit in no more than 10 steps from `coax`?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import string\n",
+    "import heapq"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2336"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "words = [w.strip() for w in open('08-rooms.txt').readlines()]\n",
+    "len(words)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def adjacents(word):\n",
+    "    return [word[0:i] + l + word[i+1:]\n",
+    "           for i in range(len(word))\n",
+    "           for l in string.ascii_lowercase\n",
+    "           if l != word[i]]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "neighbours = {w: [n for n in adjacents(w) if n in words]\n",
+    "             for w in words}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def distance(w1, w2):\n",
+    "    return sum(1 for i in range(len(w1))\n",
+    "               if w1[i] != w2[i])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# def extend(chain):\n",
+    "#     return [chain + [s] for s in neighbours[chain[-1]]\n",
+    "#            if s not in chain]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def extend(chain, closed=None):\n",
+    "    if closed:\n",
+    "        nbrs = set(neighbours[chain[-1]]) - closed\n",
+    "    else:\n",
+    "        nbrs = neighbours[chain[-1]]\n",
+    "    return [chain + [s] for s in nbrs\n",
+    "           if s not in chain]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def extend_raw(chain):\n",
+    "    nbrs = [w for w in adjacents(chain[-1]) if w in words]\n",
+    "    return [chain + [s] for s in nbrs\n",
+    "           if s not in chain]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def bfs_search(start, goal, debug=False):\n",
+    "    agenda = [[start]]\n",
+    "    finished = False\n",
+    "    while not finished and agenda:\n",
+    "        current = agenda[0]\n",
+    "        if debug:\n",
+    "            print(current)\n",
+    "        if current[-1] == goal:\n",
+    "            finished = True\n",
+    "        else:\n",
+    "            successors = extend(current)\n",
+    "            agenda = agenda[1:] + successors\n",
+    "    if finished:\n",
+    "        return current\n",
+    "    else:\n",
+    "        return None        "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def bfs_search_closed(start, goal, debug=False):\n",
+    "    agenda = [[start]]\n",
+    "    closed = set()\n",
+    "    finished = False\n",
+    "    while not finished and agenda:\n",
+    "        current = agenda[0]\n",
+    "        if debug:\n",
+    "            print(current)\n",
+    "        if current[-1] == goal:\n",
+    "            finished = True\n",
+    "        else:\n",
+    "            closed.add(current[-1])\n",
+    "            successors = extend(current, closed)\n",
+    "            agenda = agenda[1:] + successors\n",
+    "    if finished:\n",
+    "        return current\n",
+    "    else:\n",
+    "        return None   "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def dfs_search(start, goal, debug=False):\n",
+    "    agenda = [[start]]\n",
+    "    finished = False\n",
+    "    while not finished and agenda:\n",
+    "        current = agenda[0]\n",
+    "        if debug:\n",
+    "            print(current)\n",
+    "        if current[-1] == goal:\n",
+    "            finished = True\n",
+    "        else:\n",
+    "            successors = extend(current)\n",
+    "            agenda = successors + agenda[1:]\n",
+    "    if finished:\n",
+    "        return current\n",
+    "    else:\n",
+    "        return None        "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def astar_search(start, goal, debug=False):\n",
+    "    agenda = [(distance(start, goal), [start])]\n",
+    "    heapq.heapify(agenda)\n",
+    "    finished = False\n",
+    "    while not finished and agenda:\n",
+    "        _, current = heapq.heappop(agenda)\n",
+    "        if debug:\n",
+    "            print(current)\n",
+    "        if current[-1] == goal:\n",
+    "            finished = True\n",
+    "        else:\n",
+    "            successors = extend(current)\n",
+    "            for s in successors:\n",
+    "                heapq.heappush(agenda, (len(current) + distance(s[-1], goal) - 1, s))\n",
+    "    if finished:\n",
+    "        return current\n",
+    "    else:\n",
+    "        return None        "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# Uses direct lookup of successors, rather than using cached neighbours in the dict\n",
+    "def astar_search_raw(start, goal, debug=False):\n",
+    "    agenda = [(distance(start, goal), [start])]\n",
+    "    heapq.heapify(agenda)\n",
+    "    finished = False\n",
+    "    while not finished and agenda:\n",
+    "        _, current = heapq.heappop(agenda)\n",
+    "        if debug:\n",
+    "            print(current)\n",
+    "        if current[-1] == goal:\n",
+    "            finished = True\n",
+    "        else:\n",
+    "            successors = extend_raw(current) # Difference here\n",
+    "            for s in successors:\n",
+    "                heapq.heappush(agenda, (len(current) + distance(s[-1], goal) - 1, s))\n",
+    "    if finished:\n",
+    "        return current\n",
+    "    else:\n",
+    "        return None        "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def astar_search_closed(start, goal, debug=False):\n",
+    "    agenda = [(distance(start, goal), [start])]\n",
+    "    heapq.heapify(agenda)\n",
+    "    closed = set()\n",
+    "    finished = False\n",
+    "    while not finished and agenda:\n",
+    "        _, current = heapq.heappop(agenda)\n",
+    "        if debug:\n",
+    "            print(current)\n",
+    "        if current[-1] == goal:\n",
+    "            finished = True\n",
+    "        else:\n",
+    "            closed.add(current[-1])\n",
+    "            successors = extend(current, closed)\n",
+    "            for s in successors:\n",
+    "                heapq.heappush(agenda, (len(current) + distance(s[-1], goal) - 1, s))\n",
+    "    if finished:\n",
+    "        return current\n",
+    "    else:\n",
+    "        return None   "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['vice', 'dice', 'dire', 'dare', 'ware', 'wars']"
+      ]
+     },
+     "execution_count": 16,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "astar_search('vice', 'wars')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['vice', 'dice', 'dire', 'dare', 'ware', 'wars']"
+      ]
+     },
+     "execution_count": 17,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "astar_search_raw('vice', 'wars')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['boon', 'boot', 'bolt', 'belt', 'bell', 'sell']"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "astar_search_raw('boon', 'sell')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "6"
+      ]
+     },
+     "execution_count": 19,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(astar_search('vice', 'wars'))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# len(bfs_search('vice', 'wars'))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "6"
+      ]
+     },
+     "execution_count": 21,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(bfs_search_closed('vice', 'wars'))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "793"
+      ]
+     },
+     "execution_count": 22,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(dfs_search('vice', 'wars'))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "10000 loops, best of 3: 157 µs per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "astar_search('vice', 'wars')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "100 loops, best of 3: 15.5 ms per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "astar_search_raw('vice', 'wars')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "10000 loops, best of 3: 166 µs per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "astar_search_closed('vice', 'wars')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# %%timeit\n",
+    "# bfs_search('vice', 'wars')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 loop, best of 3: 554 ms per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "bfs_search_closed('vice', 'wars')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "10 loops, best of 3: 90.6 ms per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "dfs_search('vice', 'wars')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Part 2\n",
+    "\n",
+    "The example shows that `jags` is reachable in four steps from `rash`. There are 11 words one step away from `rash`: \n",
+    "`bash`, `cash`, `dash`, `gash`, `hash`, `lash`, `mash`, `rasp`, `rush`, `sash`, and `wash`. \n",
+    "\n",
+    "There are 47 words reachable in one or two steps from `rash`. They are `base`, `bash`, `bask`, `bass`, `bast`, `bath`, `bosh`, `bush`, `case`, `cash`, `cask`, `cast`, `dash`, `dish`, `gash`, `gasp`, `gosh`, `gush`, `hash`, `hasp`, `hath`, `hush`, `lash`, `lass`, `last`, `lath`, `lush`, `mash`, `mask`, `mass`, `mast`, `math`, `mesh`, `mush`, `push`, `ramp`, `rasp`, `ruse`, `rush`, `rusk`, `rust`, `sash`, `sass`, `tush`, `wash`, `wasp`, and `wish`.\n",
+    "\n",
+    "There are 180 words reachable in up to three steps from `rash`.\n",
+    "\n",
+    "How many words are reachable in up to ten steps from `vice`?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def reachable_in(word, n, trim_extras=False):\n",
+    "    reachable = set()\n",
+    "    boundary = set([word])\n",
+    "    for i in range(n):\n",
+    "        extras = set()\n",
+    "        for w in boundary:\n",
+    "            extras.update(neighbours[w])\n",
+    "        if trim_extras:\n",
+    "            extras.difference_update(reachable)\n",
+    "        reachable.update(boundary)\n",
+    "        boundary = extras.copy()\n",
+    "    return reachable.union(extras).difference(set([word]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['bash',\n",
+       " 'cash',\n",
+       " 'dash',\n",
+       " 'gash',\n",
+       " 'hash',\n",
+       " 'lash',\n",
+       " 'mash',\n",
+       " 'sash',\n",
+       " 'wash',\n",
+       " 'rush',\n",
+       " 'rasp']"
+      ]
+     },
+     "execution_count": 30,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "neighbours['rash']"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(11,\n",
+       " '`bash`, `cash`, `dash`, `gash`, `hash`, `lash`, `mash`, `rasp`, `rush`, `sash`, `wash`')"
+      ]
+     },
+     "execution_count": 31,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(reachable_in('rash', 1)), ', '.join(sorted('`{}`'.format(r) for r in reachable_in('rash', 1)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(11,\n",
+       " '<code>bash</code>, <code>cash</code>, <code>dash</code>, <code>gash</code>, <code>hash</code>, <code>lash</code>, <code>mash</code>, <code>rasp</code>, <code>rush</code>, <code>sash</code>, <code>wash</code>')"
+      ]
+     },
+     "execution_count": 32,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(reachable_in('rash', 1)), ', '.join(sorted('<code>{}</code>'.format(r) for r in reachable_in('rash', 1)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(47,\n",
+       " '`base`, `bash`, `bask`, `bass`, `bast`, `bath`, `bosh`, `bush`, `case`, `cash`, `cask`, `cast`, `dash`, `dish`, `gash`, `gasp`, `gosh`, `gush`, `hash`, `hasp`, `hath`, `hush`, `lash`, `lass`, `last`, `lath`, `lush`, `mash`, `mask`, `mass`, `mast`, `math`, `mesh`, `mush`, `push`, `ramp`, `rasp`, `ruse`, `rush`, `rusk`, `rust`, `sash`, `sass`, `tush`, `wash`, `wasp`, `wish`')"
+      ]
+     },
+     "execution_count": 33,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(reachable_in('rash', 2)), ', '.join(sorted('`{}`'.format(r) for r in reachable_in('rash', 2)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(47,\n",
+       " '<code>base</code>, <code>bash</code>, <code>bask</code>, <code>bass</code>, <code>bast</code>, <code>bath</code>, <code>bosh</code>, <code>bush</code>, <code>case</code>, <code>cash</code>, <code>cask</code>, <code>cast</code>, <code>dash</code>, <code>dish</code>, <code>gash</code>, <code>gasp</code>, <code>gosh</code>, <code>gush</code>, <code>hash</code>, <code>hasp</code>, <code>hath</code>, <code>hush</code>, <code>lash</code>, <code>lass</code>, <code>last</code>, <code>lath</code>, <code>lush</code>, <code>mash</code>, <code>mask</code>, <code>mass</code>, <code>mast</code>, <code>math</code>, <code>mesh</code>, <code>mush</code>, <code>push</code>, <code>ramp</code>, <code>rasp</code>, <code>ruse</code>, <code>rush</code>, <code>rusk</code>, <code>rust</code>, <code>sash</code>, <code>sass</code>, <code>tush</code>, <code>wash</code>, <code>wasp</code>, <code>wish</code>')"
+      ]
+     },
+     "execution_count": 34,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(reachable_in('rash', 2)), ', '.join(sorted('<code>{}</code>'.format(r) for r in reachable_in('rash', 2)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "180"
+      ]
+     },
+     "execution_count": 35,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(reachable_in('rash', 3))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 36,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2195"
+      ]
+     },
+     "execution_count": 36,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(reachable_in('rash', 10))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2192"
+      ]
+     },
+     "execution_count": 37,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(reachable_in('vice', 10))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "100 loops, best of 3: 5.81 ms per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "len(reachable_in('rash', 10))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "100 loops, best of 3: 2.71 ms per loop\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%timeit\n",
+    "len(reachable_in('rash', 10, trim_extras=True))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 40,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2188"
+      ]
+     },
+     "execution_count": 40,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(reachable_in('stay', 10))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 41,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2193"
+      ]
+     },
+     "execution_count": 41,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(reachable_in('coax', 10))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 42,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "280"
+      ]
+     },
+     "execution_count": 42,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "stay5 = reachable_in('stay', 4)\n",
+    "len(stay5)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 43,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "296"
+      ]
+     },
+     "execution_count": 43,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "extras = set()\n",
+    "for w in stay5:\n",
+    "    extras.update(neighbours[w])\n",
+    "extras.difference_update(stay5)\n",
+    "len(extras)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'know step yeps test pout book beck poor boos veep teed gent saws dyer hemp soon deem legs bets twit whim belt rock well bled whet prop spec weep peed loan week clef feed lock yens vent doer less teem toot yews blur clue pert pegs brew flea trig vets sued felt perk bobs brat tens beef leap bloc shoo moan boob jeez suet sits rood drag goat stay chip fled fist than loot pets suck peek pled heel hair sill prep char knot lens meek trap jeep beet crew draw tell nets peep meet sows glue bees bent pelt whit need foot bran chop gram chew teen veil lent gees fret soft leis pent gets weed keen reek news prim drab wets sics deed bows pier akin pock geed grey bogs goad skis peck prod loam keep pens hoot best reed yous sewn been tram pest whom bout unit deep boot dual lees omit peel sues berm dock yock shes lets mock grow jell whip lean thin sots geek stem floe tees sort fees gout mead dram said twin prom bras bier heft foul root fell melt bops coup coot atop brad chin moot shoe sacs chit hell door lead feet boon bolt leaf bell bias eery goop reel text boom herd rent leek rend club self send sick term airs frog yell next czar plus mean brow foam crow troy nest heed dell load glib peps cent chow pees bend jock held tent soil poop moor sped emit boss fest crop mews knit tout crag knob grab thaw vial sack help jets very boys flue whir newt wiry beep room pews crab baas cock coop hock blue flee moat skid quit dial brag cell aloe grad hews went leak toad wees mewl coat dent'"
+      ]
+     },
+     "execution_count": 44,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "' '.join(extras)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 45,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['coax', 'coat', 'boat', 'boar', 'soar', 'star', 'stay']"
+      ]
+     },
+     "execution_count": 45,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "astar_search('coax', 'stay')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 46,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "CPU times: user 620 ms, sys: 4 ms, total: 624 ms\n",
+      "Wall time: 624 ms\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "['coax', 'coat', 'chat', 'shat', 'spat', 'spay', 'stay']"
+      ]
+     },
+     "execution_count": 46,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "%time bfs_search_closed('coax', 'stay')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 47,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# %time bfs_search('coax', 'stay')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 48,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['czar', 'tzar', 'tear', 'sear', 'star', 'stay']"
+      ]
+     },
+     "execution_count": 48,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "astar_search('czar', 'stay')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 49,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# %time bfs_search('czar', 'stay')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 50,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# %time bfs_search('coax', 'stay')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 79,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "185"
+      ]
+     },
+     "execution_count": 79,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "rushn = reachable_in('rush', 3)\n",
+    "rushn.add('rush')\n",
+    "len(rushn)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 80,
+   "metadata": {
+    "collapsed": true,
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "links = set()\n",
+    "for w in rushn:\n",
+    "    for n in neighbours[w]:\n",
+    "        if n in rushn:\n",
+    "            links.add(frozenset((n, w)))\n",
+    "\n",
+    "with open('rush3.dot', 'w') as f:\n",
+    "    f.write('graph g {\\n')\n",
+    "    for l in links:\n",
+    "        lt = tuple(l)\n",
+    "        f.write('\"{}\" -- \"{}\";\\n'.format(lt[0], lt[1]))\n",
+    "    f.write('}\\n')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "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.5.2+"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/08-word-chains/word-chain-solution.ipynb b/08-word-chains/word-chain-solution.ipynb
deleted file mode 100644 (file)
index ba6e8bf..0000000
+++ /dev/null
@@ -1,1092 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "# Word chains\n",
-    "\n",
-    "\"Word chain\" puzzles are where you transform one word into another, by changing one letter at a time, with all the intermediate steps being valid words. \n",
-    "\n",
-    "For instance, you can transform 'rash' to 'jags' like this:\n",
-    "\n",
-    "```\n",
-    "rash\n",
-    "Bash\n",
-    "basS\n",
-    "baGs\n",
-    "Jags\n",
-    "```\n",
-    "\n",
-    "(the capital letter is the one changed in each step).\n",
-    "\n",
-    "## Part 1\n",
-    "\n",
-    "Given this [list of words](words4.txt), what is the minimum number of steps to go from `vice` to `wars`?"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "import string\n",
-    "import heapq"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "2336"
-      ]
-     },
-     "execution_count": 3,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "words = [w.strip() for w in open('08-rooms.txt').readlines()]\n",
-    "len(words)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def adjacents(word):\n",
-    "    return [word[0:i] + l + word[i+1:]\n",
-    "           for i in range(len(word))\n",
-    "           for l in string.ascii_lowercase\n",
-    "           if l != word[i]]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "neighbours = {w: [n for n in adjacents(w) if n in words]\n",
-    "             for w in words}"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def distance(w1, w2):\n",
-    "    return sum(1 for i in range(len(w1))\n",
-    "               if w1[i] != w2[i])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "# def extend(chain):\n",
-    "#     return [chain + [s] for s in neighbours[chain[-1]]\n",
-    "#            if s not in chain]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 8,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def extend(chain, closed=None):\n",
-    "    if closed:\n",
-    "        nbrs = set(neighbours[chain[-1]]) - closed\n",
-    "    else:\n",
-    "        nbrs = neighbours[chain[-1]]\n",
-    "    return [chain + [s] for s in nbrs\n",
-    "           if s not in chain]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def extend_raw(chain):\n",
-    "    nbrs = [w for w in adjacents(chain[-1]) if w in words]\n",
-    "    return [chain + [s] for s in nbrs\n",
-    "           if s not in chain]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 10,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def bfs_search(start, goal, debug=False):\n",
-    "    agenda = [[start]]\n",
-    "    finished = False\n",
-    "    while not finished and agenda:\n",
-    "        current = agenda[0]\n",
-    "        if debug:\n",
-    "            print(current)\n",
-    "        if current[-1] == goal:\n",
-    "            finished = True\n",
-    "        else:\n",
-    "            successors = extend(current)\n",
-    "            agenda = agenda[1:] + successors\n",
-    "    if finished:\n",
-    "        return current\n",
-    "    else:\n",
-    "        return None        "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 11,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def bfs_search_closed(start, goal, debug=False):\n",
-    "    agenda = [[start]]\n",
-    "    closed = set()\n",
-    "    finished = False\n",
-    "    while not finished and agenda:\n",
-    "        current = agenda[0]\n",
-    "        if debug:\n",
-    "            print(current)\n",
-    "        if current[-1] == goal:\n",
-    "            finished = True\n",
-    "        else:\n",
-    "            closed.add(current[-1])\n",
-    "            successors = extend(current, closed)\n",
-    "            agenda = agenda[1:] + successors\n",
-    "    if finished:\n",
-    "        return current\n",
-    "    else:\n",
-    "        return None   "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 12,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def dfs_search(start, goal, debug=False):\n",
-    "    agenda = [[start]]\n",
-    "    finished = False\n",
-    "    while not finished and agenda:\n",
-    "        current = agenda[0]\n",
-    "        if debug:\n",
-    "            print(current)\n",
-    "        if current[-1] == goal:\n",
-    "            finished = True\n",
-    "        else:\n",
-    "            successors = extend(current)\n",
-    "            agenda = successors + agenda[1:]\n",
-    "    if finished:\n",
-    "        return current\n",
-    "    else:\n",
-    "        return None        "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 13,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def astar_search(start, goal, debug=False):\n",
-    "    agenda = [(distance(start, goal), [start])]\n",
-    "    heapq.heapify(agenda)\n",
-    "    finished = False\n",
-    "    while not finished and agenda:\n",
-    "        _, current = heapq.heappop(agenda)\n",
-    "        if debug:\n",
-    "            print(current)\n",
-    "        if current[-1] == goal:\n",
-    "            finished = True\n",
-    "        else:\n",
-    "            successors = extend(current)\n",
-    "            for s in successors:\n",
-    "                heapq.heappush(agenda, (len(current) + distance(s[-1], goal) - 1, s))\n",
-    "    if finished:\n",
-    "        return current\n",
-    "    else:\n",
-    "        return None        "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 14,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "# Uses direct lookup of successors, rather than using cached neighbours in the dict\n",
-    "def astar_search_raw(start, goal, debug=False):\n",
-    "    agenda = [(distance(start, goal), [start])]\n",
-    "    heapq.heapify(agenda)\n",
-    "    finished = False\n",
-    "    while not finished and agenda:\n",
-    "        _, current = heapq.heappop(agenda)\n",
-    "        if debug:\n",
-    "            print(current)\n",
-    "        if current[-1] == goal:\n",
-    "            finished = True\n",
-    "        else:\n",
-    "            successors = extend_raw(current) # Difference here\n",
-    "            for s in successors:\n",
-    "                heapq.heappush(agenda, (len(current) + distance(s[-1], goal) - 1, s))\n",
-    "    if finished:\n",
-    "        return current\n",
-    "    else:\n",
-    "        return None        "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 15,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def astar_search_closed(start, goal, debug=False):\n",
-    "    agenda = [(distance(start, goal), [start])]\n",
-    "    heapq.heapify(agenda)\n",
-    "    closed = set()\n",
-    "    finished = False\n",
-    "    while not finished and agenda:\n",
-    "        _, current = heapq.heappop(agenda)\n",
-    "        if debug:\n",
-    "            print(current)\n",
-    "        if current[-1] == goal:\n",
-    "            finished = True\n",
-    "        else:\n",
-    "            closed.add(current[-1])\n",
-    "            successors = extend(current, closed)\n",
-    "            for s in successors:\n",
-    "                heapq.heappush(agenda, (len(current) + distance(s[-1], goal) - 1, s))\n",
-    "    if finished:\n",
-    "        return current\n",
-    "    else:\n",
-    "        return None   "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 16,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['vice', 'dice', 'dire', 'dare', 'ware', 'wars']"
-      ]
-     },
-     "execution_count": 16,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "astar_search('vice', 'wars')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 17,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['vice', 'dice', 'dire', 'dare', 'ware', 'wars']"
-      ]
-     },
-     "execution_count": 17,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "astar_search_raw('vice', 'wars')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 18,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['boon', 'boot', 'bolt', 'belt', 'bell', 'sell']"
-      ]
-     },
-     "execution_count": 18,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "astar_search_raw('boon', 'sell')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 19,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "6"
-      ]
-     },
-     "execution_count": 19,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(astar_search('vice', 'wars'))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 20,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "# len(bfs_search('vice', 'wars'))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 21,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "6"
-      ]
-     },
-     "execution_count": 21,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(bfs_search_closed('vice', 'wars'))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 22,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "793"
-      ]
-     },
-     "execution_count": 22,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(dfs_search('vice', 'wars'))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 23,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "10000 loops, best of 3: 157 µs per loop\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%timeit\n",
-    "astar_search('vice', 'wars')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 24,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "100 loops, best of 3: 15.5 ms per loop\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%timeit\n",
-    "astar_search_raw('vice', 'wars')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 25,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "10000 loops, best of 3: 166 µs per loop\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%timeit\n",
-    "astar_search_closed('vice', 'wars')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 26,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "# %%timeit\n",
-    "# bfs_search('vice', 'wars')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 27,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "1 loop, best of 3: 554 ms per loop\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%timeit\n",
-    "bfs_search_closed('vice', 'wars')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 28,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "10 loops, best of 3: 90.6 ms per loop\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%timeit\n",
-    "dfs_search('vice', 'wars')"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Part 2\n",
-    "\n",
-    "The example shows that `jags` is reachable in four steps from `rash`. There are 11 words one step away from `rash`: \n",
-    "`bash`, `cash`, `dash`, `gash`, `hash`, `lash`, `mash`, `rasp`, `rush`, `sash`, and `wash`. \n",
-    "\n",
-    "There are 47 words reachable in one or two steps from `rash`. They are `base`, `bash`, `bask`, `bass`, `bast`, `bath`, `bosh`, `bush`, `case`, `cash`, `cask`, `cast`, `dash`, `dish`, `gash`, `gasp`, `gosh`, `gush`, `hash`, `hasp`, `hath`, `hush`, `lash`, `lass`, `last`, `lath`, `lush`, `mash`, `mask`, `mass`, `mast`, `math`, `mesh`, `mush`, `push`, `ramp`, `rasp`, `ruse`, `rush`, `rusk`, `rust`, `sash`, `sass`, `tush`, `wash`, `wasp`, and `wish`.\n",
-    "\n",
-    "There are 180 words reachable in up to three steps from `rash`.\n",
-    "\n",
-    "How many words are reachable in up to ten steps from `vice`?"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 29,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "def reachable_in(word, n, trim_extras=False):\n",
-    "    reachable = set()\n",
-    "    boundary = set([word])\n",
-    "    for i in range(n):\n",
-    "        extras = set()\n",
-    "        for w in boundary:\n",
-    "            extras.update(neighbours[w])\n",
-    "        if trim_extras:\n",
-    "            extras.difference_update(reachable)\n",
-    "        reachable.update(boundary)\n",
-    "        boundary = extras.copy()\n",
-    "    return reachable.union(extras).difference(set([word]))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 30,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['bash',\n",
-       " 'cash',\n",
-       " 'dash',\n",
-       " 'gash',\n",
-       " 'hash',\n",
-       " 'lash',\n",
-       " 'mash',\n",
-       " 'sash',\n",
-       " 'wash',\n",
-       " 'rush',\n",
-       " 'rasp']"
-      ]
-     },
-     "execution_count": 30,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "neighbours['rash']"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 31,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "(11,\n",
-       " '`bash`, `cash`, `dash`, `gash`, `hash`, `lash`, `mash`, `rasp`, `rush`, `sash`, `wash`')"
-      ]
-     },
-     "execution_count": 31,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(reachable_in('rash', 1)), ', '.join(sorted('`{}`'.format(r) for r in reachable_in('rash', 1)))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 32,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "(11,\n",
-       " '<code>bash</code>, <code>cash</code>, <code>dash</code>, <code>gash</code>, <code>hash</code>, <code>lash</code>, <code>mash</code>, <code>rasp</code>, <code>rush</code>, <code>sash</code>, <code>wash</code>')"
-      ]
-     },
-     "execution_count": 32,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(reachable_in('rash', 1)), ', '.join(sorted('<code>{}</code>'.format(r) for r in reachable_in('rash', 1)))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 33,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "(47,\n",
-       " '`base`, `bash`, `bask`, `bass`, `bast`, `bath`, `bosh`, `bush`, `case`, `cash`, `cask`, `cast`, `dash`, `dish`, `gash`, `gasp`, `gosh`, `gush`, `hash`, `hasp`, `hath`, `hush`, `lash`, `lass`, `last`, `lath`, `lush`, `mash`, `mask`, `mass`, `mast`, `math`, `mesh`, `mush`, `push`, `ramp`, `rasp`, `ruse`, `rush`, `rusk`, `rust`, `sash`, `sass`, `tush`, `wash`, `wasp`, `wish`')"
-      ]
-     },
-     "execution_count": 33,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(reachable_in('rash', 2)), ', '.join(sorted('`{}`'.format(r) for r in reachable_in('rash', 2)))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 34,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "(47,\n",
-       " '<code>base</code>, <code>bash</code>, <code>bask</code>, <code>bass</code>, <code>bast</code>, <code>bath</code>, <code>bosh</code>, <code>bush</code>, <code>case</code>, <code>cash</code>, <code>cask</code>, <code>cast</code>, <code>dash</code>, <code>dish</code>, <code>gash</code>, <code>gasp</code>, <code>gosh</code>, <code>gush</code>, <code>hash</code>, <code>hasp</code>, <code>hath</code>, <code>hush</code>, <code>lash</code>, <code>lass</code>, <code>last</code>, <code>lath</code>, <code>lush</code>, <code>mash</code>, <code>mask</code>, <code>mass</code>, <code>mast</code>, <code>math</code>, <code>mesh</code>, <code>mush</code>, <code>push</code>, <code>ramp</code>, <code>rasp</code>, <code>ruse</code>, <code>rush</code>, <code>rusk</code>, <code>rust</code>, <code>sash</code>, <code>sass</code>, <code>tush</code>, <code>wash</code>, <code>wasp</code>, <code>wish</code>')"
-      ]
-     },
-     "execution_count": 34,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(reachable_in('rash', 2)), ', '.join(sorted('<code>{}</code>'.format(r) for r in reachable_in('rash', 2)))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 35,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "180"
-      ]
-     },
-     "execution_count": 35,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(reachable_in('rash', 3))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 36,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "2195"
-      ]
-     },
-     "execution_count": 36,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(reachable_in('rash', 10))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 37,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "2192"
-      ]
-     },
-     "execution_count": 37,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(reachable_in('vice', 10))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 38,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "100 loops, best of 3: 5.81 ms per loop\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%timeit\n",
-    "len(reachable_in('rash', 10))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 39,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "100 loops, best of 3: 2.71 ms per loop\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%timeit\n",
-    "len(reachable_in('rash', 10, trim_extras=True))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 40,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "2188"
-      ]
-     },
-     "execution_count": 40,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(reachable_in('stay', 10))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 41,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "2193"
-      ]
-     },
-     "execution_count": 41,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "len(reachable_in('coax', 10))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 42,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "280"
-      ]
-     },
-     "execution_count": 42,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "stay5 = reachable_in('stay', 4)\n",
-    "len(stay5)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 43,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "296"
-      ]
-     },
-     "execution_count": 43,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "extras = set()\n",
-    "for w in stay5:\n",
-    "    extras.update(neighbours[w])\n",
-    "extras.difference_update(stay5)\n",
-    "len(extras)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 44,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "'know step yeps test pout book beck poor boos veep teed gent saws dyer hemp soon deem legs bets twit whim belt rock well bled whet prop spec weep peed loan week clef feed lock yens vent doer less teem toot yews blur clue pert pegs brew flea trig vets sued felt perk bobs brat tens beef leap bloc shoo moan boob jeez suet sits rood drag goat stay chip fled fist than loot pets suck peek pled heel hair sill prep char knot lens meek trap jeep beet crew draw tell nets peep meet sows glue bees bent pelt whit need foot bran chop gram chew teen veil lent gees fret soft leis pent gets weed keen reek news prim drab wets sics deed bows pier akin pock geed grey bogs goad skis peck prod loam keep pens hoot best reed yous sewn been tram pest whom bout unit deep boot dual lees omit peel sues berm dock yock shes lets mock grow jell whip lean thin sots geek stem floe tees sort fees gout mead dram said twin prom bras bier heft foul root fell melt bops coup coot atop brad chin moot shoe sacs chit hell door lead feet boon bolt leaf bell bias eery goop reel text boom herd rent leek rend club self send sick term airs frog yell next czar plus mean brow foam crow troy nest heed dell load glib peps cent chow pees bend jock held tent soil poop moor sped emit boss fest crop mews knit tout crag knob grab thaw vial sack help jets very boys flue whir newt wiry beep room pews crab baas cock coop hock blue flee moat skid quit dial brag cell aloe grad hews went leak toad wees mewl coat dent'"
-      ]
-     },
-     "execution_count": 44,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "' '.join(extras)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 45,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['coax', 'coat', 'boat', 'boar', 'soar', 'star', 'stay']"
-      ]
-     },
-     "execution_count": 45,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "astar_search('coax', 'stay')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 46,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "CPU times: user 620 ms, sys: 4 ms, total: 624 ms\n",
-      "Wall time: 624 ms\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "['coax', 'coat', 'chat', 'shat', 'spat', 'spay', 'stay']"
-      ]
-     },
-     "execution_count": 46,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "%time bfs_search_closed('coax', 'stay')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 47,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "# %time bfs_search('coax', 'stay')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 48,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['czar', 'tzar', 'tear', 'sear', 'star', 'stay']"
-      ]
-     },
-     "execution_count": 48,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "astar_search('czar', 'stay')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 49,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "# %time bfs_search('czar', 'stay')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 50,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "# %time bfs_search('coax', 'stay')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 79,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "185"
-      ]
-     },
-     "execution_count": 79,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "rushn = reachable_in('rush', 3)\n",
-    "rushn.add('rush')\n",
-    "len(rushn)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 80,
-   "metadata": {
-    "scrolled": true
-   },
-   "outputs": [],
-   "source": [
-    "links = set()\n",
-    "for w in rushn:\n",
-    "    for n in neighbours[w]:\n",
-    "        if n in rushn:\n",
-    "            links.add(frozenset((n, w)))\n",
-    "\n",
-    "with open('rush3.dot', 'w') as f:\n",
-    "    f.write('graph g {\\n')\n",
-    "    for l in links:\n",
-    "        lt = tuple(l)\n",
-    "        f.write('\"{}\" -- \"{}\";\\n'.format(lt[0], lt[1]))\n",
-    "    f.write('}\\n')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {
-    "collapsed": true
-   },
-   "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.5.2+"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
index bf6f6c111d4a1fb3cbcd2e98855cae20994a4b14..61d009756777b3cb64ff1bd1b0547a07cdf247a5 100644 (file)
@@ -4,40 +4,85 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "# Wordsearch\n",
-    "Given a text file, consisting of three parts (a grid size, a grid, and a list of words), find:\n",
-    "* the words present in the grid, \n",
-    "* the longest word present in the grid, \n",
-    "* the number of words not present in the grid, \n",
-    "* the longest word not present that can be formed from the leftover letters\n",
+    "First nights in hotels are always a bit of an anticlimax, what with the recovery from travel and all. You decided to do one of your wordsearch puzzles.\n",
     "\n",
-    "The only words that need be considered are the ones given in the list in the puzzle input.\n",
+    "These puzzles are a bit different from normal because they have a puzzle grid and a list of words, but only some of the words are in the puzzle; some of the words given are decoys and aren't present.\n",
     "\n",
-    "The puzzle consists of:\n",
-    "1. A line consisting of _w_`x`_h_, where _w_ and _h_ are integers giving the width and height of the grid.\n",
-    "2. The grid itself, consisting of _h_ lines each of _w_ letters.\n",
-    "3. A list of words, one word per line, of arbitrary length. "
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Example\n",
+    "For instance, given the grid:\n",
     "\n",
-    "\n",
-    "`...p.mown.\n",
-    ".sdse..ee.\n",
-    ".e.elad.cr\n",
-    "pi.dtir.ah\n",
+    "```\n",
+    "fhjpamownq\n",
+    "wsdseuqeev\n",
+    "ieaeladhcr\n",
+    "piedtiriah\n",
     "rzsiwovspu\n",
-    "oawh.kieab\n",
-    "brow.c.rda\n",
-    "ecnotops.r\n",
-    "d.kc.d...b\n",
-    ".staple...`\n",
+    "oawhakieab\n",
+    "browpcfrda\n",
+    "ecnotopssr\n",
+    "dikchdnpnb\n",
+    "bstapleokr\n",
+    "```\n",
+    "and the list of words:\n",
+    "\n",
+    "* adapting, apace, bombing, cackles, carnal, chump, coccyxes, cowhides, crazies, crumbled, dock, fickler, foaming, guts, knows, lived, minuend, molested, mown, pears, probed, rhubarb, rioted, shinier, solaria, staple, tops, wide, winced\n",
+    "\n",
+    "you can find these words:\n",
+    "\n",
+    "* apace, cowhides, crazies, dock, knows, lived, mown, pears, probed, rhubarb, rioted, staple, tops, wide\n",
+    "\n",
+    "but these are the decoys:\n",
+    "\n",
+    "* adapting, bombing, cackles, carnal, chump, coccyxes, crumbled, fickler, foaming, guts, minuend, molested, shinier, solaria, winced\n",
+    "\n",
+    "For this puzzle, there are 14 words with a total length of 76 letters. (Some of the words may overlap in the grid, but don't worry about that when counting word lengths in your solution.)\n",
+    "\n",
+    "## About wordsearches\n",
+    "\n",
+    "Words can go in any of the eight directions (up, down, left, right, and diagonals) in a straight line. A letter in the grid can be in more than one word. Words don't wrap around the edges of the grid.\n",
+    "\n",
+    "In the example above, the words \"lived\", \"wide\" and \"staple\" are in these positions (two words are diagonal and share a letter).\n",
+    "\n",
+    "```\n",
+    "..........\n",
+    ".......e..\n",
+    "....l.d...\n",
+    ".....i....\n",
+    "....w.v...\n",
+    ".......e..\n",
+    "........d.\n",
+    "..........\n",
+    "..........\n",
+    ".staple...\n",
+    "```\n",
+    "\n",
+    "The longest word, \"cowhides\", runs vertically upwards:\n",
+    "\n",
+    "```\n",
+    "..........\n",
+    "...s......\n",
+    "...e......\n",
+    "...d......\n",
+    "...i......\n",
+    "...h......\n",
+    "...w......\n",
+    "...o......\n",
+    "...c......\n",
+    "..........\n",
+    "```\n",
+    "\n",
+    "If there are words present in the grid that aren't in the list of words given, ignore them. For instance, you can see the word \"brow\" running left to right on the seventh row of the grid, but that doesn't count as a word in this puzzle because \"brow\" isn't in the list of words you're given.\n",
+    "\n",
+    "You're safe to assume that each word in the puzzle is present either zero or one times, never more.\n",
+    "\n",
+    "## File format\n",
+    "The wordsearch puzzle is given as a text file. The first line of the file is WxH, where W and H are the width and height of the puzzle grid, in characters. The next H lines are the grid, each line being W characters long. Finally, there's an arbitrary number of words to look for, one on each line.\n",
+    "\n",
+    "Ignore any trailing or leading blank lines, and any whitespace on a line.\n",
+    "\n",
+    "The example puzzle above, a ten by ten grid, would be written to a file as:\n",
     "\n",
     "```\n",
+    "10x10\n",
     "fhjpamownq\n",
     "wsdseuqeev\n",
     "ieaeladhcr\n",
     "ecnotopssr\n",
     "dikchdnpnb\n",
     "bstapleokr\n",
+    "adapting\n",
+    "apace\n",
+    "bombing\n",
+    "cackles\n",
+    "carnal\n",
+    "chump\n",
+    "coccyxes\n",
+    "cowhides\n",
+    "crazies\n",
+    "crumbled\n",
+    "dock\n",
+    "fickler\n",
+    "foaming\n",
+    "guts\n",
+    "knows\n",
+    "lived\n",
+    "minuend\n",
+    "molested\n",
+    "mown\n",
+    "pears\n",
+    "probed\n",
+    "rhubarb\n",
+    "rioted\n",
+    "shinier\n",
+    "solaria\n",
+    "staple\n",
+    "tops\n",
+    "wide\n",
+    "winced\n",
     "```\n",
     "\n",
-    "14 words added;  6 directions\n",
+    "# Part 1\n",
     "\n",
-    "Present: apace cowhides crazies dock knows lived mown pears probed rhubarb rioted staple tops wide\n",
+    "Your wordsearch puzzle is given in [10-wordsearch.txt](10-wordsearch.txt). \n",
+    "\n",
+    "What is the total of the lengths of all the words present in the puzzle?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "After you've solved the wordsearch and found all the words you can, you'll have some letters unused in any word. For the example wordsearch, once you've found the words, you're left with this:\n",
     "\n",
-    "Decoys: adapting bombing boor brick cackles carnal casino chaplets chump coaster coccyxes coddle collies creels crumbled cunt curds curled curlier deepen demeanor dicier dowses ensuing faddish fest fickler foaming gambol garoting gliding gristle grunts guts ibex impugns instants kielbasy lanyard loamier lugs market meanly minuend misprint mitts molested moonshot mucking oaks olives orgasmic pastrami perfect proceed puckered quashed refined regards retraces revel ridges ringlet scoff shinier siren solaria sprain sunder sunup tamped tapes thirds throw tiller times trains tranquil transfix typesets uric wariness welts whimsy winced winced\n",
+    "```\n",
+    "fhj.a....q\n",
+    "w....uq..v\n",
+    "i.a....h..\n",
+    "..e....i..\n",
+    "..........\n",
+    "....a.....\n",
+    "....p.f...\n",
+    "........s.\n",
+    ".i..h.npn.\n",
+    "b......okr\n",
+    "```\n",
+    "The letters remaining in the grid are `aaabeffhhhiiijknnoppqqrsuvw`. 9 of those letters are vowels. \n",
     "\n",
-    "Decoys: fickler, adapting, chump, foaming, molested, carnal, crumbled, guts, minuend, bombing, winced, coccyxes, solaria, shinier, cackles\n",
+    "# Part 2\n",
     "\n",
-    "All words: adapting, apace, bombing, cackles, carnal, chump, coccyxes, cowhides, crazies, crumbled, dock, fickler, foaming, guts, knows, lived, minuend, molested, mown, pears, probed, rhubarb, rioted, shinier, solaria, staple, tops, wide, winced\n",
+    "Your wordsearch puzzle is still given in [10-wordsearch.txt](10-wordsearch.txt).\n",
     "\n",
-    "Directions:  [('probed', '`(True, 3, 0, <Direction.down: 4>)`'), ('staple', '`(True, 9, 1, <Direction.right: 2>)`'), ('rioted', '`(True, 6, 7, <Direction.upleft: 5>)`'), ('cowhides', '`(True, 8, 3, <Direction.up: 3>)`'), ('tops', '`(True, 7, 4, <Direction.right: 2>)`'), ('knows', '`(True, 8, 2, <Direction.up: 3>)`'), ('lived', '`(True, 2, 4, <Direction.downright: 8>)`'), ('rhubarb', '`(True, 2, 9, <Direction.down: 4>)`'), ('crazies', '`(True, 7, 1, <Direction.up: 3>)`'), ('dock', '`(True, 8, 5, <Direction.up: 3>)`'), ('apace', '`(True, 5, 8, <Direction.up: 3>)`'), ('mown', '`(True, 0, 5, <Direction.right: 2>)`'), ('pears', '`(True, 0, 3, <Direction.downright: 8>)`'), ('wide', '`(True, 4, 4, <Direction.upright: 6>)`')]"
+    "How many vowels are left over after solving this puzzle?"
    ]
   },
   {